summaryrefslogtreecommitdiff
path: root/ishtar_common
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2022-10-06 16:00:40 +0200
committerÉtienne Loks <etienne.loks@iggdrasil.net>2022-12-12 12:23:18 +0100
commit43010940511b29eeba2be1f985d3b97b1ac7e62d (patch)
tree488d49c8ec2cd6443a42fb70c0073ab56883d3d5 /ishtar_common
parent4b22b3a77938aaec4c21c921c90e922fe526c43c (diff)
downloadIshtar-43010940511b29eeba2be1f985d3b97b1ac7e62d.tar.bz2
Ishtar-43010940511b29eeba2be1f985d3b97b1ac7e62d.zip
Geodata: manage cascade remove and geodata clear
Diffstat (limited to 'ishtar_common')
-rw-r--r--ishtar_common/models_common.py73
-rw-r--r--ishtar_common/tests.py77
2 files changed, 135 insertions, 15 deletions
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index d32f835bd..adf1c1516 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -2581,18 +2581,13 @@ class GeoVectorData(Imported, OwnPerms):
post_save.connect(post_save_geodata, sender=GeoVectorData)
-def geodata_attached_changed(sender, **kwargs):
- # manage main geoitem and cascade association
- instance = kwargs.get("instance", None)
- model = kwargs.get("model", None)
- pk_set = kwargs.get("pk_set", None)
- if not instance or not model or not pk_set:
- return
+def geodata_attached_post_add(model, instance, pk_set):
item_pks = list(model.objects.filter(pk__in=pk_set).values_list("pk", flat=True))
if not item_pks:
return
- if not hasattr(instance, "_geodata"): # use a cache to manage during geodata attach
+ # use a cache to manage during geodata attach
+ if not hasattr(instance, "_geodata"):
instance._geodata = []
if not instance.main_geodata_id:
instance.main_geodata_id = item_pks[0]
@@ -2617,11 +2612,71 @@ def geodata_attached_changed(sender, **kwargs):
if not q.count():
if not child:
child = model.objects.get(pk=pk)
- if not pk in geoitems:
+ if pk not in geoitems:
geoitems[pk] = GeoVectorData.objects.get(pk=pk)
child_model.objects.get(pk=child_id).geodata.add(geoitems[pk])
+def geodata_attached_remove(model, instance, pk_set=None, clear=False):
+ if clear:
+ item_pks = getattr(instance, "_geodata_clear_item_pks", [])
+ else:
+ item_pks = list(model.objects.filter(pk__in=pk_set).values_list("pk", flat=True))
+ if not item_pks:
+ return
+
+ # use a cache to manage during geodata attach
+ if not hasattr(instance, "_geodata"):
+ instance._geodata = []
+ if instance.main_geodata_id in item_pks:
+ instance.main_geodata_id = None
+ instance.skip_history_when_saving = True
+ instance._no_move = True
+ if not hasattr(instance, "_geodata"):
+ instance._geodata = []
+ instance._geodata += [pk for pk in item_pks if pk not in instance._geodata]
+ instance.save()
+
+ # for all sub item verify that the geo items are present
+ for query in instance.geodata_child_item_queries():
+ child_model = query.model
+ m2m_model = child_model.geodata.through
+ m2m_key = f"{child_model._meta.model_name}_id"
+ geoitems = {}
+ for child_id in query.values_list("id", flat=True):
+ child = None
+ for pk in item_pks:
+ q = m2m_model.objects.filter(**{m2m_key: child_id,
+ "geovectordata_id": pk})
+ if q.count():
+ if not child:
+ child = model.objects.get(pk=pk)
+ if pk not in geoitems:
+ geoitems[pk] = GeoVectorData.objects.get(pk=pk)
+ child_model.objects.get(pk=child_id).geodata.remove(geoitems[pk])
+
+
+def geodata_attached_changed(sender, **kwargs):
+ # manage main geoitem and cascade association
+ instance = kwargs.get("instance", None)
+ model = kwargs.get("model", None)
+ pk_set = kwargs.get("pk_set", None)
+ action = kwargs.get("action", None)
+ if not instance or not model:
+ return
+
+ if action == "post_add":
+ geodata_attached_post_add(model, instance, pk_set)
+ elif action == "post_remove":
+ geodata_attached_remove(model, instance, pk_set)
+ elif action == "pre_clear":
+ instance._geodata_clear_item_pks = list(
+ instance.geodata.values_list("id", flat=True)
+ )
+ elif action == "post_clear":
+ geodata_attached_remove(model, instance, clear=True)
+
+
class GeographicItem(models.Model):
main_geodata = models.ForeignKey(
GeoVectorData,
diff --git a/ishtar_common/tests.py b/ishtar_common/tests.py
index 74e746c61..4156f9f0f 100644
--- a/ishtar_common/tests.py
+++ b/ishtar_common/tests.py
@@ -3372,6 +3372,16 @@ class GeoVectorTest(TestCase):
app_label=self.app_source,
model=self.model_source
).pk
+ self.alt_data_type = models.GeoDataType.objects.get(
+ txt_idx="basefind-center",
+ )
+ self.alt_app_source = "archaeological_finds"
+ self.alt_model_source = "basefind"
+ self.alt_source_pk = self.base_find.pk
+ self.alt_source_content_type_pk = ContentType.objects.get(
+ app_label=self.alt_app_source,
+ model=self.alt_model_source
+ ).pk
def _reinit_objects(self):
# get object from db
@@ -3383,13 +3393,16 @@ class GeoVectorTest(TestCase):
BaseFind = apps.get_model("archaeological_finds", "BaseFind")
self.base_find = BaseFind.objects.get(pk=self.base_find.pk)
- def _create_geodata(self):
+ def _create_geodata(self, alt=False):
+ ct = self.source_content_type_pk if not alt else self.alt_source_content_type_pk
+ source = self.source_pk if not alt else self.alt_source_pk
+ dt = self.data_type if not alt else self.alt_data_type
return models.GeoVectorData.objects.create(
- source_content_type_id=self.source_content_type_pk,
- source_id=self.source_pk,
+ source_content_type_id=ct,
+ source_id=source,
name="Test geo",
origin=self.origin,
- data_type=self.data_type,
+ data_type=dt,
provider=self.provider,
comment="This is a comment."
)
@@ -3402,6 +3415,9 @@ class GeoVectorTest(TestCase):
self.assertIsNone(self.base_find.main_geodata)
self.assertEqual(self.base_find.geodata.count(), 0)
+ geo_vector_find = self._create_geodata(alt=True)
+ self.base_find.geodata.add(geo_vector_find)
+
geo_vector = self._create_geodata()
self.operation.geodata.add(geo_vector)
@@ -3410,10 +3426,59 @@ class GeoVectorTest(TestCase):
self.assertEqual(self.operation.main_geodata, geo_vector)
self.assertEqual(self.context_record.geodata.count(), 1)
self.assertEqual(self.context_record.main_geodata, geo_vector)
+ self.assertEqual(self.base_find.geodata.count(), 2)
+ self.assertEqual(self.base_find.main_geodata, geo_vector_find)
+
+ geo_vector2 = self._create_geodata()
+ self.operation.geodata.add(geo_vector2)
+
+ self._reinit_objects()
+ self.assertEqual(self.operation.geodata.count(), 2)
+ self.assertEqual(self.operation.main_geodata, geo_vector) # no change
+ self.assertEqual(self.context_record.geodata.count(), 2)
+ self.assertEqual(self.context_record.main_geodata, geo_vector) # no change
+ self.assertEqual(self.base_find.geodata.count(), 3)
+ self.assertEqual(self.base_find.main_geodata, geo_vector_find) # no change
+
+ def test_cascade_remove(self):
+ geo_vector = self._create_geodata()
+ self.operation.geodata.add(geo_vector)
+ geo_vector2 = self._create_geodata()
+ self.operation.geodata.add(geo_vector2)
+ geo_vector_find = self._create_geodata(alt=True)
+ self.base_find.geodata.add(geo_vector_find)
+
+ self.operation.geodata.remove(geo_vector)
+ self._reinit_objects()
+ # main geoitem changed to geovector2
+ self.assertEqual(self.operation.main_geodata, geo_vector2)
+ self.assertEqual(self.operation.geodata.count(), 1)
+ self.assertEqual(self.context_record.main_geodata, geo_vector2)
+ self.assertEqual(self.context_record.geodata.count(), 1)
+ self.assertEqual(self.base_find.main_geodata, geo_vector2)
+ self.assertEqual(self.base_find.geodata.count(), 2)
+
+ self.operation.geodata.remove(geo_vector2)
+ self._reinit_objects()
+ self.assertIsNone(self.operation.main_geodata)
+ self.assertEqual(self.operation.geodata.count(), 0)
+ self.assertIsNone(self.context_record.main_geodata)
+ self.assertEqual(self.context_record.geodata.count(), 0)
+ self.assertEqual(self.base_find.main_geodata, geo_vector_find)
+ self.assertEqual(self.base_find.geodata.count(), 1)
+
+ self.operation.geodata.add(geo_vector)
+ self.operation.geodata.add(geo_vector2)
+
+ self.operation.geodata.clear()
+ self._reinit_objects()
+ self.assertIsNone(self.operation.main_geodata)
+ self.assertEqual(self.operation.geodata.count(), 0)
+ self.assertIsNone(self.context_record.main_geodata)
+ self.assertEqual(self.context_record.geodata.count(), 0)
+ self.assertEqual(self.base_find.main_geodata, geo_vector_find)
self.assertEqual(self.base_find.geodata.count(), 1)
- self.assertEqual(self.base_find.main_geodata, geo_vector)
- # test geo item remove
# test town add
# test town remove