mirror of
https://github.com/yweber/lodel2.git
synced 2026-10-15 02:54:02 +02:00
New version of fieldtypes class hierarchy + partial migrationhandler adaptation
This commit is contained in:
parent
5acf09a1ee
commit
bbf33373d0
10 changed files with 240 additions and 168 deletions
80
DataSource/MySQL/fieldtypes.py
Normal file
80
DataSource/MySQL/fieldtypes.py
Normal file
|
|
@ -0,0 +1,80 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
## @package DataSource.MySQL.fieldtypes
|
||||
#
|
||||
# Defines usefull function to handle fieldtype in MySQL datasource
|
||||
|
||||
import EditorialModel
|
||||
from EditorialModel import fieldtypes as ed_fieldtypes
|
||||
import EditorialModel.fieldtypes.generic
|
||||
from EditorialModel.fieldtypes.generic import SingleValueFieldType, MultiValueFieldType, ReferenceFieldType
|
||||
import EditorialModel.fieldtypes.integer
|
||||
import EditorialModel.fieldtypes.char
|
||||
import EditorialModel.fieldtypes.bool
|
||||
import EditorialModel.fieldtypes.text
|
||||
import EditorialModel.fieldtypes.rel2type
|
||||
|
||||
## @brief Returns column specs from fieldtype
|
||||
# @param emfieldtype EmFieldType : An EmFieldType insance
|
||||
# @todo escape default value
|
||||
def singlevaluefieldtype_db_init_specs(emfieldtype):
|
||||
colspec = ''
|
||||
if not emfieldtype.nullable:
|
||||
colspec = 'NOT NULL'
|
||||
if hasattr(emfieldtype, 'default'):
|
||||
colspec += ' DEFAULT '
|
||||
if emfieldtype.default is None:
|
||||
colspec += 'NULL '
|
||||
else:
|
||||
colspec += emfieldtype.default # ESCAPE VALUE HERE !!!!
|
||||
|
||||
if emfieldtype.name == 'pk':
|
||||
colspec += ' AUTO_INCREMENT'
|
||||
|
||||
return colspec
|
||||
|
||||
## @brief Given a fieldtype return instructions to be executed by the migration handler
|
||||
#
|
||||
# The returned value in a tuple of len = 3
|
||||
#
|
||||
# The first items gives instruction type. Possible values are :
|
||||
# - 'column' : add a column
|
||||
# - the second tuple item is the SQL type of the new column
|
||||
# - the third tuple item is the SQL specs (constraints like default value, nullable, unique , auto_increment etc.)
|
||||
# - 'table' : add a column in another table and make a fk to the current table
|
||||
# - the second tuple item is a tuple(key_name, key_value)
|
||||
# - the third tuple item is a tuple(column_type, column_spec)
|
||||
# @param fieldtype GenericFieldType : A FieldType instance
|
||||
# @return a tuple (instruction_type, infos)
|
||||
def fieldtype_db_init(fieldtype):
|
||||
if isinstance(fieldtype, EditorialModel.fieldtypes.rel2type.EmFieldType):
|
||||
return (None, None, None)
|
||||
elif isinstance(fieldtype, SingleValueFieldType):
|
||||
res = [ 'column', None, singlevaluefieldtype_db_init_specs(fieldtype) ]
|
||||
# We will create a column
|
||||
if isinstance(fieldtype, EditorialModel.fieldtypes.integer.EmFieldType):
|
||||
res[1] = 'INT'
|
||||
elif isinstance(fieldtype, EditorialModel.fieldtypes.char.EmFieldType):
|
||||
res[1] = 'VARCHAR(%d)' % fieldtype.max_length
|
||||
elif isinstance(fieldtype, EditorialModel.fieldtypes.text.EmFieldType):
|
||||
res[1] = 'TEXT'
|
||||
elif isinstance(fieldtype, EditorialModel.fieldtypes.bool.EmFieldType):
|
||||
res[1] = 'BOOL'
|
||||
elif isinstance(fieldtype, EditorialModel.fieldtypes.datetime.EmFieldType):
|
||||
res[1] = 'DATETIME'
|
||||
elif isinstance(fieldtype, EditorialModel.fieldtypes.generic.ReferenceFieldType):
|
||||
res[1] = 'INT'
|
||||
else:
|
||||
raise RuntimeError("Unsupported fieldtype : ", fieldtype)
|
||||
return tuple(res)
|
||||
elif isinstance(fieldtype, MultiValueFieldType):
|
||||
res = [ 'table', None, None ]
|
||||
key_type, _ = fieldtype_db_init(fieldtype.key_fieldtype)
|
||||
key_name = fieldtype.keyname
|
||||
res[1] = (key_name, key_type)
|
||||
res[2] = fieldtype_db_init(fieldtype.value_fieldtype)
|
||||
else:
|
||||
raise NotImplementedError("Not yet implemented")
|
||||
|
||||
|
||||
|
||||
|
|
@ -10,6 +10,7 @@ import EditorialModel.classtypes
|
|||
import EditorialModel.fieldtypes
|
||||
import EditorialModel.fieldtypes.generic
|
||||
|
||||
from DataSource.MySQL import fieldtypes as fieldtypes_utils
|
||||
from DataSource.MySQL import utils
|
||||
from DataSource.dummy.migrationhandler import DummyMigrationHandler
|
||||
|
||||
|
|
@ -274,8 +275,6 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
|||
|
||||
# Creating foreign keys between relation and object table
|
||||
sup_cname, sub_cname = self.get_sup_and_sub_cols()
|
||||
self._add_fk(tname, object_tname, sup_cname, self._object_pk[0], 'fk_relations_superiors')
|
||||
self._add_fk(tname, object_tname, sub_cname, self._object_pk[0], 'fk_relations_subordinate')
|
||||
|
||||
## @brief Returns the fieldname for superior and subordinate in relation table
|
||||
# @return a tuple (superior_name, subordinate_name)
|
||||
|
|
@ -301,8 +300,9 @@ class MysqlMigrationHandler(DummyMigrationHandler):
|
|||
def _create_table(self, table_name, pk_name, pk_ftype, engine, charset='utf8', if_exists='nothing'):
|
||||
#Escaped table name
|
||||
etname = utils.escape_idname(table_name)
|
||||
pk_type = self._field_to_type(pk_ftype)
|
||||
pk_specs = self._field_to_specs(pk_ftype)
|
||||
instr_type, pk_type, pk_specs = fieldtypes_utils.fieldtype_db_init(pk_ftype)
|
||||
if instr_type != 'column':
|
||||
raise ValueError("Migration handler doesn't support MultiValueFieldType as primary keys")
|
||||
|
||||
if if_exists == 'drop':
|
||||
self._query("""DROP TABLE IF EXISTS {table_name};""".format(table_name=etname))
|
||||
|
|
@ -343,11 +343,17 @@ ADD COLUMN {col_name} {col_type} {col_specs};"""
|
|||
etname = utils.escape_idname(table_name)
|
||||
ecname = utils.escape_idname(col_name)
|
||||
|
||||
instr, col_type, col_specs = fieldtypes_utils.fieldtype_db_init(col_fieldtype)
|
||||
if instr is None:
|
||||
return True
|
||||
if instr != "column":
|
||||
raise RuntimeError("Bad implementation")
|
||||
|
||||
add_col = add_col.format(
|
||||
table_name=etname,
|
||||
col_name=ecname,
|
||||
col_type=self._field_to_type(col_fieldtype),
|
||||
col_specs=self._field_to_specs(col_fieldtype),
|
||||
col_type=col_type,
|
||||
col_specs=col_specs,
|
||||
)
|
||||
try:
|
||||
self._query(add_col)
|
||||
|
|
@ -359,6 +365,31 @@ ADD COLUMN {col_name} {col_type} {col_specs};"""
|
|||
#LOG
|
||||
print("Aborded, column `%s` exists" % col_name)
|
||||
return False
|
||||
|
||||
if isinstance(col_fieldtype, EditorialModel.fieldtypes.generic.ReferenceFieldType):
|
||||
# We have to create a FK !
|
||||
if col_fieldtype.reference == 'object':
|
||||
dst_table_name = utils.common_tables['object']
|
||||
dst_col_name, _ = self._object_pk
|
||||
elif col_fieldtypes.reference == 'relation':
|
||||
dst_table_name = utils.common_tables['relation']
|
||||
dst_col_name, _ = self._relation_pk
|
||||
|
||||
fk_name = 'fk_%s-%s_%s-%s' % (
|
||||
table_name,
|
||||
col_name,
|
||||
dst_table_name,
|
||||
dst_col_name,
|
||||
)
|
||||
|
||||
self._add_fk(
|
||||
src_table_name = table_name,
|
||||
dst_table_name = dst_table_name,
|
||||
src_col_name = col_name,
|
||||
dst_col_name = dst_col_name,
|
||||
fk_name = fk_name
|
||||
)
|
||||
|
||||
return True
|
||||
|
||||
## @brief Add a foreign key
|
||||
|
|
@ -398,7 +429,7 @@ FOREIGN KEY ({src_col}) references {dst_table}({dst_col});""".format(
|
|||
self._query("""ALTER TABLE {src_table}
|
||||
DROP FOREIGN KEY {fk_name}""".format(
|
||||
src_table=utils.escape_idname(src_table_name),
|
||||
fk_name=fk_name
|
||||
fk_name=utils.escape_idname(fk_name)
|
||||
))
|
||||
except self._dbmodule.err.InternalError:
|
||||
# If the FK don't exists we do not care
|
||||
|
|
@ -412,7 +443,7 @@ DROP FOREIGN KEY {fk_name}""".format(
|
|||
colval_l_ins = dict() # param for insert trigger
|
||||
|
||||
for cname, cftype in cols_ftype.items():
|
||||
if cftype.ftype == 'datetime':
|
||||
if isinstance(cftype, EditorialModel.fieldtypes.datetime.EmFieldType):
|
||||
if cftype.now_on_update:
|
||||
colval_l_upd[cname] = 'NOW()'
|
||||
if cftype.now_on_create:
|
||||
|
|
@ -450,65 +481,6 @@ FOR EACH ROW SET {col_val_list};""".format(
|
|||
)
|
||||
self._query(trig_q)
|
||||
|
||||
## @brief Identifier escaping
|
||||
# @param idname str : An SQL identifier
|
||||
#def _idname_escape(self, idname):
|
||||
# if '`' in idname:
|
||||
# raise ValueError("Invalid name : '%s'"%idname)
|
||||
# return '`%s`'%idname
|
||||
|
||||
## @brief Returns column specs from fieldtype
|
||||
# @param emfieldtype EmFieldType : An EmFieldType insance
|
||||
# @todo escape default value
|
||||
def _field_to_specs(self, emfieldtype):
|
||||
colspec = ''
|
||||
if not emfieldtype.nullable:
|
||||
colspec = 'NOT NULL'
|
||||
if hasattr(emfieldtype, 'default'):
|
||||
colspec += ' DEFAULT '
|
||||
if emfieldtype.default is None:
|
||||
colspec += 'NULL '
|
||||
else:
|
||||
colspec += emfieldtype.default # ESCAPE VALUE HERE !!!!
|
||||
|
||||
if emfieldtype.name == 'pk':
|
||||
colspec += ' AUTO_INCREMENT'
|
||||
|
||||
return colspec
|
||||
|
||||
## @brief Given a fieldtype return a MySQL type specifier
|
||||
# @param emfieldtype EmFieldType : A fieldtype
|
||||
# @return the corresponding MySQL type
|
||||
def _field_to_type(self, emfieldtype):
|
||||
ftype = emfieldtype.ftype
|
||||
|
||||
if ftype == 'char' or ftype == 'str':
|
||||
res = "VARCHAR(%d)" % emfieldtype.max_length
|
||||
elif ftype == 'text':
|
||||
res = "TEXT"
|
||||
elif ftype == 'datetime':
|
||||
res = "DATETIME"
|
||||
# client side workaround for only one column with CURRENT_TIMESTAMP : giving NULL to timestamp that don't allows NULL
|
||||
# cf. https://dev.mysql.com/doc/refman/5.0/en/timestamp-initialization.html#idm139961275230400
|
||||
# The solution for the migration handler is to create triggers :
|
||||
# CREATE TRIGGER trigger_name BEFORE INSERT ON `my_super_table`
|
||||
# FOR EACH ROW SET NEW.my_date_column = NOW();
|
||||
# and
|
||||
# CREATE TRIGGER trigger_name BEFORE UPDATE ON
|
||||
|
||||
elif ftype == 'bool':
|
||||
res = "BOOL"
|
||||
elif ftype == 'int':
|
||||
res = "INT"
|
||||
elif ftype == 'rel2type':
|
||||
res = "INT"
|
||||
elif ftype == 'leobject':
|
||||
res = "INT"
|
||||
else:
|
||||
raise ValueError("Unsuported fieldtype ftype : %s" % ftype)
|
||||
|
||||
return res
|
||||
|
||||
## @brief Delete all table created by the MH
|
||||
# @param model Model : the Editorial model
|
||||
def __purge_db(self, model):
|
||||
|
|
|
|||
|
|
@ -1,17 +1,15 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from .generic import GenericFieldType
|
||||
from .generic import SingleValueFieldType
|
||||
|
||||
|
||||
class EmFieldType(GenericFieldType):
|
||||
class EmFieldType(SingleValueFieldType):
|
||||
|
||||
help = 'Basic string (varchar) field. Take max_length=64 as option'
|
||||
|
||||
ftype = 'char'
|
||||
|
||||
## @brief A char field
|
||||
# @brief max_length int : The maximum length of this field
|
||||
def __init__(self, max_length=64, **kwargs):
|
||||
self.max_length = max_length
|
||||
super(EmFieldType, self).__init__(ftype='char', **kwargs)
|
||||
super(EmFieldType, self).__init__(**kwargs)
|
||||
|
||||
|
|
|
|||
|
|
@ -1,14 +1,12 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from .generic import GenericFieldType
|
||||
from .generic import SingleValueFieldType
|
||||
|
||||
|
||||
class EmFieldType(GenericFieldType):
|
||||
class EmFieldType(SingleValueFieldType):
|
||||
|
||||
help = 'A datetime field. Take two boolean options now_on_update and now_on_create'
|
||||
|
||||
ftype = 'datetime'
|
||||
|
||||
## @brief A datetime field
|
||||
# @param now_on_update bool : If true the date is set to NOW on update
|
||||
# @param now_on_create bool : If true the date is set to NEW on creation
|
||||
|
|
@ -16,4 +14,4 @@ class EmFieldType(GenericFieldType):
|
|||
def __init__(self, now_on_update=False, now_on_create=False, **kwargs):
|
||||
self.now_on_update = now_on_update
|
||||
self.now_on_create = now_on_create
|
||||
super(EmFieldType, self).__init__(ftype='datetime', **kwargs)
|
||||
super(EmFieldType, self).__init__(**kwargs)
|
||||
|
|
|
|||
|
|
@ -13,7 +13,7 @@ class EmFieldType(integer.EmFieldType):
|
|||
def __init__(self, is_id_class, **kwargs):
|
||||
self._is_id_class = is_id_class
|
||||
kwargs['internal'] = 'automatic'
|
||||
super(EmFieldType, self).__init__(is_id_class = is_id_class, **kwargs)
|
||||
super().__init__(is_id_class = is_id_class, **kwargs)
|
||||
|
||||
def _check_data_value(self, value):
|
||||
return (value, None)
|
||||
|
|
|
|||
|
|
@ -3,80 +3,44 @@
|
|||
import types
|
||||
import importlib
|
||||
|
||||
|
||||
## @brief Abstract class representing a fieldtype
|
||||
#
|
||||
# Important notes on datas checking :
|
||||
class GenericFieldType(object):
|
||||
|
||||
help_text = 'Generic field type : abstract class for every fieldtype'
|
||||
|
||||
## @brief Text describing the fieldtype
|
||||
help = 'Generic field type : abstract class for every fieldtype'
|
||||
## @brief Allowed type for handled datas
|
||||
_allowed_ftype = ['char', 'str', 'int', 'bool', 'datetime', 'text', 'rel2type', 'leobject']
|
||||
|
||||
## @brief The basic lowlevel value type
|
||||
ftype = None
|
||||
|
||||
## @brief Instanciate a new fieldtype
|
||||
# @param ftype str : The type of datas handled by this fieldtype
|
||||
# @param nullable bool : is None allowed as value ?
|
||||
# @param check_function function : A callback check function that takes 1 argument and raise a TypeError if the validation fails
|
||||
# @param uniq bool : Indicate if a field should handle uniq values
|
||||
# @param primary bool : If true the field is a primary key
|
||||
# @param **kwargs dict : Other arguments
|
||||
# @throw NotImplementedError if called directly
|
||||
# @throw AttributeError if bad ftype
|
||||
# @throw AttributeError if bad check_function
|
||||
def __init__(self, ftype, nullable=True, check_data_value=None, uniq=False, primary=False, **kwargs):
|
||||
## @param internal False | str : define wheter or not a field is internal
|
||||
# @throw NotImplementedError if called from bad class
|
||||
def __init__(self, internal = False, **args):
|
||||
if self.__class__ == GenericFieldType:
|
||||
raise NotImplementedError("Abstract class")
|
||||
|
||||
if self.ftype is None:
|
||||
raise RuntimeError("The class attribute ftype is not properly set by the %s EmFieldType" % self.name)
|
||||
|
||||
if ftype not in self._allowed_ftype:
|
||||
raise AttributeError("Ftype '%s' not known" % ftype)
|
||||
|
||||
if ftype != self.__class__.ftype:
|
||||
raise RuntimeError("The ftype is not the same for the instance and the class. Maybe %s reimplement ftype at class level but shouldn't" % self.name)
|
||||
|
||||
self.ftype = ftype
|
||||
self.nullable = bool(nullable)
|
||||
self.uniq = bool(uniq)
|
||||
|
||||
if 'default' in kwargs:
|
||||
self.default, error = self.check_data_value(kwargs['default'])
|
||||
if error:
|
||||
raise error
|
||||
del kwargs['default']
|
||||
|
||||
for argname, argvalue in kwargs.items():
|
||||
setattr(self, argname, argvalue)
|
||||
|
||||
## @return A fieldtype name from an instance
|
||||
self.internal = internal #Check this value ?
|
||||
|
||||
for argname, argval in args.items():
|
||||
setattr(self, argname, argval)
|
||||
|
||||
## Fieldtype name
|
||||
# @todo should be a staticmethod
|
||||
@property
|
||||
def name(self):
|
||||
return self.__module__.split('.')[-1]
|
||||
|
||||
## @return True if a field is internal, else returns False
|
||||
## @return True if a fieldtype is internal
|
||||
def is_internal(self):
|
||||
return hasattr(self, 'internal') and self.internal
|
||||
|
||||
## @brief Check if a Value is correct else return a check fail reason
|
||||
# @param value * : The value to check
|
||||
# @return (checked_and_casted_value, Exception|None)
|
||||
def check_data_value(self, value):
|
||||
if value is None:
|
||||
if not self.nullable:
|
||||
return (None, TypeError("'None' value but field is not nullable"))
|
||||
return (None, None)
|
||||
return self._check_data_value(value)
|
||||
return self.internal != False
|
||||
|
||||
## @brief Build automatic fields values
|
||||
## @brief Take care to call the fieldtype defined _check_data_value() method
|
||||
# @return a tuple (value, error|None)
|
||||
def check_data_value(self, value):
|
||||
return self._check_data_value(value)
|
||||
|
||||
def _check_data_value(self, value):
|
||||
return (value, None)
|
||||
|
||||
## @brief Build field value
|
||||
# @param lec LeCrud : A LeCrud child class
|
||||
# @param fname str : The field name
|
||||
# @param datas dict : dict storing fields values
|
||||
# @return constructed datas
|
||||
# @param fname str : The field name
|
||||
# @param datas dict : dict storing fields values (from the lec)
|
||||
# @return constructed datas (for the fname field)
|
||||
# @throw RuntimeError if unable to construct data
|
||||
def construct_data(self, lec, fname, datas):
|
||||
if fname in datas:
|
||||
return datas[fname]
|
||||
|
|
@ -85,7 +49,7 @@ class GenericFieldType(object):
|
|||
elif lec.fieldtypes()[fname].nullable:
|
||||
return None
|
||||
raise RuntimeError("Unable to construct data for field %s", fname)
|
||||
|
||||
|
||||
## @brief Check datas consistency
|
||||
# @param leo LeCrud : A LeCrud child class instance
|
||||
# @param fname str : The field name
|
||||
|
|
@ -94,12 +58,6 @@ class GenericFieldType(object):
|
|||
def check_data_consistency(self, lec, fname, datas):
|
||||
return True
|
||||
|
||||
## @brief Dummy check, designed to be implemented in child classes
|
||||
# @param value * : The value
|
||||
# @return (checked_and_casted_value, Exception|None)
|
||||
def _check_data_value(self, value):
|
||||
return (value, None)
|
||||
|
||||
## @brief Given a fieldtype name return the associated python class
|
||||
# @param fieldtype_name str : A fieldtype name
|
||||
# @return An GenericFieldType derivated class
|
||||
|
|
@ -122,18 +80,83 @@ class GenericFieldType(object):
|
|||
hash_dats.append((kdic, getattr(self, kdic)))
|
||||
return hash(tuple(hash_dats))
|
||||
|
||||
## @brief Transform a value into a valid python representation according to the fieldtype
|
||||
# @param value ? : The value to cast
|
||||
# @param kwargs dict : optionnal cast arguments
|
||||
# @return Something (depending on the fieldtype
|
||||
# @throw AttributeError if error in argument given to the method
|
||||
# @throw TypeError if the cast is not possible
|
||||
def cast(self, value, **kwargs):
|
||||
if len(kwargs) > 0:
|
||||
raise AttributeError("No optionnal argument allowed for %s cast method" % self.__class__.__name__)
|
||||
return value
|
||||
class SingleValueFieldType(GenericFieldType):
|
||||
|
||||
## @brief Instanciate a new fieldtype
|
||||
# @param nullable bool : is None allowed as value ?
|
||||
# @param uniqu bool : Indicate if a field should handle uniq value
|
||||
# @param primary bool : If True the field is a primary key
|
||||
# @param **args : Other arguments
|
||||
# @throw NotImplementedError if called from bad class
|
||||
def __init__(self, internal = False, nullable = True, uniq = False, primary = False, **args):
|
||||
if self.__class__ == SingleValueFieldType:
|
||||
raise NotImplementedError("Asbtract class")
|
||||
|
||||
super().__init__(internal, **args)
|
||||
|
||||
self.nullable = nullable
|
||||
self.uniq = uniq
|
||||
self.primary = primary
|
||||
if 'default' in args:
|
||||
self.default, error = self.check_data_value(args['default'])
|
||||
if error:
|
||||
raise error
|
||||
del(args['default'])
|
||||
|
||||
def check_data_value(self, value):
|
||||
if value is None:
|
||||
if not self.nullable:
|
||||
return (None, TypeError("'None' value but field is not nullable"))
|
||||
return (None, None)
|
||||
return super().check_data_value(value)
|
||||
|
||||
class ReferenceFieldType(SingleValueFieldType):
|
||||
|
||||
## @brief Instanciate a new fieldtype
|
||||
#
|
||||
#
|
||||
# @param reference str : A string that defines the reference (can be 'object' or 'relation')
|
||||
# @param nullable bool : is None allowed as value ?
|
||||
# @param unique bool : Indicate if a field should handle uniq value
|
||||
# @param primary bool : If True the field is a primary key
|
||||
# @param **args : Other arguments
|
||||
# @throw NotImplementedError if called from bad class
|
||||
def __init__(self, reference, internal=False, nullable = True, uniq = False, primary = False, **args):
|
||||
if reference.lower() not in ['relation', 'object']:
|
||||
raise ValueError("Bad value for reference : %s. Excepted on of 'relation', 'object'" % reference)
|
||||
self.reference = reference.lower()
|
||||
super().__init__(
|
||||
internal = internal,
|
||||
nullable = nullable,
|
||||
uniq = uniq,
|
||||
primary = primary,
|
||||
**args
|
||||
);
|
||||
pass
|
||||
|
||||
class MultiValueFieldType(GenericFieldType):
|
||||
|
||||
## @brief Instanciate a new multivalue fieldtype
|
||||
#
|
||||
# This fieldtype describe a field that handles multiple values referenced by a key (like a dict).
|
||||
# A typicall example is the i18n fieldtype
|
||||
# @param keyname str : The identifier key name
|
||||
# @param key_fieldtype SingleValueFieldType : A SingleValueFieldType child class instance
|
||||
# @param value_fieldtype SingleValueFieldType : A SingleValueFieldType child class instance
|
||||
def __init__(self, internal, keyname, key_fieldtype, value_fieldtype, **args):
|
||||
super().__init__(internal)
|
||||
## stores the keyname
|
||||
self.keyname = keyname
|
||||
## stores the fieldtype that handles the key
|
||||
self.key_fieldtype = key_fieldtype
|
||||
## stores the fieldtype that handles the values
|
||||
self.value_fieldtype = value_fieldtype
|
||||
|
||||
#
|
||||
#
|
||||
# Exceptions
|
||||
#
|
||||
#
|
||||
class FieldTypeError(Exception):
|
||||
pass
|
||||
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
#-*- coding: utf-8 -*-
|
||||
|
||||
from .generic import GenericFieldType
|
||||
from .generic import SingleValueFieldType
|
||||
|
||||
|
||||
class EmFieldType(GenericFieldType):
|
||||
class EmFieldType(SingleValueFieldType):
|
||||
|
||||
help = 'Basic integer field'
|
||||
|
||||
|
|
|
|||
|
|
@ -3,16 +3,17 @@
|
|||
import leapi.letype as letype
|
||||
import leapi.leclass as leclass
|
||||
|
||||
from .generic import GenericFieldType, FieldTypeError
|
||||
from .generic import ReferenceFieldType, FieldTypeError
|
||||
|
||||
class EmFieldType(GenericFieldType):
|
||||
class EmFieldType(ReferenceFieldType):
|
||||
|
||||
help = 'Fieldtypes designed to handle pk of LeObject in LeRelations'
|
||||
|
||||
ftype = 'leobject'
|
||||
|
||||
|
||||
## @todo Replace hardcoded string for reference initialisation
|
||||
def __init__(self, superior=True, **kwargs):
|
||||
super(EmFieldType, self).__init__(ftype = 'leobject', superior = superior, **kwargs)
|
||||
super().__init__(superior = superior, reference='object', **kwargs)
|
||||
|
||||
def _check_data_value(self, value):
|
||||
if not isinstance(value, int):
|
||||
|
|
|
|||
|
|
@ -10,10 +10,10 @@ class EmFieldType(EmFieldType):
|
|||
help = 'Stores a relation\'s nature'
|
||||
|
||||
def __init__(self, **kwargs):
|
||||
kwargs.update({'nullable': True, 'check_data_value': EmFieldType.check_data_value})
|
||||
super(EmFieldType, self).__init__(**kwargs)
|
||||
kwargs.update({'nullable': True})
|
||||
super().__init__(**kwargs)
|
||||
|
||||
def check_data_value(self, value):
|
||||
def _check_data_value(self, value):
|
||||
if value is None or ( value in classtypes.EmNature.getall()):
|
||||
return value, None
|
||||
else:
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ class EmFieldType(GenericFieldType):
|
|||
|
||||
def __init__(self, rel_to_type_id, **kwargs):
|
||||
self.rel_to_type_id = rel_to_type_id
|
||||
super(EmFieldType, self).__init__(ftype='rel2type', **kwargs)
|
||||
super(EmFieldType, self).__init__(**kwargs)
|
||||
|
||||
def get_related_type(self):
|
||||
return self.model.component(self.rel_to_type_id)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue