mirror of
https://github.com/yweber/lodel2.git
synced 2025-11-14 18:09:17 +01:00
New version (again) of the fieldtypes
This commit is contained in:
parent
4c0b8d3279
commit
773afc5b2c
9 changed files with 139 additions and 505 deletions
3
.gitignore
vendored
3
.gitignore
vendored
|
|
@ -4,4 +4,5 @@
|
|||
.idea
|
||||
Lodel/settings/locale.py
|
||||
Lodel/settings/local.py
|
||||
doc
|
||||
doc
|
||||
.*.swp
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
import importlib
|
||||
|
||||
from EditorialModel.components import EmComponent
|
||||
from EditorialModel.exceptions import EmComponentCheckError
|
||||
import EditorialModel
|
||||
|
|
@ -12,6 +14,8 @@ class EmField(EmComponent):
|
|||
|
||||
ranked_in = 'fieldgroup_id'
|
||||
|
||||
ftype = None
|
||||
|
||||
fieldtypes = {
|
||||
'int': models.IntegerField,
|
||||
'integer': models.IntegerField,
|
||||
|
|
@ -30,24 +34,44 @@ class EmField(EmComponent):
|
|||
|
||||
## Instanciate a new EmField
|
||||
# @todo define and test type for icon and fieldtype
|
||||
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):
|
||||
# @warning nullable == True by default
|
||||
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):
|
||||
|
||||
self.fieldgroup_id = fieldgroup_id
|
||||
self.check_type('fieldgroup_id', int)
|
||||
self.fieldtype = fieldtype
|
||||
self.optional = optional
|
||||
self.check_type('optional', bool)
|
||||
self.internal = internal
|
||||
self.check_type('internal', bool)
|
||||
self.rel_to_type_id = rel_to_type_id
|
||||
self.check_type('rel_to_type_id', (int, type(None)))
|
||||
self.rel_field_id = rel_field_id
|
||||
self.check_type('rel_field_id', (int, type(None)))
|
||||
self.icon = icon
|
||||
|
||||
self.nullable = nullable
|
||||
self.default = default
|
||||
|
||||
self.options = kwargs
|
||||
|
||||
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)
|
||||
|
||||
@staticmethod
|
||||
def get_field_class(ftype, **kwargs):
|
||||
ftype_module = importlib.import_module('EditorialModel.fieldtypes.%s'%ftype)
|
||||
return ftype_module.fclass
|
||||
|
||||
## @brief Abstract method that should return a validation function
|
||||
# @param raise_e Exception : if not valid raise this exception
|
||||
# @param ret_valid : if valid return this value
|
||||
# @param ret_invalid : if not valid return this value
|
||||
def validation_function(self, raise_e = None, ret_valid = None, ret_invalid = None):
|
||||
if self.__class__ == EmField:
|
||||
raise NotImplementedError("Abstract method")
|
||||
if raise_e is None and ret_valid is None:
|
||||
raise AttributeError("Behavior doesn't allows to return a valid validation function")
|
||||
|
||||
return False
|
||||
|
||||
|
||||
## @brief Return the list of relation fields for a rel_to_type
|
||||
# @return None if the field is not a rel_to_type else return a list of EmField
|
||||
def rel_to_type_fields(self):
|
||||
|
|
@ -72,6 +96,7 @@ class EmField(EmComponent):
|
|||
def delete_check(self):
|
||||
return True
|
||||
|
||||
"""
|
||||
def to_django(self):
|
||||
if self.fieldtype in ('varchar', 'char'):
|
||||
max_length = None if 'max_length' not in self.options else self.options['max_length']
|
||||
|
|
@ -86,3 +111,4 @@ class EmField(EmComponent):
|
|||
return models.NullBooleanField(**self.options)
|
||||
|
||||
return self.fieldtypes[self.fieldtype](**self.options)
|
||||
"""
|
||||
|
|
|
|||
|
|
@ -1,494 +0,0 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from django.db import models
|
||||
import re
|
||||
import datetime
|
||||
import json
|
||||
import importlib
|
||||
import copy
|
||||
import EditorialModel
|
||||
from Lodel.utils.mlstring import MlString
|
||||
|
||||
|
||||
## @brief Characterise fields for LeObject and EmComponent
|
||||
# This class handles values rules for LeObject and EmComponents.
|
||||
#
|
||||
# It allows to EmFieldValue classes family to have rules to cast, validate and save values.
|
||||
#
|
||||
# There is exposed methods that allows LeObject and EmType to run a save sequence. This methods are :
|
||||
# - EmFieldType.to_value() That cast a value to an EmFieldType internal storage
|
||||
# - EmFieldType.is_valid() That indicates wether or not a value is valid
|
||||
# - EmFieldType.pre_save() That returns weighted SQL request that must be run before any value save @ref EditorialModel::types::EmType.save_values()
|
||||
# - EmFieldType.to_sql() That returns a value that can be inserted in database.
|
||||
# - EmFieldType.post_save() That returns weighted SQL request that must be run after any value save @ref EditorialModel::types::EmType.save_values()
|
||||
#
|
||||
class EmFieldType(object):
|
||||
|
||||
## Stores options and default value for EmFieldType
|
||||
# options list :
|
||||
# - type (str|None) : if None will make an 'abstract' fieldtype (with no value assignement possible)
|
||||
# - nullable (bool) : tell whether or not a fieldType accept NULL value
|
||||
# - default (mixed) : The default value for a FieldType
|
||||
# - primarykey (bool) : If true the fieldType represent a PK
|
||||
# - autoincrement (bool) : If true the fieldType will be autoincremented
|
||||
# - index (bool) : If true the columns will be indexed in Db
|
||||
# - name (str) : FieldType name
|
||||
# - doc (str) : FieldType documentation
|
||||
# - onupdate (callable) : A callback to call on_update
|
||||
# - valueobject (EmFieldValue or childs) : An object that represent values for this fieldType
|
||||
# - type_* (mixed) : Use to construct an options dictinnary for a type (exemple : type_length => nnewColumn(lenght= [type_lenght VALUE] )) @ref EmFieldSQLType
|
||||
# - validators (list) : List of validator functions to use
|
||||
_opt = {
|
||||
'name': None,
|
||||
'type': None,
|
||||
'nullable': True,
|
||||
'default': None,
|
||||
'primarykey': False,
|
||||
'autoincrement': False,
|
||||
'uniq': False,
|
||||
'index': False,
|
||||
'doc': None,
|
||||
'onupdate': None,
|
||||
'valueobject': None,
|
||||
'validators': None
|
||||
}
|
||||
|
||||
## Instanciate an EmFieldType
|
||||
# For arguments see @ref EmFieldType::_opt
|
||||
# @see EmFieldType::_opt
|
||||
def __init__(self, **kwargs):
|
||||
self.__init(kwargs)
|
||||
self.type_options = dict()
|
||||
|
||||
# stores all col_* arguments into the self.type_options dictionary
|
||||
args = kwargs.copy()
|
||||
for optname in args:
|
||||
type_opt = re.sub(r'^type_', '', optname)
|
||||
if type_opt != optname:
|
||||
self.type_options[type_opt] = args[optname]
|
||||
del kwargs[optname]
|
||||
|
||||
# checks if the other arguments are valid
|
||||
if len(set(kwargs.keys()) - set(self.__class__._opt.keys())) > 0:
|
||||
badargs = ""
|
||||
for bad in set(kwargs.keys()) - set(self.__class__._opt.keys()):
|
||||
badargs += " " + bad
|
||||
raise TypeError("Unexpected arguments : %s" % badargs)
|
||||
|
||||
# stores other arguments as instance attribute
|
||||
for opt_name in self.__class__._opt:
|
||||
setattr(self, opt_name, (kwargs[opt_name] if opt_name in kwargs else self.__class__._opt[opt_name]))
|
||||
|
||||
# checks type's options valididty
|
||||
if self.type != None:
|
||||
try:
|
||||
EmFieldSQLType.sqlType(self.type, **self.type_options)
|
||||
except TypeError as e:
|
||||
raise e
|
||||
|
||||
# Default value for name
|
||||
if self.name == None:
|
||||
if self.__class__ == EmFieldType:
|
||||
self.name = 'generic'
|
||||
else:
|
||||
self.name = self.__class__.__name__
|
||||
|
||||
# Default value for doc
|
||||
if self.doc == None:
|
||||
if self.__class__ == EmFieldType:
|
||||
self.doc = 'Abstract generic EmFieldType'
|
||||
else:
|
||||
self.doc = self.__class__.__name__
|
||||
|
||||
## MUST be called first in each constructor
|
||||
# @todo this solution is not good (look at the __init__ for EmFieldType childs)
|
||||
def __init(self, kwargs):
|
||||
try:
|
||||
self.args_copy
|
||||
except AttributeError:
|
||||
self.args_copy = kwargs.copy()
|
||||
|
||||
@property
|
||||
## A predicate that indicates whether or not an EmFieldType is "abstract"
|
||||
def is_abstract(self):
|
||||
return (self.type == None)
|
||||
|
||||
## Returns a copy of the current EmFieldType
|
||||
def copy(self):
|
||||
args = self.args_copy.copy()
|
||||
return self.__class__(**args)
|
||||
|
||||
def dump_opt(self):
|
||||
return json.dumps(self.args_copy)
|
||||
|
||||
@staticmethod
|
||||
## Return an instance from a classname and options from dump_opt
|
||||
# @param classname str: The EmFieldType class name
|
||||
# @param json_opt str: getted from dump_opt
|
||||
def restore(colname, classname, json_opt):
|
||||
field_type_class = getattr(EditorialModel.fieldtypes, classname)
|
||||
init_opt = json.loads(json_opt)
|
||||
init_opt['name'] = colname
|
||||
return field_type_class(**init_opt)
|
||||
|
||||
## Return a value object 'driven' by this EmFieldType
|
||||
# @param name str: The column name associated with the value
|
||||
# @param *init_val mixed: If given this will be the initialisation value
|
||||
# @return a EmFieldValue instance
|
||||
# @todo better default value (and bad values) handling
|
||||
def valueObject(self, name, *init_val):
|
||||
if self.valueObject == None:
|
||||
return EmFieldValue(name, self, *init_val)
|
||||
return self.valueObject(name, self, *init_val)
|
||||
|
||||
## Cast to the correct value
|
||||
# @param v mixed : the value to cast
|
||||
# @return A gently casted value
|
||||
# @throw ValueError if v is innapropriate
|
||||
# @throw NotImplementedError if self is an abstract EmFieldType
|
||||
def to_value(self, v):
|
||||
if self.type == None:
|
||||
raise NotImplemented("This EmFieldType is abstract")
|
||||
if v == None and not self.nullable:
|
||||
raise TypeError("Field not nullable")
|
||||
return v
|
||||
|
||||
## to_value alias
|
||||
# @param value mixed : the value to cast
|
||||
# @return A casted value
|
||||
def from_string(self, value):
|
||||
return self.to_value(value)
|
||||
|
||||
## Returns a gently sql forged value
|
||||
# @return A sql forged value
|
||||
# @warning It assumes that the value is correct and comes from an EmFieldValue object
|
||||
def to_sql(self, value):
|
||||
if self.is_abstract:
|
||||
raise NotImplementedError("This EmFieldType is abstract")
|
||||
return True
|
||||
|
||||
## Returns whether or not a value is valid for this EmFieldType
|
||||
# @note This function always returns True and is here for being overloaded by child objects
|
||||
# @return A boolean, True if valid else False
|
||||
def is_valid(self, value):
|
||||
if self.is_abstract:
|
||||
raise NotImplementedError("This EmFieldType is abstract")
|
||||
return True
|
||||
|
||||
## Pre-save actions
|
||||
def pre_save(self):
|
||||
if self.is_abstract:
|
||||
raise NotImplementedError("This EmFieldType is abstract")
|
||||
return []
|
||||
|
||||
## Post-save actions
|
||||
def post_save(self):
|
||||
if self.is_abstract:
|
||||
raise NotImplementedError("This EmFieldType is abstract")
|
||||
return []
|
||||
|
||||
@classmethod
|
||||
## Function designed to be called by child class to enforce a type
|
||||
# @param args dict: The kwargs argument of __init__
|
||||
# @param typename str: The typename to enforce
|
||||
# @return The new kwargs to be used
|
||||
# @throw TypeError if type is present is args
|
||||
def _setType(cl, args, typename):
|
||||
return cl._argEnforce(args, 'type', typename, True)
|
||||
|
||||
@classmethod
|
||||
## Function designed to be called by child's constructo to enforce an argument
|
||||
# @param args dict: The constructor's kwargs
|
||||
# @param argname str: The name of the argument to enforce
|
||||
# @param argval mixed: The value we want to enforce
|
||||
# @param Return a new kwargs
|
||||
# @throw TypeError if type is present is args and exception argument is True
|
||||
def _argEnforce(cl, args, argname, argval, exception=True):
|
||||
if exception and argname in args:
|
||||
raise TypeError("Invalid argument '"+argname+"' for "+cl.__class__.__name__+" __init__")
|
||||
args[argname] = argval
|
||||
return args
|
||||
|
||||
@classmethod
|
||||
## Function designed to be called by child's constructor to set a default value
|
||||
# @param args dict: The constructor's kwargs
|
||||
# @param argname str: The name of the argument with default value
|
||||
# @param argval mixed : The default value
|
||||
# @return a new kwargs dict
|
||||
def _argDefault(cl, args, argname, argval):
|
||||
if argname not in args:
|
||||
args[argname] = argval
|
||||
return args
|
||||
|
||||
class EmFieldValue(object):
|
||||
|
||||
## Instanciates a EmFieldValue
|
||||
# @param name str : The column name associated with this value
|
||||
# @param fieldtype EmFieldType: The EmFieldType defining the value
|
||||
# @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
|
||||
# @throw TypeError if more than 2 arguments given
|
||||
# @throw TypeError if fieldtype is not an EmFieldType
|
||||
# @throw TypeError if fieldtype is an abstract EmFieldType
|
||||
def __init__(self, name, fieldtype, *value):
|
||||
if not isinstance(fieldtype, EmFieldType):
|
||||
raise TypeError("Expected <class EmFieldType> for 'fieldtype' argument, but got : %s instead" % str(type(fieldtype)))
|
||||
if fieldtype.is_abstract:
|
||||
raise TypeError("The given fieldtype in argument is abstract.")
|
||||
|
||||
# This copy ensures that the fieldtype will not change during the value lifecycle
|
||||
super(EmFieldValue, self).__setattr__('fieldtype', fieldtype.copy())
|
||||
|
||||
if len(value) > 1:
|
||||
raise TypeError("Accept only 2 positionnal parameters. %s given." % str(len(value)+1))
|
||||
elif len(value) == 1:
|
||||
self.value = value[0]
|
||||
else:
|
||||
self.value = fieldtype.default
|
||||
|
||||
# Use this to set value in the constructor
|
||||
setv = super(EmFieldValue, self).__setattr__
|
||||
# This copy makes column attributes accessible easily
|
||||
for attrname in self.fieldtype.__dict__:
|
||||
setv(attrname, getattr(self.fieldtype, attrname))
|
||||
|
||||
# Assign some EmFieldType methods to the value
|
||||
setv('from_python', self.fieldtype.to_value)
|
||||
setv('from_string', self.fieldtype.to_value)
|
||||
#setv('sqlCol', self.fieldtype.sqlCol)
|
||||
|
||||
## The only writable attribute of EmFieldValue is the value
|
||||
# @param name str: Have to be value
|
||||
# @param value mixed: The value to set
|
||||
# @throw AtrributeError if another attribute than value is to be set
|
||||
# @throw ValueError if self.to_value raises it
|
||||
# @see EmFieldType::to_value()
|
||||
def __setattr__(self, name, value):
|
||||
if name != "value":
|
||||
raise AttributeError("EmFieldValue has only the value property settable")
|
||||
super(EmFieldValue,self).__setattr__('value', self.fieldtype.to_value(value))
|
||||
|
||||
##
|
||||
# @warning When getting the fieldtype you actually get a copy of it to prevent any modifications !
|
||||
def __getattr__(self, name):
|
||||
if name == 'fieldtype':
|
||||
return self.fieldtype.copy()
|
||||
return super(EmFieldValue, self).__getattribute__(name)
|
||||
|
||||
## @brief Return a valid SQL value
|
||||
#
|
||||
# Can be used to convert any value (giving one positionnal argument) or to return the current value
|
||||
# @param *value list: If a positionnal argument is given return it and not the instance value
|
||||
# @return A value suitable for sql
|
||||
def to_sql(self, *value):
|
||||
if len(value) > 1:
|
||||
raise TypeError("Excepted 0 or 1 positional argument but got "+str(len(value)))
|
||||
elif len(value) == 1:
|
||||
return self.fieldtype.to_sql(value[0])
|
||||
return self.fieldtype.to_sql(self.value)
|
||||
|
||||
class EmFieldSQLType(object):
|
||||
_integer = {'sql': models.IntegerField}
|
||||
_bigint = {'sql': models.BigIntegerField}
|
||||
_smallint = {'sql': models.SmallIntegerField}
|
||||
_boolean = {'sql': models.BooleanField}
|
||||
_nullableboolean = {'sql': models.NullBooleanField}
|
||||
_float = {'sql': models.FloatField}
|
||||
_varchar = {'sql': models.CharField}
|
||||
_text = {'sql': models.TextField}
|
||||
_time = {'sql': models.TimeField}
|
||||
_date = {'sql': models.DateField}
|
||||
_datetime = {'sql': models.DateTimeField}
|
||||
|
||||
_names = {
|
||||
'int': _integer,
|
||||
'integer': _integer,
|
||||
'bigint': _bigint,
|
||||
'smallint': _smallint,
|
||||
'boolean': _boolean,
|
||||
'bool': _boolean,
|
||||
'float': _float,
|
||||
'char': _varchar,
|
||||
'varchar': _varchar,
|
||||
'text': _text,
|
||||
'time': _time,
|
||||
'date': _date,
|
||||
'datetime': _datetime,
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def sqlType(cls, name, **kwargs):
|
||||
if not isinstance(name, str):
|
||||
raise TypeError("Expect <class str>, <class int>|None but got : %s %s" % (str(type(name)), str(type(size))))
|
||||
name = name.lower()
|
||||
if name not in cls._names:
|
||||
raise ValueError("Unknown type '%s'" % name)
|
||||
|
||||
if name in ['boolean','bool'] and kwargs['nullable'] in [1,'true']:
|
||||
sqlclass = _nullableboolean
|
||||
else:
|
||||
sqlclass = cls._names[name]
|
||||
|
||||
if len(kwargs) == 0:
|
||||
return sqlclass['sql']
|
||||
|
||||
return sqlclass['sql'](**kwargs)
|
||||
|
||||
|
||||
## @brief Represents values with common arithmetic operations
|
||||
class EmFieldValue_int(EmFieldValue):
|
||||
def __int__(self):
|
||||
return self.value
|
||||
|
||||
def __add__(self, other):
|
||||
return self.value + other
|
||||
|
||||
def __sub__(self, other):
|
||||
return self.value - other
|
||||
|
||||
def __mul__(self, other):
|
||||
return self.value * other
|
||||
|
||||
def __div__(self, other):
|
||||
return self.value / other
|
||||
|
||||
def __mod__(self, other):
|
||||
return self.value % other
|
||||
|
||||
def __iadd__(self, other):
|
||||
self.value = int(self.value + other)
|
||||
return self
|
||||
|
||||
def __isub__(self, other):
|
||||
self.value = int(self.value - other)
|
||||
return self
|
||||
|
||||
def __imul__(self, other):
|
||||
self.value = int(self.value * other)
|
||||
return self
|
||||
|
||||
def __idiv__(self, other):
|
||||
self.value = int(self.value / other)
|
||||
return self
|
||||
|
||||
|
||||
## @brief Handles integer fields
|
||||
# @note Enforcing type to be int
|
||||
# @note Default name is 'integer' and default 'valueobject' is EmFieldValue_int
|
||||
class EmField_integer(EmFieldType):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._init(kwargs)
|
||||
# Default name
|
||||
kwargs = self.__class__._argDefault(kwargs, 'name', 'integer')
|
||||
# Default value object
|
||||
kwargs = self.__class__._argDefault(kwargs, 'valueobject', EmFieldValue_int)
|
||||
# Type enforcing
|
||||
kwargs = self.__class__._setType(kwargs, 'int')
|
||||
super(EmField_integer, self).__init__(**kwargs)
|
||||
|
||||
##
|
||||
# @todo catch cast error ?
|
||||
#def to_sql(self, value):
|
||||
# return value
|
||||
|
||||
def to_value(self, value):
|
||||
if value == None:
|
||||
return super(EmField_integer, self).to_value(value)
|
||||
return int(value)
|
||||
|
||||
|
||||
## @brief Handles boolean fields
|
||||
# @note Enforce type to be 'boolean'
|
||||
# @note Default name is 'boolean'
|
||||
class EmField_boolean(EmFieldType):
|
||||
def __init__(self, **kwargs):
|
||||
self._init(kwargs)
|
||||
#Default name
|
||||
kwargs = self.__class__._argDefault(kwargs, 'name', 'boolean')
|
||||
#Type enforcing
|
||||
kwargs = self.__class__._setType(kwargs, 'boolean')
|
||||
super(EmField_boolean, self).__init__(**kwargs)
|
||||
|
||||
#def to_sql(self, value):
|
||||
# return 1 if super(EmField_boolean, self).to_sql(value) else 0
|
||||
|
||||
def to_value(self, value):
|
||||
if value == None:
|
||||
return super(EmField_boolean, self).to_value(value)
|
||||
self.value = bool(value)
|
||||
return self.value
|
||||
|
||||
|
||||
## @brief Handles string fields
|
||||
# @note Enforce type to be (varchar)
|
||||
# @note Default 'name' is 'char'
|
||||
# @note Default 'type_length' is 76
|
||||
class EmField_char(EmFieldType):
|
||||
|
||||
default_length = 76
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._init(kwargs)
|
||||
kwargs = self.__class__._argDefault(kwargs, 'type_length', self.__class__.default_length)
|
||||
kwargs = self.__class__._argDefault(kwargs, 'name', 'char')
|
||||
#Type enforcing
|
||||
kwargs = self.__class__._setType(kwargs, 'varchar')
|
||||
super(EmField_char, self).__init__(**kwargs)
|
||||
|
||||
#def to_sql(self, value):
|
||||
# return str(value)
|
||||
|
||||
|
||||
## @brief Handles date fields
|
||||
# @note Enforce type to be 'datetime'
|
||||
# @todo rename to EmField_datetime
|
||||
# @todo timezones support
|
||||
class EmField_date(EmFieldType):
|
||||
def __init__(self, **kwargs):
|
||||
self._init(kwargs)
|
||||
kwargs = self.__class__._argDefault(kwargs, 'name', 'date')
|
||||
#Type enforcing
|
||||
kwargs = self.__class__._setType(kwargs, 'datetime')
|
||||
super(EmField_date, self).__init__(**kwargs)
|
||||
|
||||
#def to_sql(self, value):
|
||||
# return value #thanks to sqlalchemy
|
||||
|
||||
def to_value(self, value):
|
||||
if value == None:
|
||||
return super(EmField_date, self).to_value(value)
|
||||
if isinstance(value, int):
|
||||
#assume its a timestamp
|
||||
return datetime.fromtimestamp(value)
|
||||
if isinstance(value, datetime.datetime):
|
||||
return value
|
||||
|
||||
|
||||
## @brief Handles strings with translations
|
||||
class EmField_mlstring(EmField_char):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._init(kwargs)
|
||||
kwargs = self.__class__._argDefault(kwargs, 'name', 'mlstr')
|
||||
super(EmField_mlstring, self).__init__(**kwargs)
|
||||
|
||||
#def to_sql(self, value):
|
||||
# return value.__str__()
|
||||
|
||||
def to_value(self, value):
|
||||
if value == None:
|
||||
return super(EmField_mlstring, self).to_value(value)
|
||||
if isinstance(value, str):
|
||||
return MlString.load(value)
|
||||
elif isinstance(value, MlString):
|
||||
return value
|
||||
raise TypeError("<class str> or <class MlString> excepted. But got "+str(type(value)))
|
||||
|
||||
|
||||
## @brief Handles lodel uid fields
|
||||
class EmField_uid(EmField_integer):
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
self._init(kwargs)
|
||||
kwargs = self.__class__._argEnforce(kwargs, 'primarykey', True)
|
||||
super(EmField_uid, self).__init__(**kwargs)
|
||||
5
EditorialModel/fieldtypes/__init__.py
Normal file
5
EditorialModel/fieldtypes/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
from os.path import dirname, basename, isfile
|
||||
import glob
|
||||
modules = glob.glob(dirname(__file__)+"/*.py")
|
||||
__all__ = [ basename(f)[:-3] for f in modules if isfile(f) and f != '__init__.py']
|
||||
|
||||
13
EditorialModel/fieldtypes/char.py
Normal file
13
EditorialModel/fieldtypes/char.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from EditorialModel.fields import EmField
|
||||
|
||||
class EmFieldChar(EmField):
|
||||
|
||||
ftype = 'char'
|
||||
|
||||
def __init__(self, max_length=64, **kwargs):
|
||||
self.max_length = max_length
|
||||
super(EmFieldChar, self).__init__(**kwargs)
|
||||
|
||||
fclass = EmFieldChar
|
||||
13
EditorialModel/fieldtypes/int.py
Normal file
13
EditorialModel/fieldtypes/int.py
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from EditorialModel.fields import EmField
|
||||
|
||||
|
||||
class EmFieldInt(EmField):
|
||||
|
||||
ftype = 'int'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
super(EmFieldChar, self).__init__(**kwargs)
|
||||
|
||||
fclass=EmFieldInt
|
||||
29
EditorialModel/fieldtypes/regexchar.py
Normal file
29
EditorialModel/fieldtypes/regexchar.py
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
import re
|
||||
from EditorialModel.fieldtypes import EmFieldChar
|
||||
|
||||
class EmFieldCharRegex(EmFieldChar):
|
||||
|
||||
def __init__(self, regex = '', **kwargs):
|
||||
self.regex = regex
|
||||
v_re = re.compile(regex) #trigger an error if invalid regex
|
||||
|
||||
super(EmFieldCharRegex, self).__init__(**kwargs)
|
||||
|
||||
def validation_function(self, raise_e = None, ret_valid = None, ret_invalid = None):
|
||||
super(EmFieldChar, self).validation_function(raise_e, ret_valid, ret_invalid)
|
||||
|
||||
if not raise_e is None:
|
||||
def v_fun(value):
|
||||
if not re.match(self.regex):
|
||||
raise raise_e
|
||||
else:
|
||||
def v_fun(value):
|
||||
if not re.match(self.regex):
|
||||
return ret_invalid
|
||||
else:
|
||||
return ret_valid
|
||||
return v_fun
|
||||
|
||||
fclass = EmFieldCharRegex
|
||||
20
EditorialModel/fieldtypes/rel2type.py
Normal file
20
EditorialModel/fieldtypes/rel2type.py
Normal file
|
|
@ -0,0 +1,20 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from EditorialModel.fields import EmField
|
||||
|
||||
class EmFieldRel2Type(EmField):
|
||||
|
||||
ftype= 'rel2type'
|
||||
|
||||
def __init__(self, rel_to_type_id, **kwargs):
|
||||
self.rel_to_type_id = rel_to_type_id
|
||||
super(EmFieldRel2Type, self).__init__(**kwargs)
|
||||
|
||||
def get_related_type(self):
|
||||
return self.model.component(self.rel_to_type_id)
|
||||
|
||||
def get_related_fields(self):
|
||||
return [ f for f in self.model.components(EmField) if f.rel_field_id == self.uid ]
|
||||
|
||||
|
||||
fclass = EmFieldRel2Type
|
||||
|
|
@ -3,6 +3,7 @@
|
|||
## @file editorialmodel.py
|
||||
# Manage instance of an editorial model
|
||||
|
||||
import EditorialModel
|
||||
from EditorialModel.migrationhandler.dummy import DummyMigrationHandler
|
||||
from EditorialModel.classes import EmClass
|
||||
from EditorialModel.fieldgroups import EmFieldGroup
|
||||
|
|
@ -53,6 +54,9 @@ class Model(object):
|
|||
# @return A class name as string or False if cls is not an EmComponent child class
|
||||
def name_from_emclass(em_class):
|
||||
if em_class not in Model.components_class:
|
||||
spl = em_class.__module__.split('.')
|
||||
if spl[1] == 'fieldtypes':
|
||||
return 'EmField'
|
||||
return False
|
||||
return em_class.__name__
|
||||
|
||||
|
|
@ -67,11 +71,20 @@ class Model(object):
|
|||
#Store and delete the EmComponent class name from datas
|
||||
cls_name = kwargs['component']
|
||||
del kwargs['component']
|
||||
cls = self.emclass_from_name(cls_name)
|
||||
|
||||
if cls_name == 'EmField':
|
||||
if not 'type' in kwargs:
|
||||
raise AttributeError("Missing 'type' from EmField instanciation")
|
||||
|
||||
cls = EditorialModel.fields.EmField.get_field_class(kwargs['type'])
|
||||
del(kwargs['type'])
|
||||
else:
|
||||
cls = self.emclass_from_name(cls_name)
|
||||
|
||||
if cls:
|
||||
kwargs['uid'] = uid
|
||||
# create a dict for the component and one indexed by uids, store instanciated component in it
|
||||
self._components['uids'][uid] = cls(self, **kwargs)
|
||||
self._components['uids'][uid] = cls(model=self, **kwargs)
|
||||
self._components[cls_name].append(self._components['uids'][uid])
|
||||
else:
|
||||
raise ValueError("Unknow EmComponent class : '" + cls_name + "'")
|
||||
|
|
@ -109,9 +122,10 @@ class Model(object):
|
|||
## Sort components by rank in Model::_components
|
||||
# @param emclass pythonClass : The type of components to sort
|
||||
# @throw AttributeError if emclass is not valid
|
||||
# @warning disabled the test on component_class because of EmField new way of working
|
||||
def sort_components(self, component_class):
|
||||
if component_class not in self.components_class:
|
||||
raise AttributeError("Bad argument emclass : '" + component_class + "', excpeting one of " + str(self.components_class))
|
||||
#if component_class not in self.components_class:
|
||||
# raise AttributeError("Bad argument emclass : '" + str(component_class) + "', excpeting one of " + str(self.components_class))
|
||||
|
||||
self._components[self.name_from_emclass(component_class)] = sorted(self.components(component_class), key=lambda comp: comp.rank)
|
||||
|
||||
|
|
@ -129,9 +143,16 @@ class Model(object):
|
|||
# @param datas dict : the options needed by the component creation
|
||||
# @throw ValueError if datas['rank'] is not valid (too big or too small, not an integer nor 'last' or 'first' )
|
||||
# @todo Handle a raise from the migration handler
|
||||
# @todo Transform the datas arg in **datas ?
|
||||
def create_component(self, component_type, datas):
|
||||
|
||||
em_obj = self.emclass_from_name(component_type)
|
||||
|
||||
if component_type == 'EmField':
|
||||
if not 'type' in datas:
|
||||
raise AttributeError("Missing 'type' from EmField instanciation")
|
||||
em_obj = EditorialModel.fields.EmField.get_field_class(datas['type'])
|
||||
del(datas['type'])
|
||||
else:
|
||||
em_obj = self.emclass_from_name(component_type)
|
||||
|
||||
rank = 'last'
|
||||
if 'rank' in datas:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue