Browse Source

New version (again) of the fieldtypes

Yann Weber 8 years ago
parent
commit
773afc5b2c

+ 2
- 1
.gitignore View File

@@ -4,4 +4,5 @@
4 4
 .idea
5 5
 Lodel/settings/locale.py
6 6
 Lodel/settings/local.py
7
-doc
7
+doc
8
+.*.swp

+ 30
- 4
EditorialModel/fields.py View File

@@ -1,5 +1,7 @@
1 1
 #-*- coding: utf-8 -*-
2 2
 
3
+import importlib
4
+
3 5
 from EditorialModel.components import EmComponent
4 6
 from EditorialModel.exceptions import EmComponentCheckError
5 7
 import EditorialModel
@@ -12,6 +14,8 @@ class EmField(EmComponent):
12 14
 
13 15
     ranked_in = 'fieldgroup_id'
14 16
 
17
+    ftype = None
18
+
15 19
     fieldtypes = {
16 20
         'int': models.IntegerField,
17 21
         'integer': models.IntegerField,
@@ -30,24 +34,44 @@ class EmField(EmComponent):
30 34
 
31 35
     ## Instanciate a new EmField
32 36
     # @todo define and test type for icon and fieldtype
33
-    def __init__(self, model, uid, name, fieldgroup_id, fieldtype, optional=False, internal=False, rel_to_type_id=None, rel_field_id=None, icon='0', string=None, help_text=None, date_update=None, date_create=None, rank=None, **kwargs):
37
+    # @warning nullable == True by default
38
+    def __init__(self, model, uid, name, fieldgroup_id, optional=False, internal=False, rel_field_id=None, icon='0', string=None, help_text=None, date_update=None, date_create=None, rank=None, nullable = True, default = None, **kwargs):
34 39
 
35 40
         self.fieldgroup_id = fieldgroup_id
36 41
         self.check_type('fieldgroup_id', int)
37
-        self.fieldtype = fieldtype
38 42
         self.optional = optional
39 43
         self.check_type('optional', bool)
40 44
         self.internal = internal
41 45
         self.check_type('internal', bool)
42
-        self.rel_to_type_id = rel_to_type_id
43
-        self.check_type('rel_to_type_id', (int, type(None)))
44 46
         self.rel_field_id = rel_field_id
45 47
         self.check_type('rel_field_id', (int, type(None)))
46 48
         self.icon = icon
49
+
50
+        self.nullable = nullable
51
+        self.default = default
52
+
47 53
         self.options = kwargs
48 54
 
49 55
         super(EmField, self).__init__(model=model, uid=uid, name=name, string=string, help_text=help_text, date_update=date_update, date_create=date_create, rank=rank)
50 56
 
57
+    @staticmethod
58
+    def get_field_class(ftype, **kwargs):
59
+        ftype_module = importlib.import_module('EditorialModel.fieldtypes.%s'%ftype)
60
+        return ftype_module.fclass
61
+
62
+    ## @brief Abstract method that should return a validation function
63
+    # @param raise_e Exception : if not valid raise this exception
64
+    # @param ret_valid : if valid return this value
65
+    # @param ret_invalid : if not valid return this value
66
+    def validation_function(self, raise_e = None, ret_valid = None, ret_invalid = None):
67
+        if self.__class__ == EmField:
68
+            raise NotImplementedError("Abstract method")
69
+        if raise_e is None and ret_valid is None:
70
+            raise AttributeError("Behavior doesn't allows to return a valid validation function")
71
+
72
+        return False
73
+            
74
+
51 75
     ## @brief Return the list of relation fields for a rel_to_type
52 76
     # @return None if the field is not a rel_to_type else return a list of EmField
53 77
     def rel_to_type_fields(self):
@@ -72,6 +96,7 @@ class EmField(EmComponent):
72 96
     def delete_check(self):
73 97
         return True
74 98
 
99
+    """
75 100
     def to_django(self):
76 101
         if self.fieldtype in ('varchar', 'char'):
77 102
             max_length = None if 'max_length' not in self.options else self.options['max_length']
@@ -86,3 +111,4 @@ class EmField(EmComponent):
86 111
             return models.NullBooleanField(**self.options)
87 112
 
88 113
         return self.fieldtypes[self.fieldtype](**self.options)
114
+    """

+ 0
- 494
EditorialModel/fieldtypes.py View File

@@ -1,494 +0,0 @@
1
-#-*- coding: utf-8 -*-
2
-
3
-from django.db import models
4
-import re
5
-import datetime
6
-import json
7
-import importlib
8
-import copy
9
-import EditorialModel
10
-from Lodel.utils.mlstring import MlString
11
-
12
-
13
-## @brief Characterise fields for LeObject and EmComponent
14
-# This class handles values rules for LeObject and EmComponents.
15
-#
16
-# It allows to EmFieldValue classes family to have rules to cast, validate and save values.
17
-#
18
-# There is exposed methods that allows LeObject and EmType to run a save sequence. This methods are :
19
-# - EmFieldType.to_value() That cast a value to an EmFieldType internal storage
20
-# - EmFieldType.is_valid() That indicates wether or not a value is valid
21
-# - EmFieldType.pre_save() That returns weighted SQL request that must be run before any value save @ref EditorialModel::types::EmType.save_values()
22
-# - EmFieldType.to_sql() That returns a value that can be inserted in database.
23
-# - EmFieldType.post_save() That returns weighted SQL request that must be run after any value save @ref EditorialModel::types::EmType.save_values()
24
-#
25
-class EmFieldType(object):
26
-
27
-    ## Stores options and default value for EmFieldType
28
-    # options list :
29
-    # - type (str|None) : if None will make an 'abstract' fieldtype (with no value assignement possible)
30
-    # - nullable (bool) : tell whether or not a fieldType accept NULL value
31
-    # - default (mixed) : The default value for a FieldType
32
-    # - primarykey (bool) : If true the fieldType represent a PK
33
-    # - autoincrement (bool) : If true the fieldType will be autoincremented
34
-    # - index (bool) : If true the columns will be indexed in Db
35
-    # - name (str) : FieldType name
36
-    # - doc (str) : FieldType documentation
37
-    # - onupdate (callable) : A callback to call on_update
38
-    # - valueobject (EmFieldValue or childs) : An object that represent values for this fieldType
39
-    # - type_* (mixed) : Use to construct an options dictinnary for a type (exemple : type_length => nnewColumn(lenght= [type_lenght VALUE] )) @ref EmFieldSQLType
40
-    # - validators (list) : List of validator functions to use
41
-    _opt = {
42
-        'name': None,
43
-        'type': None,
44
-        'nullable': True,
45
-        'default': None,
46
-        'primarykey': False,
47
-        'autoincrement': False,
48
-        'uniq': False,
49
-        'index': False,
50
-        'doc': None,
51
-        'onupdate': None,
52
-        'valueobject': None,
53
-        'validators': None
54
-    }
55
-
56
-    ## Instanciate an EmFieldType
57
-    # For arguments see @ref EmFieldType::_opt
58
-    # @see EmFieldType::_opt
59
-    def __init__(self, **kwargs):
60
-        self.__init(kwargs)
61
-        self.type_options = dict()
62
-
63
-        # stores all col_* arguments into the self.type_options dictionary
64
-        args = kwargs.copy()
65
-        for optname in args:
66
-            type_opt = re.sub(r'^type_', '', optname)
67
-            if type_opt != optname:
68
-                self.type_options[type_opt] = args[optname]
69
-                del kwargs[optname]
70
-
71
-        # checks if the other arguments are valid
72
-        if len(set(kwargs.keys()) - set(self.__class__._opt.keys())) > 0:
73
-            badargs = ""
74
-            for bad in set(kwargs.keys()) - set(self.__class__._opt.keys()):
75
-                badargs += " " + bad
76
-            raise TypeError("Unexpected arguments : %s" % badargs)
77
-
78
-        # stores other arguments as instance attribute
79
-        for opt_name in self.__class__._opt:
80
-            setattr(self, opt_name, (kwargs[opt_name] if opt_name in kwargs else self.__class__._opt[opt_name]))
81
-
82
-        # checks type's options valididty
83
-        if self.type != None:
84
-            try:
85
-                EmFieldSQLType.sqlType(self.type, **self.type_options)
86
-            except TypeError as e:
87
-                raise e
88
-
89
-        # Default value for name
90
-        if self.name == None:
91
-            if  self.__class__ == EmFieldType:
92
-                self.name = 'generic'
93
-            else:
94
-                self.name = self.__class__.__name__
95
-
96
-        # Default value for doc
97
-        if self.doc == None:
98
-            if self.__class__ == EmFieldType:
99
-                self.doc = 'Abstract generic EmFieldType'
100
-            else:
101
-                self.doc = self.__class__.__name__
102
-
103
-    ## MUST be called first in each constructor
104
-    # @todo this solution is not good (look at the __init__ for EmFieldType childs)
105
-    def __init(self, kwargs):
106
-        try:
107
-            self.args_copy
108
-        except AttributeError:
109
-            self.args_copy = kwargs.copy()
110
-
111
-    @property
112
-    ## A predicate that indicates whether or not an EmFieldType is "abstract"
113
-    def is_abstract(self):
114
-        return (self.type == None)
115
-
116
-    ## Returns a copy of the current EmFieldType
117
-    def copy(self):
118
-        args = self.args_copy.copy()
119
-        return self.__class__(**args)
120
-
121
-    def dump_opt(self):
122
-        return json.dumps(self.args_copy)
123
-
124
-    @staticmethod
125
-    ## Return an instance from a classname and options from dump_opt
126
-    # @param classname str: The EmFieldType class name
127
-    # @param json_opt str: getted from dump_opt
128
-    def restore(colname, classname, json_opt):
129
-        field_type_class = getattr(EditorialModel.fieldtypes, classname)
130
-        init_opt = json.loads(json_opt)
131
-        init_opt['name'] = colname
132
-        return field_type_class(**init_opt)
133
-
134
-    ## Return a value object 'driven' by this EmFieldType
135
-    # @param name str: The column name associated with the value
136
-    # @param *init_val mixed: If given this will be the initialisation value
137
-    # @return a EmFieldValue instance
138
-    # @todo better default value (and bad values) handling
139
-    def valueObject(self, name, *init_val):
140
-        if self.valueObject == None:
141
-            return EmFieldValue(name, self, *init_val)
142
-        return self.valueObject(name, self, *init_val)
143
-
144
-    ## Cast to the correct value
145
-    # @param v mixed : the value to cast
146
-    # @return A gently casted value
147
-    # @throw ValueError if v is innapropriate
148
-    # @throw NotImplementedError if self is an abstract EmFieldType
149
-    def to_value(self, v):
150
-        if self.type == None:
151
-            raise NotImplemented("This EmFieldType is abstract")
152
-        if v == None and not self.nullable:
153
-            raise TypeError("Field not nullable")
154
-        return v
155
-
156
-    ## to_value alias
157
-    # @param value mixed : the value to cast
158
-    # @return A casted value
159
-    def from_string(self, value):
160
-        return self.to_value(value)
161
-
162
-    ## Returns a gently sql forged value
163
-    # @return A sql forged value
164
-    # @warning It assumes that the value is correct and comes from an EmFieldValue object
165
-    def to_sql(self, value):
166
-        if self.is_abstract:
167
-            raise NotImplementedError("This EmFieldType is abstract")
168
-        return True
169
-
170
-    ## Returns whether or not a value is valid for this EmFieldType
171
-    # @note This function always returns True and is here for being overloaded  by child objects
172
-    # @return A boolean, True if valid else False
173
-    def is_valid(self, value):
174
-        if self.is_abstract:
175
-            raise NotImplementedError("This EmFieldType is abstract")
176
-        return True
177
-
178
-    ## Pre-save actions
179
-    def pre_save(self):
180
-        if self.is_abstract:
181
-            raise NotImplementedError("This EmFieldType is abstract")
182
-        return []
183
-
184
-    ## Post-save actions
185
-    def post_save(self):
186
-        if self.is_abstract:
187
-            raise NotImplementedError("This EmFieldType is abstract")
188
-        return []
189
-
190
-    @classmethod
191
-    ## Function designed to be called by child class to enforce a type
192
-    # @param args dict: The kwargs argument of __init__
193
-    # @param typename str: The typename to enforce
194
-    # @return The new kwargs to be used
195
-    # @throw TypeError if type is present is args
196
-    def _setType(cl, args, typename):
197
-        return cl._argEnforce(args, 'type', typename, True)
198
-
199
-    @classmethod
200
-    ## Function designed to be called by child's constructo to enforce an argument
201
-    # @param args dict: The constructor's kwargs
202
-    # @param argname str: The name of the argument to enforce
203
-    # @param argval mixed: The value we want to enforce
204
-    # @param Return a new kwargs
205
-    # @throw TypeError if type is present is args and exception argument is True
206
-    def _argEnforce(cl, args, argname, argval, exception=True):
207
-        if exception and argname in args:
208
-            raise TypeError("Invalid argument '"+argname+"' for "+cl.__class__.__name__+" __init__")
209
-        args[argname] = argval
210
-        return args
211
-
212
-    @classmethod
213
-    ## Function designed to be called by child's constructor to set a default value
214
-    # @param args dict: The constructor's kwargs
215
-    # @param argname str: The name of the argument with default value
216
-    # @param argval mixed : The default value
217
-    # @return a new kwargs dict
218
-    def _argDefault(cl, args, argname, argval):
219
-        if argname not in args:
220
-            args[argname] = argval
221
-        return args
222
-
223
-class EmFieldValue(object):
224
-
225
-    ## Instanciates a EmFieldValue
226
-    # @param name str : The column name associated with this value
227
-    # @param fieldtype EmFieldType: The EmFieldType defining the value
228
-    # @param *value *list: This argument allow to pass a value to set (even None) and to detect if no value given to set to EmFieldType's default value
229
-    # @throw TypeError if more than 2 arguments given
230
-    # @throw TypeError if fieldtype is not an EmFieldType
231
-    # @throw TypeError if fieldtype is an abstract EmFieldType
232
-    def __init__(self, name, fieldtype, *value):
233
-        if not isinstance(fieldtype, EmFieldType):
234
-            raise TypeError("Expected <class EmFieldType> for 'fieldtype' argument, but got : %s instead" % str(type(fieldtype)))
235
-        if fieldtype.is_abstract:
236
-            raise TypeError("The given fieldtype in argument is abstract.")
237
-
238
-        # This copy ensures that the fieldtype will not change during the value lifecycle
239
-        super(EmFieldValue, self).__setattr__('fieldtype', fieldtype.copy())
240
-
241
-        if len(value) > 1:
242
-            raise TypeError("Accept only 2 positionnal parameters. %s given." % str(len(value)+1))
243
-        elif len(value) == 1:
244
-            self.value = value[0]
245
-        else:
246
-            self.value = fieldtype.default
247
-
248
-        # Use this to set value in the constructor
249
-        setv = super(EmFieldValue, self).__setattr__
250
-        # This copy makes column attributes accessible easily
251
-        for attrname in self.fieldtype.__dict__:
252
-            setv(attrname, getattr(self.fieldtype, attrname))
253
-
254
-        # Assign some EmFieldType methods to the value
255
-        setv('from_python', self.fieldtype.to_value)
256
-        setv('from_string', self.fieldtype.to_value)
257
-        #setv('sqlCol', self.fieldtype.sqlCol)
258
-
259
-    ## The only writable attribute of EmFieldValue is the value
260
-    # @param name str: Have to be value
261
-    # @param value mixed: The value to set
262
-    # @throw AtrributeError if another attribute than value is to be set
263
-    # @throw ValueError if self.to_value raises it
264
-    # @see EmFieldType::to_value()
265
-    def __setattr__(self, name, value):
266
-        if name != "value":
267
-            raise AttributeError("EmFieldValue has only the value property settable")
268
-        super(EmFieldValue,self).__setattr__('value', self.fieldtype.to_value(value))
269
-
270
-        ##
271
-    # @warning When getting the fieldtype you actually get a copy of it to prevent any modifications !
272
-    def __getattr__(self, name):
273
-        if name == 'fieldtype':
274
-            return self.fieldtype.copy()
275
-        return super(EmFieldValue, self).__getattribute__(name)
276
-
277
-    ## @brief Return a valid SQL value
278
-    #
279
-    # Can be used to convert any value (giving one positionnal argument) or to return the current value
280
-    # @param *value list: If a positionnal argument is given return it and not the instance value
281
-    # @return A value suitable for sql
282
-    def to_sql(self, *value):
283
-        if len(value) > 1:
284
-            raise TypeError("Excepted 0 or 1 positional argument but got "+str(len(value)))
285
-        elif len(value) == 1:
286
-            return self.fieldtype.to_sql(value[0])
287
-        return self.fieldtype.to_sql(self.value)
288
-
289
-class EmFieldSQLType(object):
290
-    _integer = {'sql': models.IntegerField}
291
-    _bigint = {'sql': models.BigIntegerField}
292
-    _smallint = {'sql': models.SmallIntegerField}
293
-    _boolean = {'sql': models.BooleanField}
294
-    _nullableboolean = {'sql': models.NullBooleanField}
295
-    _float = {'sql': models.FloatField}
296
-    _varchar = {'sql': models.CharField}
297
-    _text = {'sql': models.TextField}
298
-    _time = {'sql': models.TimeField}
299
-    _date = {'sql': models.DateField}
300
-    _datetime = {'sql': models.DateTimeField}
301
-
302
-    _names = {
303
-        'int': _integer,
304
-        'integer': _integer,
305
-        'bigint': _bigint,
306
-        'smallint': _smallint,
307
-        'boolean': _boolean,
308
-        'bool': _boolean,
309
-        'float': _float,
310
-        'char': _varchar,
311
-        'varchar': _varchar,
312
-        'text': _text,
313
-        'time': _time,
314
-        'date': _date,
315
-        'datetime': _datetime,
316
-    }
317
-
318
-    @classmethod
319
-    def sqlType(cls, name, **kwargs):
320
-        if not isinstance(name, str):
321
-            raise TypeError("Expect <class str>, <class int>|None but got : %s %s" % (str(type(name)), str(type(size))))
322
-        name = name.lower()
323
-        if name not in cls._names:
324
-            raise ValueError("Unknown type '%s'" % name)
325
-
326
-        if name in ['boolean','bool'] and kwargs['nullable'] in [1,'true']:
327
-            sqlclass = _nullableboolean
328
-        else:
329
-            sqlclass = cls._names[name]
330
-
331
-        if len(kwargs) == 0:
332
-            return sqlclass['sql']
333
-
334
-        return sqlclass['sql'](**kwargs)
335
-
336
-
337
-## @brief Represents values with common arithmetic operations
338
-class EmFieldValue_int(EmFieldValue):
339
-    def __int__(self):
340
-        return self.value
341
-
342
-    def __add__(self, other):
343
-        return self.value + other
344
-
345
-    def __sub__(self, other):
346
-        return self.value - other
347
-
348
-    def __mul__(self, other):
349
-        return self.value * other
350
-
351
-    def __div__(self, other):
352
-        return self.value / other
353
-
354
-    def __mod__(self, other):
355
-        return self.value % other
356
-
357
-    def __iadd__(self, other):
358
-        self.value = int(self.value + other)
359
-        return self
360
-
361
-    def __isub__(self, other):
362
-        self.value = int(self.value - other)
363
-        return self
364
-
365
-    def __imul__(self, other):
366
-        self.value = int(self.value * other)
367
-        return self
368
-
369
-    def __idiv__(self, other):
370
-        self.value = int(self.value / other)
371
-        return self
372
-
373
-
374
-## @brief Handles integer fields
375
-# @note Enforcing type to be int
376
-# @note Default name is 'integer' and default 'valueobject' is EmFieldValue_int
377
-class EmField_integer(EmFieldType):
378
-
379
-    def __init__(self, **kwargs):
380
-        self._init(kwargs)
381
-        # Default name
382
-        kwargs = self.__class__._argDefault(kwargs, 'name', 'integer')
383
-        # Default value object
384
-        kwargs = self.__class__._argDefault(kwargs, 'valueobject', EmFieldValue_int)
385
-        # Type enforcing
386
-        kwargs = self.__class__._setType(kwargs, 'int')
387
-        super(EmField_integer, self).__init__(**kwargs)
388
-
389
-    ##
390
-    # @todo catch cast error ?
391
-    #def to_sql(self, value):
392
-    #    return value
393
-
394
-    def to_value(self, value):
395
-        if value == None:
396
-            return super(EmField_integer, self).to_value(value)
397
-        return int(value)
398
-
399
-
400
-## @brief Handles boolean fields
401
-# @note Enforce type to be 'boolean'
402
-# @note Default name is 'boolean'
403
-class EmField_boolean(EmFieldType):
404
-    def __init__(self, **kwargs):
405
-        self._init(kwargs)
406
-        #Default name
407
-        kwargs = self.__class__._argDefault(kwargs, 'name', 'boolean')
408
-        #Type enforcing
409
-        kwargs = self.__class__._setType(kwargs, 'boolean')
410
-        super(EmField_boolean, self).__init__(**kwargs)
411
-
412
-    #def to_sql(self, value):
413
-    #    return 1 if super(EmField_boolean, self).to_sql(value) else 0
414
-
415
-    def to_value(self, value):
416
-        if value == None:
417
-            return super(EmField_boolean, self).to_value(value)
418
-        self.value = bool(value)
419
-        return self.value
420
-
421
-
422
-## @brief Handles string fields
423
-# @note Enforce type to be (varchar)
424
-# @note Default 'name' is 'char'
425
-# @note Default 'type_length' is 76
426
-class EmField_char(EmFieldType):
427
-
428
-    default_length = 76
429
-
430
-    def __init__(self, **kwargs):
431
-        self._init(kwargs)
432
-        kwargs = self.__class__._argDefault(kwargs, 'type_length', self.__class__.default_length)
433
-        kwargs = self.__class__._argDefault(kwargs, 'name', 'char')
434
-        #Type enforcing
435
-        kwargs = self.__class__._setType(kwargs, 'varchar')
436
-        super(EmField_char, self).__init__(**kwargs)
437
-
438
-    #def to_sql(self, value):
439
-    #    return str(value)
440
-
441
-
442
-## @brief Handles date fields
443
-# @note Enforce type to be 'datetime'
444
-# @todo rename to EmField_datetime
445
-# @todo timezones support
446
-class EmField_date(EmFieldType):
447
-    def __init__(self, **kwargs):
448
-        self._init(kwargs)
449
-        kwargs = self.__class__._argDefault(kwargs, 'name', 'date')
450
-        #Type enforcing
451
-        kwargs = self.__class__._setType(kwargs, 'datetime')
452
-        super(EmField_date, self).__init__(**kwargs)
453
-
454
-    #def to_sql(self, value):
455
-    #    return value #thanks to sqlalchemy
456
-
457
-    def to_value(self, value):
458
-        if value == None:
459
-            return super(EmField_date, self).to_value(value)
460
-        if isinstance(value, int):
461
-            #assume its a timestamp
462
-            return datetime.fromtimestamp(value)
463
-        if isinstance(value, datetime.datetime):
464
-            return value
465
-
466
-
467
-## @brief Handles strings with translations
468
-class EmField_mlstring(EmField_char):
469
-
470
-    def __init__(self, **kwargs):
471
-        self._init(kwargs)
472
-        kwargs = self.__class__._argDefault(kwargs, 'name', 'mlstr')
473
-        super(EmField_mlstring, self).__init__(**kwargs)
474
-
475
-    #def to_sql(self, value):
476
-    #    return value.__str__()
477
-
478
-    def to_value(self, value):
479
-        if value == None:
480
-            return super(EmField_mlstring, self).to_value(value)
481
-        if isinstance(value, str):
482
-            return MlString.load(value)
483
-        elif isinstance(value, MlString):
484
-            return value
485
-        raise TypeError("<class str> or <class MlString> excepted. But got "+str(type(value)))
486
-
487
-
488
-## @brief Handles lodel uid fields
489
-class EmField_uid(EmField_integer):
490
-
491
-    def __init__(self, **kwargs):
492
-        self._init(kwargs)
493
-        kwargs = self.__class__._argEnforce(kwargs, 'primarykey', True)
494
-        super(EmField_uid, self).__init__(**kwargs)

+ 5
- 0
EditorialModel/fieldtypes/__init__.py View File

@@ -0,0 +1,5 @@
1
+from os.path import dirname, basename, isfile
2
+import glob
3
+modules = glob.glob(dirname(__file__)+"/*.py")
4
+__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and f != '__init__.py']
5
+

