Browse Source

Automatic update of Back-references

prieto 7 years ago
parent
commit
57688e7afb

+ 103
- 1
lodel/leapi/datahandlers/base_classes.py View File

@@ -121,7 +121,16 @@ class DataHandler(object):
121 121
     # @todo A implémenter
122 122
     def check_data_consistency(self, emcomponent, fname, datas):
123 123
         return True
124
-
124
+ 
125
+    ##@brief make consistency after a query
126
+    # @param emcomponent EmComponent : An EmComponent child class instance
127
+    # @param fname : the field name
128
+    # @param datas dict : dict storing fields values
129
+    # @return an Exception instance if fails else True
130
+    # @todo A implémenter   
131
+    def make_consistency(self, emcomponent, fname, datas):
132
+        pass
133
+    
125 134
     ##@brief This method is use by plugins to register new data handlers
126 135
     @classmethod
127 136
     def register_new_handler(cls, name, data_handler):
@@ -201,6 +210,7 @@ class Reference(DataHandler):
201 210
             #if not issubclass(lodel.leapi.leobject.LeObject, back_reference[0]) or not isinstance(back_reference[1], str):
202 211
             #    raise TypeError("Back reference was expected to be a tuple(<class LeObject>, str) but got : (%s, %s)" % (back_reference[0], back_reference[1]))
203 212
         self.__back_reference = back_reference
213
+        self.back_ref = back_reference
204 214
 
205 215
         super().__init__(internal=internal, **kwargs)
206 216
     
@@ -232,6 +242,31 @@ class Reference(DataHandler):
232 242
                     return None, FieldValidationError("Some element of this references are not valids (don't fit with allowed_classes")
233 243
         return value
234 244
 
245
+    ##@brief Check datas consistency
246
+    # @param emcomponent EmComponent : An EmComponent child class instance
247
+    # @param fname : the field name
248
+    # @param datas dict : dict storing fields values
249
+    # @return an Exception instance if fails else True
250
+    # @todo A implémenter
251
+    def check_data_consistency(self, emcomponent, fname, datas):
252
+        dh = emcomponent.field(fname)
253
+        logger.debug(dh)
254
+        logger.info('Warning : multiple uid capabilities are broken here')
255
+        uid = datas[emcomponent.uid_fieldname()[0]]
256
+        target_class = self.back_ref[0]
257
+        target_field = self.back_ref[1]
258
+        target_uidfield = traget_class.uid_fieldname()[0]
259
+        value = datas[emcomponent.data(fname)]
260
+        
261
+        obj = target_class.get((target_uidfield , '=', value))
262
+        
263
+        if len(obj) == 0:
264
+            logger.warning('Object referenced does not exist')
265
+            return False
266
+        
267
+        obj.set_data(target_field, uid)
268
+        obj.update()
269
+        return True
235 270
 
236 271
 ##@brief This class represent a data_handler for single reference to another object
237 272
 #
@@ -277,6 +312,73 @@ class MultipleRef(Reference):
277 312
     def check_data_consistency(self, emcomponent, fname, datas):
278 313
         return True
279 314
     
