summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archaeological_context_records/models.py15
-rw-r--r--archaeological_context_records/tests.py30
-rw-r--r--archaeological_finds/models_finds.py22
-rw-r--r--archaeological_operations/models.py16
-rw-r--r--archaeological_warehouse/models.py4
-rw-r--r--ishtar_common/models.py4
-rw-r--r--ishtar_common/models_common.py41
-rw-r--r--ishtar_common/utils.py7
-rw-r--r--ishtar_common/wizards.py1
9 files changed, 123 insertions, 17 deletions
diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py
index 4da7e35e2..87300b899 100644
--- a/archaeological_context_records/models.py
+++ b/archaeological_context_records/models.py
@@ -27,7 +27,7 @@ from django.contrib.postgres.indexes import GinIndex
from django.contrib.sites.models import Site
from django.db import transaction, OperationalError, IntegrityError
from django.db.models import Q
-from django.db.models.signals import post_delete, post_save, m2m_changed
+from django.db.models.signals import m2m_changed, pre_delete, post_delete, post_save
from django.urls import reverse, reverse_lazy
from ishtar_common.utils import get_generated_id, gettext_lazy as _, pgettext_lazy, \
@@ -59,6 +59,7 @@ from ishtar_common.models import (
RelationItem,
Town,
get_current_profile,
+ geo_item_pre_delete,
document_attached_changed,
HistoryModel,
GeoItem,
@@ -1485,10 +1486,11 @@ class ContextRecord(
Return sub object list that will be deleted
:return: {"Sub object type": ["Sub object 1", "Sub object 2", ...]}
"""
+ data = super().get_deleted_data()
if not self.base_finds.count():
- return {}
+ return data
lbl = str(_("Base finds"))
- data = {lbl: []}
+ data[lbl] = []
for item in self.base_finds.all():
data[lbl].append(str(item))
for key, value in item.get_deleted_data().items():
@@ -1514,11 +1516,11 @@ class ContextRecord(
def context_record_post_save(sender, **kwargs):
- cached_label_changed(sender=sender, **kwargs)
- post_save_geo(sender=sender, **kwargs)
instance = kwargs.get("instance", None)
- if not instance or not instance.pk:
+ if not instance or not instance.pk or getattr(instance, "__delete", False):
return
+ cached_label_changed(sender=sender, **kwargs)
+ post_save_geo(sender=sender, **kwargs)
profile = get_current_profile()
if profile.parent_relations_engine == "T":
ContextRecordTree._update_self_relation(instance.pk) # on creation: manage self relation
@@ -1532,6 +1534,7 @@ def context_record_post_save(sender, **kwargs):
cached_label_changed(Find, instance=f)
+pre_delete.connect(geo_item_pre_delete, sender=ContextRecord)
post_save.connect(context_record_post_save, sender=ContextRecord)
m2m_changed.connect(document_attached_changed, sender=ContextRecord.documents.through)
m2m_changed.connect(geodata_attached_changed, sender=ContextRecord.geodata.through)
diff --git a/archaeological_context_records/tests.py b/archaeological_context_records/tests.py
index 942ad83f1..0338a2f20 100644
--- a/archaeological_context_records/tests.py
+++ b/archaeological_context_records/tests.py
@@ -24,6 +24,7 @@ import locale
from django.apps import apps
from django.conf import settings
from django.contrib.auth.models import Permission, Group
+from django.contrib.contenttypes.models import ContentType
from django.core.exceptions import ValidationError
from django.core.files.uploadedfile import SimpleUploadedFile
from django.template.defaultfilters import slugify
@@ -600,6 +601,35 @@ class ContextRecordTest(ContextRecordInit, TestCase):
# same unit and other operation -> 1
self.assertEqual(cr3.custom_index, 1)
+ def test_cascade_delete(self):
+ cr1 = self.context_records[0]
+ # add a geo_vector associated to the town
+ source_content_type_pk = ContentType.objects.get(
+ app_label="ishtar_common",
+ model="town"
+ ).pk
+ geo_vector = models.GeoVectorData.objects.create(
+ source_content_type_id=source_content_type_pk,
+ source_id=cr1.town_id,
+ name="geo",
+ comment="This is a comment."
+ )
+ cr1.geodata.add(geo_vector)
+ BaseFind = apps.get_model("archaeological_finds", "BaseFind")
+ bf = BaseFind.objects.create(context_record=cr1)
+ bf.geodata.add(geo_vector)
+ Find = apps.get_model("archaeological_finds", "Find")
+ find = Find.objects.create()
+ bf.find.add(find)
+ dating = models.ContextRecordDating.objects.create(context_record=cr1)
+ cr1.operation.delete()
+ self.assertEqual(models.ContextRecord.objects.filter(id=cr1.id).count(), 0)
+ self.assertEqual(Find.objects.filter(id=find.id).count(), 0)
+ self.assertEqual(BaseFind.objects.filter(id=bf.id).count(), 0)
+ self.assertEqual(models.ContextRecordDating.objects.filter(id=dating.id).count(),
+ 0)
+ self.assertEqual(models.GeoVectorData.objects.filter(id=geo_vector.id).count(), 1)
+
class ContextRecordQATest(ContextRecordInit, TestCase):
fixtures = CONTEXT_RECORD_TOWNS_FIXTURES
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index 5eed32772..56232165f 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -71,6 +71,8 @@ from ishtar_common.models import (
QuickAction,
SearchVectorConfig,
ValueGetter,
+ main_item_pre_delete,
+ geo_item_pre_delete
)
from ishtar_common.models_common import HistoricalRecords, SerializeItem, \
GeoVectorData, geodata_attached_changed
@@ -938,21 +940,23 @@ class BaseFind(
Return sub object list that will be deleted
:return: {"Sub object type": ["Sub object 1", "Sub object 2", ...]}
"""
+ data = super().get_deleted_data()
if self.find.count() != 1:
- return {}
+ return data
lbl = str(_("Finds"))
- data = {lbl: []}
+ data[lbl] = []
for item in self.find.all():
data[lbl].append(str(item))
return data
def post_save_basefind(sender, **kwargs):
+ instance = kwargs.get("instance", None)
+ if not instance or not instance.pk or getattr(instance, "__delete", False):
+ return
cached_label_changed(sender, **kwargs)
post_save_geo(sender, **kwargs)
instance = kwargs.get("instance", None)
- if not instance or not instance.pk:
- return
for f in instance.find.all():
cached_label_changed(Find, instance=f)
@@ -961,10 +965,12 @@ def pre_delete_basefind(sender, **kwargs):
instance = kwargs["instance"]
if not instance or not instance.pk:
return
+ geo_item_pre_delete(sender, **kwargs)
q = Find.objects.filter(base_finds__pk=instance.pk)
for find in q.all():
if find.base_finds.count() == 1: # only associated to the deleted base find
find.__base_find_deleted = True # prevent loop
+ find.__delete = True
find.delete()
@@ -3828,6 +3834,14 @@ def pre_clean_find(sender, **kwargs):
instance.upstream_treatment.delete()
+def pre_delete_find(sender, **kwargs):
+ instance = kwargs["instance"]
+ if not instance or not instance.pk:
+ return
+ main_item_pre_delete(sender, **kwargs)
+
+
+pre_delete.connect(pre_delete_find, sender=Find)
post_save.connect(cached_label_changed, sender=Find)
pre_delete.connect(pre_clean_find, sender=Find)
diff --git a/archaeological_operations/models.py b/archaeological_operations/models.py
index 6ef6ced88..452874abe 100644
--- a/archaeological_operations/models.py
+++ b/archaeological_operations/models.py
@@ -32,7 +32,7 @@ from django.contrib.postgres.indexes import GinIndex
from django.contrib.sites.models import Site
from django.db import transaction, OperationalError, IntegrityError
from django.db.models import Q, Max, Sum
-from django.db.models.signals import post_save, m2m_changed, post_delete
+from django.db.models.signals import m2m_changed, post_save, post_delete, pre_delete
from django.forms import ValidationError
from django.urls import reverse, reverse_lazy
from ishtar_common.data_importer import post_importer_action
@@ -73,6 +73,7 @@ from ishtar_common.models import (
QuickAction,
MainItem,
HierarchicalType,
+ geo_item_pre_delete,
)
from ishtar_common.models_common import Department, GeoVectorData, HistoricalRecords,\
geodata_attached_changed, geotown_attached_changed
@@ -1015,6 +1016,11 @@ class ArchaeologicalSite(
def site_post_save(sender, **kwargs):
+ instance = kwargs.get("instance", None)
+ if not instance or not instance.pk:
+ return
+ if getattr(instance, "__delete", False):
+ return
cached_label_changed(sender=sender, **kwargs)
post_save_geo(sender=sender, **kwargs)
@@ -1937,10 +1943,10 @@ class Operation(
Return sub object list that will be deleted
:return: {"Sub object type": ["Sub object 1", "Sub object 2", ...]}
"""
- data = {}
+ data = super().get_deleted_data()
if self.administrative_act.count():
lbl = str(_("Administrative act"))
- data = {lbl: []}
+ data[lbl] = []
for item in self.administrative_act.all():
data[lbl].append(str(item))
if self.context_record.count():
@@ -2696,7 +2702,8 @@ for attr in Operation.HISTORICAL_M2M:
def operation_post_save(sender, **kwargs):
- if not kwargs["instance"]:
+ instance = kwargs.get("instance", None)
+ if not instance or not instance.pk or getattr(instance, "__delete", False):
return
post_save_geo(sender=sender, **kwargs)
@@ -2743,6 +2750,7 @@ def operation_post_save(sender, **kwargs):
post_save.connect(operation_post_save, sender=Operation)
+pre_delete.connect(geo_item_pre_delete, sender=Operation)
def operation_town_m2m_changed(sender, **kwargs):
diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py
index dc9aa340a..4a5294632 100644
--- a/archaeological_warehouse/models.py
+++ b/archaeological_warehouse/models.py
@@ -58,6 +58,7 @@ from ishtar_common.models_common import (
QuickAction,
MainItem,
Merge,
+ main_item_pre_delete
)
from ishtar_common.model_merging import merge_model_objects
from ishtar_common.utils import (
@@ -2170,6 +2171,9 @@ def container_post_save(sender, **kwargs):
def container_pre_delete(sender, **kwargs):
instance = kwargs["instance"]
+ if not instance or not instance.pk:
+ return
+ main_item_pre_delete(sender, **kwargs)
if getattr(instance, "_no_pre_delete", False):
return
q = Container.objects.filter(container_tree_child__container_parent=instance)
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index aa9224be7..86be555ca 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -187,6 +187,8 @@ from ishtar_common.models_common import (
State,
StatisticItem,
Town,
+ main_item_pre_delete,
+ geo_item_pre_delete
)
__all__ = [
@@ -247,6 +249,8 @@ __all__ = [
"GeoOriginType",
"GeoProviderType",
"GeoBufferType",
+ "geo_item_pre_delete",
+ "main_item_pre_delete"
]
logger = logging.getLogger(__name__)
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index 00ff8babd..986ba209d 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -40,7 +40,7 @@ from django.urls import reverse, NoReverseMatch
from django.core.validators import validate_slug
from django.db import connection, transaction, OperationalError, IntegrityError
from django.db.models import JSONField, Q, Count, Max
-from django.db.models.signals import post_save, post_delete, m2m_changed
+from django.db.models.signals import m2m_changed, post_save, post_delete, pre_delete
from django.template import loader
from django.template.defaultfilters import slugify
from django.utils import timezone
@@ -3110,6 +3110,8 @@ def geodata_attached_changed(sender, **kwargs):
if not profile.mapping:
return
instance = kwargs.get("instance", None)
+ if getattr(instance, "__delete", False):
+ return
model = kwargs.get("model", None)
pk_set = kwargs.get("pk_set", None)
@@ -3244,6 +3246,43 @@ class GeographicItem(models.Model):
self._geodata_list = lst
return lst
+ @property
+ def q_associated_source_geovectordata(self):
+ content_type = ContentType.objects.get_for_model(self.__class__)
+ return GeoVectorData.objects.filter(source_content_type=content_type,
+ source_id=self.pk)
+
+ def get_deleted_data(self) -> dict:
+ """
+ Return sub object list that will be deleted
+ :return: {"Sub object type": ["Sub object 1", "Sub object 2", ...]}
+ """
+ if not self.q_associated_source_geovectordata.count():
+ return {}
+ lbl = str(_("Geographic - Vector data"))
+ data = {lbl: []}
+ for geodata in self.q_associated_source_geovectordata.all():
+ data[lbl].append(f"{self.__class__._meta.verbose_name} - {geodata}")
+ return data
+
+
+def main_item_pre_delete(sender, **kwargs):
+ instance = kwargs.get("instance", None)
+ if not instance or not instance.pk:
+ return
+ instance.__delete = True
+
+
+def geo_item_pre_delete(sender, **kwargs):
+ instance = kwargs.get("instance", None)
+ if not instance or not instance.pk:
+ return
+ instance.__delete = True
+ instance._post_save_geo_ok = True
+ instance._post_saved_geo = True
+ instance.geodata.clear()
+ instance.q_associated_source_geovectordata.delete()
+
class PermissionQuery(models.Model):
model = models.ForeignKey(ContentType, related_name="permissions",
diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py
index bd79814e9..bdd7a67e5 100644
--- a/ishtar_common/utils.py
+++ b/ishtar_common/utils.py
@@ -2402,20 +2402,23 @@ def manage_m2m(obj, kwargs):
obj.skip_history_when_saving = True
elif not obj.history_modifier:
obj.skip_history_when_saving = True
+ obj._post_save_geo_ok = True
obj.save()
def related_historization_changed(sender, **kwargs):
rel_obj = kwargs.get("instance", None)
- if not rel_obj or not getattr(rel_obj, "CURRENT_MODEL_ATTR", None):
+ if not rel_obj or not getattr(rel_obj, "CURRENT_MODEL_ATTR", None) or getattr(
+ rel_obj, "__delete", False):
return
obj = getattr(rel_obj, rel_obj.CURRENT_MODEL_ATTR)
+ obj._post_save_geo_ok = True
manage_m2m(obj, kwargs)
def m2m_historization_changed(sender, **kwargs):
obj = kwargs.get("instance", None)
- if not obj:
+ if not obj or getattr(obj, "__delete", False):
return
manage_m2m(obj, kwargs)
diff --git a/ishtar_common/wizards.py b/ishtar_common/wizards.py
index d29ebf365..a7313b13b 100644
--- a/ishtar_common/wizards.py
+++ b/ishtar_common/wizards.py
@@ -1941,6 +1941,7 @@ class MultipleDeletionWizard(MultipleItemWizard):
for obj in objs:
lbls.append(str(obj))
try:
+ obj.__delete = True
obj.delete()
except ObjectDoesNotExist:
pass