diff options
Diffstat (limited to 'archaeological_context_records/models.py')
-rw-r--r-- | archaeological_context_records/models.py | 114 |
1 files changed, 113 insertions, 1 deletions
diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index d62dde4be..96ba16935 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -35,6 +35,7 @@ from ishtar_common.utils import ( cached_label_changed, m2m_historization_changed, post_save_geo, + task ) from ishtar_common.models import ( @@ -61,6 +62,7 @@ from ishtar_common.models import ( DocumentItem, MainItem, QuickAction, + RelationsViews ) from ishtar_common.models_common import HistoricalRecords from archaeological_operations.models import ( @@ -1282,7 +1284,7 @@ class RecordRelationView(models.Model): return '{} "{}"'.format(self.relation_type, self.right_record) -class ContextRecordTree(models.Model): +class ContextRecordTree(RelationsViews): CREATE_SQL = """ CREATE VIEW cr_parent_relation_id AS SELECT id @@ -1354,6 +1356,19 @@ class ContextRecordTree(models.Model): DROP VIEW IF EXISTS context_records_tree; DROP VIEW IF EXISTS cr_parent_relation_id; """ + + CREATE_TABLE_SQL = """ + CREATE TABLE {table} ( + key varchar(100) PRIMARY KEY, + cr_id integer NOT NULL, + cr_parent_id integer NOT NULL, + CONSTRAINT fk1_{table} FOREIGN KEY(cr_id) + REFERENCES {fk_table}(id), + CONSTRAINT fk2_{table} FOREIGN KEY(cr_parent_id) + REFERENCES {fk_table}(id) + );""".format(table="context_records_tree", + fk_table="archaeological_context_records_contextrecord") + key = models.TextField(primary_key=True) cr = models.ForeignKey( "archaeological_context_records.ContextRecord", @@ -1369,3 +1384,100 @@ class ContextRecordTree(models.Model): class Meta: managed = False db_table = "context_records_tree" + + @classmethod + def _save_tree(cls, tree): + keys = [] + print("tree", tree) + for idx, parent_id in enumerate(tree[:-1]): + for child_id in tree[idx:]: + if child_id != parent_id: + cls.objects.get_or_create( + key=f"{child_id}_{parent_id}", + cr_id=child_id, cr_parent_id=parent_id + ) + keys.append((child_id, parent_id)) + return keys + + @classmethod + def _update_child(cls, parent_id, tree, rel_types): + whole_tree = set() + childs = RecordRelations.objects.values_list( + "left_record_id", flat=True).filter( + right_record_id=parent_id, relation_type_id__in=rel_types) + for c in childs[:]: + if c in tree: # cyclic + childs.pop(c) + #print("childs", parent_id, childs) + if not childs: # last leaf in the tree + return cls._save_tree(tree) + for c in childs: + whole_tree.update(cls._update_child(c, tree[:] + [c], rel_types)) + return whole_tree + + @classmethod + def _get_parent_trees(cls, child_id, trees, rel_types): + parents = RecordRelations.objects.values_list( + "right_record_id", flat=True).filter( + left_record_id=child_id, relation_type_id__in=rel_types) + if not parents: + return trees + new_trees = [] + for p in parents: + if p == child_id or any(1 for tree in trees if p in tree): # cyclic + continue + c_trees = list(map(lambda x: x + [p], trees)) + new_trees += cls._get_parent_trees(p, c_trees, rel_types) + return new_trees + + @classmethod + def _update(cls, item_id, cascade=True): + # update the whole tree + rel_types = RelationType.objects.filter( + logical_relation__in=('included', 'equal')).values_list("id", flat=True) + + # get first parents + parent_ids = [ + tree[-1] for tree in cls._get_parent_trees(item_id, [[item_id]], rel_types)] + """ + parent_ids = [] + current_ids = [item_id] + while current_ids: + new_ids = [] + for current_id in current_ids: + parents = RecordRelations.objects.values_list( + "right_record_id", flat=True).filter( + left_record_id=current_id, relation_type_id__in=rel_types) + if not parents: + continue + for p in parents[:]: + if p == current_id or p in parent_ids: # cyclic + parents.pop(p) + parent_ids += parents + new_ids += parents + current_ids = new_ids + """ + def get_cr(idx): + return ContextRecord.objects.get(pk=idx) + print(get_cr(item_id)) + if not parent_ids: + parent_ids = [item_id] + print("parents", [get_cr(p) for p in parent_ids]) + + # get all child for parents and save trees + all_relations = set() + for parent_id in parent_ids: + tree = [parent_id] + all_relations.update(cls._update_child(parent_id, tree, rel_types)) + #print(all_relations) + + # delete old relations + for item_id in set([c for c, __ in all_relations] + + [p for p, __ in all_relations]): + for rel in cls.objects.filter(cr_id=item_id).all(): + if (rel.cr_id, rel.cr_parent_id) not in all_relations: + rel.delete() + for rel in cls.objects.filter(cr_parent_id=item_id).all(): + if (rel.cr_id, rel.cr_parent_id) not in all_relations: + rel.delete() + |