mirror of
https://github.com/yweber/lodel2.git
synced 2025-11-02 04:20:55 +01:00
Automatic update of Back-references
This commit is contained in:
parent
61e0567abf
commit
57688e7afb
5 changed files with 164 additions and 89 deletions
|
|
@ -121,7 +121,16 @@ class DataHandler(object):
|
|||
# @todo A implémenter
|
||||
def check_data_consistency(self, emcomponent, fname, datas):
|
||||
return True
|
||||
|
||||
|
||||
##@brief make consistency after a query
|
||||
# @param emcomponent EmComponent : An EmComponent child class instance
|
||||
# @param fname : the field name
|
||||
# @param datas dict : dict storing fields values
|
||||
# @return an Exception instance if fails else True
|
||||
# @todo A implémenter
|
||||
def make_consistency(self, emcomponent, fname, datas):
|
||||
pass
|
||||
|
||||
##@brief This method is use by plugins to register new data handlers
|
||||
@classmethod
|
||||
def register_new_handler(cls, name, data_handler):
|
||||
|
|
@ -201,6 +210,7 @@ class Reference(DataHandler):
|
|||
#if not issubclass(lodel.leapi.leobject.LeObject, back_reference[0]) or not isinstance(back_reference[1], str):
|
||||
# raise TypeError("Back reference was expected to be a tuple(<class LeObject>, str) but got : (%s, %s)" % (back_reference[0], back_reference[1]))
|
||||
self.__back_reference = back_reference
|
||||
self.back_ref = back_reference
|
||||
|
||||
super().__init__(internal=internal, **kwargs)
|
||||
|
||||
|
|
@ -232,6 +242,31 @@ class Reference(DataHandler):
|
|||
return None, FieldValidationError("Some element of this references are not valids (don't fit with allowed_classes")
|
||||
return value
|
||||
|
||||
##@brief Check datas consistency
|
||||
# @param emcomponent EmComponent : An EmComponent child class instance
|
||||
# @param fname : the field name
|
||||
# @param datas dict : dict storing fields values
|
||||
# @return an Exception instance if fails else True
|
||||
# @todo A implémenter
|
||||
def check_data_consistency(self, emcomponent, fname, datas):
|
||||
dh = emcomponent.field(fname)
|
||||
logger.debug(dh)
|
||||
logger.info('Warning : multiple uid capabilities are broken here')
|
||||
uid = datas[emcomponent.uid_fieldname()[0]]
|
||||
target_class = self.back_ref[0]
|
||||
target_field = self.back_ref[1]
|
||||
target_uidfield = traget_class.uid_fieldname()[0]
|
||||
value = datas[emcomponent.data(fname)]
|
||||
|
||||
obj = target_class.get((target_uidfield , '=', value))
|
||||
|
||||
if len(obj) == 0:
|
||||
logger.warning('Object referenced does not exist')
|
||||
return False
|
||||
|
||||
obj.set_data(target_field, uid)
|
||||
obj.update()
|
||||
return True
|
||||
|
||||
##@brief This class represent a data_handler for single reference to another object
|
||||
#
|
||||
|
|
@ -277,6 +312,73 @@ class MultipleRef(Reference):
|
|||
def check_data_consistency(self, emcomponent, fname, datas):
|
||||
return True
|
||||
|
||||
def construct_data(self, emcomponent, fname, datas, cur_value):
|
||||
if cur_value == 'None' or cur_value is None or cur_value == '':
|
||||
return None
|
||||
emcomponent_fields = emcomponent.fields()
|
||||
data_handler = None
|
||||
if fname in emcomponent_fields:
|
||||
data_handler = emcomponent_fields[fname]
|
||||
u_fname = emcomponent.uid_fieldname()
|
||||
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
|
||||
|
||||
if isinstance(cur_value, str):
|
||||
value = cur_value.split(',')
|
||||
l_value = [uidtype.cast_type(uid) for uid in value]
|
||||
elif isinstance(cur_value, list):
|
||||
l_value = list()
|
||||
for value in cur_value:
|
||||
if isinstance(value,uidtype.cast_type):
|
||||
l_value.append(value)
|
||||
else:
|
||||
raise ValueError("The items must be of the same type, string or %s" % (emcomponent.__name__))
|
||||
else:
|
||||
l_value = None
|
||||
|
||||
if l_value is not None:
|
||||
if self.back_ref is not None:
|
||||
br_class = self.back_ref[0]
|
||||
for br_id in l_value:
|
||||
query_filters = list()
|
||||
query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
|
||||
br_obj = br_class.get(query_filters)
|
||||
if len(br_obj) != 0:
|
||||
br_list = br_obj[0].data(self.back_ref[1])
|
||||
if br_list is None:
|
||||
br_list = list()
|
||||
if br_id not in br_list:
|
||||
br_list.append(br_id)
|
||||
logger.info('The referenced object has to be updated')
|
||||
return l_value
|
||||
|
||||
def make_consistency(self, emcomponent, fname, datas):
|
||||
dh = emcomponent.field(fname)
|
||||
|
||||
logger.info('Warning : multiple uid capabilities are broken here')
|
||||
uid = datas[emcomponent.uid_fieldname()[0]]
|
||||
if self.back_ref is not None:
|
||||
target_class = self.back_ref[0]
|
||||
target_field = self.back_ref[1]
|
||||
target_uidfield = target_class.uid_fieldname()[0]
|
||||
|
||||
l_value = datas[fname]
|
||||
|
||||
if l_value is not None:
|
||||
for value in l_value:
|
||||
query_filters = list()
|
||||
query_filters.append((target_uidfield , '=', value))
|
||||
obj = target_class.get(query_filters)
|
||||
if len(obj) == 0:
|
||||
logger.warning('Object referenced does not exist')
|
||||
return False
|
||||
l_uids_ref = obj[0].data(target_field)
|
||||
if l_uids_ref is None:
|
||||
l_uids_ref = list()
|
||||
if uid not in l_uids_ref:
|
||||
l_uids_ref.append(uid)
|
||||
obj[0].set_data(target_field, l_uids_ref)
|
||||
obj[0].update()
|
||||
|
||||
## @brief Class designed to handle datas access will fieldtypes are constructing datas
|
||||
#
|
||||
# This class is designed to allow automatic scheduling of construct_data calls.
|
||||
|
|
|
|||
|
|
@ -31,43 +31,7 @@ class List(MultipleRef):
|
|||
return val, expt
|
||||
|
||||
def construct_data(self, emcomponent, fname, datas, cur_value):
|
||||
if cur_value == 'None' or cur_value is None or cur_value == '':
|
||||
return None
|
||||
emcomponent_fields = emcomponent.fields()
|
||||
data_handler = None
|
||||
if fname in emcomponent_fields:
|
||||
data_handler = emcomponent_fields[fname]
|
||||
u_fname = emcomponent.uid_fieldname()
|
||||
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
|
||||
|
||||
if isinstance(cur_value, str):
|
||||
value = cur_value.split(',')
|
||||
l_value = [uidtype.cast_type(uid) for uid in value]
|
||||
elif isinstance(cur_value, list):
|
||||
l_value = list()
|
||||
for value in cur_value:
|
||||
if isinstance(value,uidtype):
|
||||
l_value.append(value)
|
||||
else:
|
||||
raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
|
||||
else:
|
||||
l_value = None
|
||||
|
||||
if l_value is not None:
|
||||
br_class = self.back_reference()[0]
|
||||
for br_id in l_value:
|
||||
query_filters = list()
|
||||
query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
|
||||
br_obj = br_class.get(query_filters)
|
||||
# if br_obj.__class__ not in
|
||||
if len(br_obj) == 0:
|
||||
raise ValueError("Not existing instance of class %s in back_reference" % br_class.__name__)
|
||||
br_list = br_obj.data(self.back_reference()[1])
|
||||
if br_id not in br_list:
|
||||
br_list.append(br_id)
|
||||
br_obj.set_data(self.back_reference()[1], br_list)
|
||||
br_obj.update()
|
||||
return l_value
|
||||
return super().construct_data(emcomponent, fname, datas, cur_value)
|
||||
|
||||
##@brief Child class of MultipleRef where references are represented in the form of a python set
|
||||
class Set(MultipleRef):
|
||||
|
|
@ -90,34 +54,8 @@ class Set(MultipleRef):
|
|||
return val, expt
|
||||
|
||||
def construct_data(self, emcomponent, fname, datas, cur_value):
|
||||
if cur_value == 'None' or cur_value is None or cur_value == '':
|
||||
return None
|
||||
emcomponent_fields = emcomponent.fields()
|
||||
data_handler = None
|
||||
if fname in emcomponent_fields:
|
||||
data_handler = emcomponent_fields[fname]
|
||||
u_fname = emcomponent.uid_fieldname()
|
||||
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
|
||||
if isinstance(cur_value, str):
|
||||
value = cur_value.split(',')
|
||||
l_value = [uidtype.cast_type(uid) for uid in value]
|
||||
logger.debug("Valeur avec uidtype : %d" % l_value)
|
||||
#l_value = [int(uid) for uid in value]
|
||||
return list(l_value)
|
||||
elif isinstance(cur_value, set):
|
||||
l_value = list()
|
||||
|
||||
for value in cur_value:
|
||||
if isinstance(value,uidtype):
|
||||
l_value.append(value)
|
||||
else:
|
||||
raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
|
||||
return l_value
|
||||
logger.debug(l_value)
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
return super().construct_data(emcomponent, fname, datas, cur_value)
|
||||
|
||||
##@brief Child class of MultipleRef where references are represented in the form of a python dict
|
||||
class Map(MultipleRef):
|
||||
|
||||
|
|
@ -139,6 +77,45 @@ class Map(MultipleRef):
|
|||
None if isinstance(expt, Exception) else value,
|
||||
expt)
|
||||
|
||||
def construct_data(self, emcomponent, fname, datas, cur_value):
|
||||
logger.info('WARNING : not well implemented...list are stored...not dict')
|
||||
if cur_value == 'None' or cur_value is None or cur_value == '':
|
||||
return None
|
||||
emcomponent_fields = emcomponent.fields()
|
||||
data_handler = None
|
||||
if fname in emcomponent_fields:
|
||||
data_handler = emcomponent_fields[fname]
|
||||
u_fname = emcomponent.uid_fieldname()
|
||||
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
|
||||
|
||||
if isinstance(cur_value, str):
|
||||
value = cur_value.split(',')
|
||||
l_value = [uidtype.cast_type(uid) for uid in value]
|
||||
elif isinstance(cur_value, list):
|
||||
l_value = list()
|
||||
for value in cur_value:
|
||||
if isinstance(value,uidtype.cast_type):
|
||||
l_value.append(value)
|
||||
else:
|
||||
raise ValueError("The items must be of the same type, string or %s" % (emcomponent.__name__))
|
||||
else:
|
||||
l_value = None
|
||||
|
||||
if l_value is not None:
|
||||
if self.back_ref is not None:
|
||||
br_class = self.back_ref[0]
|
||||
for br_id in l_value:
|
||||
query_filters = list()
|
||||
query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
|
||||
br_obj = br_class.get(query_filters)
|
||||
if len(br_obj) != 0:
|
||||
br_list = br_obj[0].data(self.back_ref[1])
|
||||
if br_list is None:
|
||||
br_list = list()
|
||||
if br_id not in br_list:
|
||||
br_list.append(br_id)
|
||||
logger.info('The referenced object has to be updated')
|
||||
return l_value
|
||||
##@brief This Reference class is designed to handler hierarchy with some constraint
|
||||
class Hierarch(MultipleRef):
|
||||
|
||||
|
|
@ -161,25 +138,4 @@ class Hierarch(MultipleRef):
|
|||
return val, expt
|
||||
|
||||
def construct_data(self, emcomponent, fname, datas, cur_value):
|
||||
if cur_value == 'None' or cur_value is None or cur_value == '':
|
||||
return None
|
||||
emcomponent_fields = emcomponent.fields()
|
||||
data_handler = None
|
||||
if fname in emcomponent_fields:
|
||||
data_handler = emcomponent_fields[fname]
|
||||
u_fname = emcomponent.uid_fieldname()
|
||||
uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
|
||||
if isinstance(cur_value, str):
|
||||
value = cur_value.split(',')
|
||||
l_value = [uidtype.cast_type(uid) for uid in value]
|
||||
return list(l_value)
|
||||
elif isinstance(cur_value, list):
|
||||
l_value = list()
|
||||
for value in cur_value:
|
||||
if isinstance(value,uidtype):
|
||||
l_value.append(value)
|
||||
else:
|
||||
raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
|
||||
return l_value
|
||||
else:
|
||||
return None
|
||||
return super().construct_data(emcomponent, fname, datas, cur_value)
|
||||
|
|
@ -471,7 +471,7 @@ construction and consitency when datas are not complete\n")
|
|||
if not ftype.is_internal() or ftype.internal != 'autosql'
|
||||
}
|
||||
return ret
|
||||
|
||||
|
||||
## @brief Check datas consistency
|
||||
#
|
||||
# @warning assert that datas is complete
|
||||
|
|
@ -490,6 +490,11 @@ construction and consitency when datas are not complete\n")
|
|||
if len(err_l) > 0:
|
||||
raise LeApiDataCheckError("Datas consistency checks fails", err_l)
|
||||
|
||||
@classmethod
|
||||
def make_consistency(cls, datas):
|
||||
for fname, dh in cls._fields.items():
|
||||
ret = dh.make_consistency(cls, fname, datas)
|
||||
|
||||
## @brief Add a new instance of LeObject
|
||||
# @return a new uid en case of success, False otherwise
|
||||
@classmethod
|
||||
|
|
|
|||
|
|
@ -475,6 +475,8 @@ class LeInsertQuery(LeQuery):
|
|||
def _query(self, datas):
|
||||
datas = self._target_class.prepare_datas(datas, True, False)
|
||||
id_inserted = self._rw_datasource.insert(self._target_class,datas)
|
||||
# To put in a hook ??
|
||||
self._target_class.make_consistency(datas=res_datas)
|
||||
return id_inserted
|
||||
"""
|
||||
## @brief Implements an insert query operation, with multiple insertions
|
||||
|
|
@ -565,6 +567,8 @@ target to LeUpdateQuery constructor"
|
|||
res = self._rw_datasource.update(
|
||||
self._target_class, filters, [],
|
||||
res_datas)
|
||||
# To put in a hook ??
|
||||
self._target_class.make_consistency(datas=res_datas)
|
||||
return res
|
||||
|
||||
## @brief Execute the update query
|
||||
|
|
|
|||
|
|
@ -3,6 +3,10 @@
|
|||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>{% block title %}{% endblock %}</title>
|
||||
|
||||
<!-- Bootstrap -->
|
||||
<link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
|
||||
|
||||
{% block style %}{% endblock %}
|
||||
{% block scripts %}{% endblock %}
|
||||
</head>
|
||||
|
|
@ -11,5 +15,9 @@
|
|||
{% block content %}{% endblock %}
|
||||
</div>
|
||||
<script type="text/javascript">{% block javascript %}{% endblock %}</script>
|
||||
<!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
|
||||
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
|
||||
<!-- Include all compiled plugins (below), or include individual files as needed -->
|
||||
<script src="bootstrap/js/bootstrap.min.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue