summaryrefslogtreecommitdiff
path: root/ishtar_common/models.py
diff options
context:
space:
mode:
Diffstat (limited to 'ishtar_common/models.py')
-rw-r--r--ishtar_common/models.py245
1 files changed, 245 insertions, 0 deletions
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index 90e8a8d8d..c8a2f4f45 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -180,6 +180,7 @@ from ishtar_common.models_common import (
post_save_cache,
QuickAction,
SearchVectorConfig,
+ SerializeItem,
SpatialReferenceSystem,
TemplateItem,
ShortMenuItem,
@@ -6248,6 +6249,250 @@ post_save.connect(post_save_cache, sender=OperationType)
post_delete.connect(post_save_cache, sender=OperationType)
+class BaseDating(models.Model, SerializeItem):
+ SLUG = "dating"
+ SERIALIZE_EXCLUDE = ["find", "context_record", "archaeological_site"]
+ CURRENT_MODEL = None
+ CURRENT_MODEL_ATTR = None
+ uuid = models.UUIDField(default=uuid.uuid4)
+ reference = models.TextField(_("Reference"), blank=True, default="")
+ external_id = models.TextField(_("External ID"), blank=True, default="")
+ period = models.ForeignKey(
+ "archaeological_operations.Period", verbose_name=_("Chronological period"),
+ on_delete=models.PROTECT,
+ blank=True,
+ null=True,
+ )
+ start_date = models.IntegerField(_("Start date"), blank=True, null=True)
+ end_date = models.IntegerField(_("End date"), blank=True, null=True)
+ dating_type = models.ForeignKey(
+ "archaeological_context_records.DatingType",
+ verbose_name=_("Dating type"),
+ on_delete=models.SET_NULL,
+ blank=True,
+ null=True,
+ )
+ quality = models.ForeignKey(
+ "archaeological_context_records.DatingQuality",
+ verbose_name=_("Quality"),
+ on_delete=models.SET_NULL,
+ blank=True,
+ null=True,
+ )
+ precise_dating = models.TextField(_("Precise on this dating"), blank=True, default="")
+ objects = UUIDModelManager()
+ ASSOCIATED_ALT_NAMES = {
+ "datings__period": SearchAltName(
+ pgettext_lazy("key for text search", "datings-period"),
+ "datings__period__label__iexact",
+ ),
+ "datings__precise_dating": SearchAltName(
+ pgettext_lazy("key for text search", "datings-precise"),
+ "datings__precise_dating__iexact",
+ ),
+ "datings__start_date": SearchAltName(
+ pgettext_lazy("key for text search", "datings-start"),
+ "datings__start_date",
+ ),
+ "datings__end_date": SearchAltName(
+ pgettext_lazy("key for text search", "datings-end"),
+ "datings__end_date",
+ ),
+ "datings__dating_type": SearchAltName(
+ pgettext_lazy("key for text search", "datings-type"),
+ "datings__dating_type__label__iexact",
+ ),
+ "datings__quality": SearchAltName(
+ pgettext_lazy("key for text search", "datings-quality"),
+ "datings__quality__label__iexact",
+ ),
+ }
+
+ class Meta:
+ abstract = True
+
+ def __str__(self):
+ if self.precise_dating and self.precise_dating.strip():
+ return self.precise_dating.strip()
+ start_date = self.start_date and str(self.start_date) or ""
+ end_date = self.end_date and str(self.end_date) or ""
+ if not start_date and not end_date:
+ return str(self.period)
+ return "%s (%s-%s)" % (self.period, start_date, end_date)
+
+ def natural_key(self):
+ return (self.uuid,)
+
+ def get_values(self, prefix="", no_values=False, filtr=None, **kwargs):
+ values = {}
+ if not filtr or prefix + "reference" in filtr:
+ values[prefix + "reference"] = self.reference
+ if not filtr or prefix + "period" in filtr:
+ values[prefix + "period"] = str(self.period)
+ if not filtr or prefix + "start_date" in filtr:
+ values[prefix + "start_date"] = self.start_date or ""
+ if not filtr or prefix + "end_date" in filtr:
+ values[prefix + "end_date"] = self.end_date or ""
+ if not filtr or prefix + "dating_type" in filtr:
+ values[prefix + "dating_type"] = (
+ str(self.dating_type) if self.dating_type else ""
+ )
+ if not filtr or prefix + "quality" in filtr:
+ values[prefix + "quality"] = str(self.quality) if self.quality else ""
+ if not filtr or prefix + "precise_dating" in filtr:
+ values[prefix + "precise_dating"] = self.precise_dating
+ return values
+
+ HISTORY_ATTR = [
+ "reference",
+ "period",
+ "start_date",
+ "end_date",
+ "dating_type",
+ "quality",
+ "precise_dating",
+ ]
+
+ def history_compress(self):
+ values = {}
+ attrs = self.HISTORY_ATTR + [self.CURRENT_MODEL_ATTR + "_id"]
+ for attr in attrs:
+ val = getattr(self, attr)
+ if hasattr(val, "history_compress"):
+ val = val.history_compress()
+ elif hasattr(val, "isoformat"):
+ val = val.isoformat()
+ elif val is None:
+ val = ""
+ else:
+ val = str(val)
+ values[attr] = val
+ return values
+
+ @classmethod
+ def history_decompress(cls, full_value, create=False):
+ if not full_value:
+ return []
+ full_res = []
+ for value in full_value:
+ res = {}
+ for key in value:
+ val = value[key]
+ if val == "" and key != "precise_dating":
+ val = None
+ elif key in ("period", "dating_type", "quality"):
+ field = cls._meta.get_field(key)
+ q = field.related_model.objects.filter(txt_idx=val)
+ if q.count():
+ val = q.all()[0]
+ else: # do not exist anymore in db
+ val = None
+ elif key in ("start_date", "end_date"):
+ val = int(val)
+ res[key] = val
+ if create:
+ res = cls.objects.create(**res)
+ full_res.append(res)
+ return full_res
+
+ @classmethod
+ def is_identical(cls, dating_1, dating_2):
+ """
+ Compare two dating attribute by attribute and return True if all
+ attribute is identical
+ """
+ for attr in [
+ "reference",
+ "period",
+ "start_date",
+ "end_date",
+ "dating_type",
+ "quality",
+ "precise_dating",
+ ]:
+ value1 = getattr(dating_1, attr)
+ value2 = getattr(dating_2, attr)
+ if attr == "precise_dating":
+ if value1:
+ value1 = value1.strip()
+ if value2:
+ value2 = value2.strip()
+ if value1 != value2:
+ return False
+ return True
+
+ def context_records_lbl(self):
+ return " - ".join(cr.cached_label for cr in self.context_records.all())
+
+ context_records_lbl.short_description = _("Context record")
+ context_records_lbl.admin_order_field = "context_records__cached_label"
+
+ def finds_lbl(self):
+ return " - ".join(f.cached_label for f in self.find.all())
+
+ finds_lbl.short_description = _("Find")
+ finds_lbl.admin_order_field = "find__cached_label"
+
+ @classmethod
+ def fix_dating_association(cls, obj):
+ """
+ Fix redundant m2m dating association (usually after imports)
+ """
+ current_datings = []
+ for dating in obj.datings.order_by("pk").all():
+ key = (
+ dating.period.pk,
+ dating.reference,
+ dating.start_date,
+ dating.end_date,
+ dating.dating_type,
+ dating.quality,
+ dating.precise_dating,
+ )
+ if key not in current_datings:
+ current_datings.append(key)
+ continue
+ dating.delete()
+
+ @property
+ def q_parent(self):
+ if not self.pk or not self.CURRENT_MODEL:
+ return
+ if getattr(self, "__q_parent", None):
+ return self.__q_parent
+ q = self.CURRENT_MODEL.objects.filter(datings__pk=self.pk)
+ if q.count():
+ self.__q_parent = q
+ return q
+
+ @property
+ def parent_external_id(self):
+ if not self.pk or not self.q_parent:
+ return ""
+ return self.q_parent.all()[0].external_id
+
+ @property
+ def auto_id(self):
+ if not self.pk or not self.q_parent:
+ return 0
+ parent_pk = self.q_parent.all()[0].pk
+ attr = self.CURRENT_MODEL_ATTR
+ for idx, dating_pk in enumerate(
+ self.__class__.objects.filter(**{attr: parent_pk}).values_list(
+ "pk", flat=True).all()).all():
+ if dating_pk == self.pk:
+ return idx + 1
+ return 0
+
+ def save(self, *args, **kwargs):
+ super().save(*args, **kwargs)
+ if not self.pk:
+ return
+ external_id = get_generated_id("dating_external_id", self)
+ if external_id != self.external_id:
+ self.__class__.objects.filter(pk=self.pk).update(external_id=external_id)
+
+
class AdministrationScript(models.Model):
path = models.CharField(_("Filename"), max_length=30)
name = models.TextField(_("Name"), blank=True, default="")