+ 13
- 0
EditorialModel/fieldtypes/char.py View File

@@ -0,0 +1,13 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+from EditorialModel.fields import EmField
4
+
5
+class EmFieldChar(EmField):
6
+    
7
+    ftype = 'char'
8
+
9
+    def __init__(self, max_length=64, **kwargs):
10
+        self.max_length = max_length
11
+        super(EmFieldChar, self).__init__(**kwargs)
12
+
13
+fclass = EmFieldChar

+ 13
- 0
EditorialModel/fieldtypes/int.py View File

@@ -0,0 +1,13 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+from EditorialModel.fields import EmField
4
+
5
+
6
+class EmFieldInt(EmField):
7
+    
8
+    ftype = 'int'
9
+
10
+    def __init__(self, **kwargs):
11
+        super(EmFieldChar, self).__init__(**kwargs)
12
+
13
+fclass=EmFieldInt

+ 29
- 0
EditorialModel/fieldtypes/regexchar.py View File

@@ -0,0 +1,29 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+import re
4
+from EditorialModel.fieldtypes import EmFieldChar
5
+
6
+class EmFieldCharRegex(EmFieldChar):
7
+    
8
+    def __init__(self, regex = '', **kwargs):
9
+        self.regex = regex
10
+        v_re = re.compile(regex) #trigger an error if invalid regex
11
+
12
+        super(EmFieldCharRegex, self).__init__(**kwargs)
13
+
14
+    def validation_function(self, raise_e = None, ret_valid = None, ret_invalid = None):
15
+        super(EmFieldChar, self).validation_function(raise_e, ret_valid, ret_invalid)
16
+
17
+        if not raise_e is None:
18
+            def v_fun(value):
19
+                if not re.match(self.regex):
20
+                    raise raise_e
21
+        else:
22
+            def v_fun(value):
23
+                if not re.match(self.regex):
24
+                    return ret_invalid
25
+                else:
26
+                    return ret_valid
27
+        return v_fun
28
+ 
29
+fclass = EmFieldCharRegex