315
+    def construct_data(self, emcomponent, fname, datas, cur_value):
316
+        if cur_value == 'None' or cur_value is None or cur_value == '':
317
+            return None
318
+        emcomponent_fields = emcomponent.fields()
319
+        data_handler = None
320
+        if fname in emcomponent_fields:
321
+            data_handler = emcomponent_fields[fname]
322
+        u_fname = emcomponent.uid_fieldname()
323
+        uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
324
+
325
+        if isinstance(cur_value, str):
326
+            value = cur_value.split(',')
327
+            l_value = [uidtype.cast_type(uid) for uid in value]
328
+        elif isinstance(cur_value, list):
329
+            l_value = list()
330
+            for value in cur_value:
331
+                if isinstance(value,uidtype.cast_type):
332
+                    l_value.append(value)
333
+                else:
334
+                    raise ValueError("The items must be of the same type, string or %s" % (emcomponent.__name__))
335
+        else:
336
+            l_value = None
337
+
338
+        if l_value is not None:
339
+            if self.back_ref is not None:
340
+                br_class = self.back_ref[0]
341
+                for br_id in l_value:
342
+                    query_filters = list()
343
+                    query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
344
+                    br_obj = br_class.get(query_filters)
345
+                    if len(br_obj) != 0:
346
+                        br_list = br_obj[0].data(self.back_ref[1])
347
+                        if br_list is None:
348
+                            br_list = list()
349
+                        if br_id not in br_list:
350
+                            br_list.append(br_id)
351
+                            logger.info('The referenced object has to be updated')
352
+        return l_value
353
+    
354
+    def make_consistency(self, emcomponent, fname, datas):
355
+        dh = emcomponent.field(fname)
356
+
357
+        logger.info('Warning : multiple uid capabilities are broken here')
358
+        uid = datas[emcomponent.uid_fieldname()[0]]
359
+        if self.back_ref is not None:
360
+            target_class = self.back_ref[0]
361
+            target_field = self.back_ref[1]
362
+            target_uidfield = target_class.uid_fieldname()[0]
363
+
364
+            l_value = datas[fname]
365
+
366
+            if l_value is not None:
367
+                for value in l_value:
368
+                    query_filters = list()
369
+                    query_filters.append((target_uidfield , '=', value))
370
+                    obj = target_class.get(query_filters)
371
+                    if len(obj) == 0:
372
+                        logger.warning('Object referenced does not exist')
373
+                        return False
374
+                    l_uids_ref = obj[0].data(target_field)
375
+                    if l_uids_ref is None:
376
+                        l_uids_ref = list()
377
+                    if uid not in l_uids_ref:
378
+                        l_uids_ref.append(uid)
379
+                        obj[0].set_data(target_field, l_uids_ref)
380
+                        obj[0].update()
381
+                
280 382
 ## @brief Class designed to handle datas access will fieldtypes are constructing datas
281 383
 #
282 384
 # This class is designed to allow automatic scheduling of construct_data calls. 

+ 43
- 87
lodel/leapi/datahandlers/references.py View File

@@ -31,43 +31,7 @@ class List(MultipleRef):
31 31
         return val, expt
32 32
 
33 33
     def construct_data(self, emcomponent, fname, datas, cur_value):
34
-        if cur_value == 'None' or cur_value is None or cur_value == '':
35
-            return None
36
-        emcomponent_fields = emcomponent.fields()
37
-        data_handler = None
38
-        if fname in emcomponent_fields:
39
-            data_handler = emcomponent_fields[fname]
40
-        u_fname = emcomponent.uid_fieldname()
41
-        uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
42
-
43
-        if isinstance(cur_value, str):
44
-            value = cur_value.split(',')
45
-            l_value = [uidtype.cast_type(uid) for uid in value]
46
-        elif isinstance(cur_value, list):
47
-            l_value = list()
48
-            for value in cur_value:
49
-                if isinstance(value,uidtype):
50
-                    l_value.append(value)
51
-                else:
52
-                    raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
53
-        else:
54
-            l_value = None
55
-           
56
-        if l_value is not None:
57
-            br_class = self.back_reference()[0]
58
-            for br_id in l_value:
59
-                query_filters = list()
60
-                query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
61
-                br_obj = br_class.get(query_filters)
62
-                # if br_obj.__class__ not in 
63
-                if len(br_obj) == 0:
64
-                    raise ValueError("Not existing instance of class %s in back_reference" % br_class.__name__)
65
-                br_list = br_obj.data(self.back_reference()[1])
66
-                if br_id not in br_list:
67
-                    br_list.append(br_id)
68
-                    br_obj.set_data(self.back_reference()[1], br_list)
69
-                    br_obj.update()
70
-        return l_value
34
+        return super().construct_data(emcomponent, fname, datas, cur_value)
71 35
 