+ 20
- 0
EditorialModel/fieldtypes/rel2type.py View File

@@ -0,0 +1,20 @@
1
+#-*- coding: utf-8 -*-
2
+
3
+from EditorialModel.fields import EmField
4
+
5
+class EmFieldRel2Type(EmField):
6
+
7
+    ftype= 'rel2type'
8
+
9
+    def __init__(self, rel_to_type_id, **kwargs):
10
+        self.rel_to_type_id = rel_to_type_id
11
+        super(EmFieldRel2Type, self).__init__(**kwargs)
12
+
13
+    def get_related_type(self):
14
+        return self.model.component(self.rel_to_type_id)
15
+
16
+    def get_related_fields(self):
17
+        return [ f for f in self.model.components(EmField) if f.rel_field_id == self.uid ]
18
+        
19
+
20
+fclass = EmFieldRel2Type

+ 27
- 6
EditorialModel/model.py View File

@@ -3,6 +3,7 @@
3 3
 ## @file editorialmodel.py
4 4
 # Manage instance of an editorial model
5 5
 
6
+import EditorialModel
6 7
 from EditorialModel.migrationhandler.dummy import DummyMigrationHandler
7 8
 from EditorialModel.classes import EmClass
8 9
 from EditorialModel.fieldgroups import EmFieldGroup