72 36
 ##@brief Child class of MultipleRef where references are represented in the form of a python set
73 37
 class Set(MultipleRef):
@@ -90,34 +54,8 @@ class Set(MultipleRef):
90 54
         return val, expt
91 55
     
92 56
     def construct_data(self, emcomponent, fname, datas, cur_value):
93
-        if cur_value == 'None' or cur_value is None or cur_value == '':
94
-            return None
95
-        emcomponent_fields = emcomponent.fields()
96
-        data_handler = None
97
-        if fname in emcomponent_fields:
98
-            data_handler = emcomponent_fields[fname]
99
-        u_fname = emcomponent.uid_fieldname()
100
-        uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
101
-        if isinstance(cur_value, str):
102
-            value = cur_value.split(',')
103
-            l_value = [uidtype.cast_type(uid) for uid in value] 
104
-            logger.debug("Valeur avec uidtype : %d" % l_value) 
105
-            #l_value = [int(uid) for uid in value] 
106
-            return list(l_value)
107
-        elif isinstance(cur_value, set):
108
-            l_value = list()
109
-            
110
-            for value in cur_value:
111
-                if isinstance(value,uidtype):
112
-                    l_value.append(value)
113
-                else:
114
-                    raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
115
-            return l_value
116
-            logger.debug(l_value)
117
-        else:
118
-            return None
119
-
120
-
57
+        return super().construct_data(emcomponent, fname, datas, cur_value)
58
+    
121 59
 ##@brief Child class of MultipleRef where references are represented in the form of a python dict
122 60
 class Map(MultipleRef):
123 61
 
@@ -139,6 +77,45 @@ class Map(MultipleRef):
139 77
                 None if isinstance(expt, Exception) else value,
140 78
                 expt)
141 79
 
80
+    def construct_data(self, emcomponent, fname, datas, cur_value):
81
+        logger.info('WARNING : not well implemented...list are stored...not dict')
82
+        if cur_value == 'None' or cur_value is None or cur_value == '':
83
+            return None
84
+        emcomponent_fields = emcomponent.fields()
85
+        data_handler = None
86
+        if fname in emcomponent_fields:
87
+            data_handler = emcomponent_fields[fname]
88
+        u_fname = emcomponent.uid_fieldname()
89
+        uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
90
+
91
+        if isinstance(cur_value, str):
92
+            value = cur_value.split(',')
93
+            l_value = [uidtype.cast_type(uid) for uid in value]
94
+        elif isinstance(cur_value, list):
95
+            l_value = list()
96
+            for value in cur_value:
97
+                if isinstance(value,uidtype.cast_type):
98
+                    l_value.append(value)
99
+                else:
100
+                    raise ValueError("The items must be of the same type, string or %s" % (emcomponent.__name__))
101
+        else:
102
+            l_value = None
103
+
104
+        if l_value is not None:
105
+            if self.back_ref is not None:
106
+                br_class = self.back_ref[0]
107
+                for br_id in l_value:
108
+                    query_filters = list()
109
+                    query_filters.append((br_class.uid_fieldname()[0], '=', br_id))
110
+                    br_obj = br_class.get(query_filters)
111
+                    if len(br_obj) != 0:
112
+                        br_list = br_obj[0].data(self.back_ref[1])
113
+                        if br_list is None:
114
+                            br_list = list()
115
+                        if br_id not in br_list:
116
+                            br_list.append(br_id)
117
+                            logger.info('The referenced object has to be updated')
118
+        return l_value
142 119
 ##@brief This Reference class is designed to handler hierarchy with some constraint
143 120
 class Hierarch(MultipleRef):
144 121
     
@@ -161,25 +138,4 @@ class Hierarch(MultipleRef):
161 138
         return val, expt
162 139
     
163 140
     def construct_data(self, emcomponent, fname, datas, cur_value):
164
-        if cur_value == 'None' or cur_value is None or cur_value == '':
165
-            return None
166
-        emcomponent_fields = emcomponent.fields()
167
-        data_handler = None
168
-        if fname in emcomponent_fields:
169
-            data_handler = emcomponent_fields[fname]
170
-        u_fname = emcomponent.uid_fieldname()
171
-        uidtype = emcomponent.field(u_fname[0]) if isinstance(u_fname, list) else emcomponent.field(u_fname)
172
-        if isinstance(cur_value, str):
173
-            value = cur_value.split(',')
174
-            l_value = [uidtype.cast_type(uid) for uid in value] 
175
-            return list(l_value)
176
-        elif isinstance(cur_value, list):
177
-            l_value = list()
178
-            for value in cur_value:
179
-                if isinstance(value,uidtype):
180
-                    l_value.append(value)
181
-                else:
182
-                    raise ValueError("The items must be of the same type, string or %s" % (ecomponent.__name__))
183
-            return l_value
184
-        else:
185
-            return None
141
+        return super().construct_data(emcomponent, fname, datas, cur_value)

+ 6
- 1
lodel/leapi/leobject.py View File

@@ -471,7 +471,7 @@ construction and consitency when datas are not complete\n")
471 471
                 if not ftype.is_internal() or ftype.internal != 'autosql'
472 472
         }
473 473
         return ret
474
-
474
+    
475 475
     ## @brief Check datas consistency
476 476
477 477
     # @warning assert that datas is complete
@@ -490,6 +490,11 @@ construction and consitency when datas are not complete\n")
490 490
         if len(err_l) > 0:
491 491
             raise LeApiDataCheckError("Datas consistency checks fails", err_l)
492 492
     
493
+    @classmethod
494
+    def make_consistency(cls, datas):
495
+        for fname, dh in cls._fields.items():
496
+            ret = dh.make_consistency(cls, fname, datas)
497
+            
493 498
     ## @brief Add a new instance of LeObject
494 499
     # @return a new uid en case of success, False otherwise
495 500
     @classmethod

+ 4
- 0
lodel/leapi/query.py View File

@@ -475,6 +475,8 @@ class LeInsertQuery(LeQuery):
475 475
     def _query(self, datas):
476 476
         datas = self._target_class.prepare_datas(datas, True, False)
477 477
         id_inserted = self._rw_datasource.insert(self._target_class,datas)
478
+        # To put in a hook ??
479
+        self._target_class.make_consistency(datas=res_datas)
478 480
         return id_inserted
479 481
     """
480 482
     ## @brief Implements an insert query operation, with multiple insertions
@@ -565,6 +567,8 @@ target to LeUpdateQuery constructor"
565 567
                 res = self._rw_datasource.update(
566 568
                     self._target_class, filters, [],
567 569
                     res_datas)
570
+        # To put in a hook ??
571
+        self._target_class.make_consistency(datas=res_datas)
568 572
         return res
569 573
     
570 574
     ## @brief Execute the update query

+ 8
- 0
plugins/webui/templates/base.html View File

@@ -3,6 +3,10 @@
3 3
 <head>
4 4
     <meta charset="UTF-8" />
5 5
     <title>{% block title %}{% endblock %}</title>
6
+    
7
+    <!-- Bootstrap -->
8
+    <link href="bootstrap/css/bootstrap.min.css" rel="stylesheet">
9
+    
6 10
     {% block style %}{% endblock %}
7 11
     {% block scripts %}{% endblock %}
8 12
 </head>
@@ -11,5 +15,9 @@
11 15
         {% block content %}{% endblock %}
12 16
     </div>
13 17
     <script type="text/javascript">{% block javascript %}{% endblock %}</script>
18
+    <!-- jQuery (necessary for Bootstrap's JavaScript plugins) -->
19
+    <script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
20
+    <!-- Include all compiled plugins (below), or include individual files as needed -->
21
+    <script src="bootstrap/js/bootstrap.min.js"></script>
14 22
 </body>
15 23
 </html>

Loading…
Cancel
Save