@@ -53,6 +54,9 @@ class Model(object):
53 54
     # @return A class name as string or False if cls is not an EmComponent child class
54 55
     def name_from_emclass(em_class):
55 56
         if em_class not in Model.components_class:
57
+            spl = em_class.__module__.split('.')
58
+            if spl[1] == 'fieldtypes':
59
+                return 'EmField'
56 60
             return False
57 61
         return em_class.__name__
58 62
 
@@ -67,11 +71,20 @@ class Model(object):
67 71
             #Store and delete the EmComponent class name from datas
68 72
             cls_name = kwargs['component']
69 73
             del kwargs['component']
70
-            cls = self.emclass_from_name(cls_name)
74
+            
75
+            if cls_name == 'EmField':
76
+                if not 'type' in kwargs:
77
+                    raise AttributeError("Missing 'type' from EmField instanciation")
78
+
79
+                cls = EditorialModel.fields.EmField.get_field_class(kwargs['type'])
80
+                del(kwargs['type'])
81
+            else:
82
+                cls = self.emclass_from_name(cls_name)
83
+
71 84
             if cls:
72 85
                 kwargs['uid'] = uid
73 86
                 # create a dict for the component and one indexed by uids, store instanciated component in it
74
-                self._components['uids'][uid] = cls(self, **kwargs)
87
+                self._components['uids'][uid] = cls(model=self, **kwargs)
75 88
                 self._components[cls_name].append(self._components['uids'][uid])
76 89
             else:
77 90
                 raise ValueError("Unknow EmComponent class : '" + cls_name + "'")
@@ -109,9 +122,10 @@ class Model(object):
109 122
     ## Sort components by rank in Model::_components
110 123
     # @param emclass pythonClass : The type of components to sort
111 124
     # @throw AttributeError if emclass is not valid
125
+    # @warning disabled the test on component_class because of EmField new way of working
112 126
     def sort_components(self, component_class):
113
-        if component_class not in self.components_class:
114
-            raise AttributeError("Bad argument emclass : '" + component_class + "', excpeting one of " + str(self.components_class))
127
+        #if component_class not in self.components_class:
128
+        #    raise AttributeError("Bad argument emclass : '" + str(component_class) + "', excpeting one of " + str(self.components_class))
115 129
 
116 130
         self._components[self.name_from_emclass(component_class)] = sorted(self.components(component_class), key=lambda comp: comp.rank)
117 131
 
@@ -129,9 +143,16 @@ class Model(object):
129 143
     # @param datas dict : the options needed by the component creation
130 144
     # @throw ValueError if datas['rank'] is not valid (too big or too small, not an integer nor 'last' or 'first' )
131 145
     # @todo Handle a raise from the migration handler
146
+    # @todo Transform the datas arg in **datas ?
132 147
     def create_component(self, component_type, datas):
133
-
134
-        em_obj = self.emclass_from_name(component_type)
148
+        
149
+        if component_type == 'EmField':
150
+            if not 'type' in datas:
151
+                raise AttributeError("Missing 'type' from EmField instanciation")
152
+            em_obj = EditorialModel.fields.EmField.get_field_class(datas['type'])
153
+            del(datas['type'])
154
+        else:
155
+            em_obj = self.emclass_from_name(component_type)
135 156
 
136 157
         rank = 'last'
137 158
         if 'rank' in datas:

Loading…
Cancel
Save