summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorÉtienne Loks <etienne.loks@iggdrasil.net>2020-11-17 15:37:22 +0100
committerÉtienne Loks <etienne.loks@iggdrasil.net>2021-02-28 12:15:21 +0100
commit4fa501cb189c61d94a2ca53a604f3db7a212153c (patch)
treee983fd246f6fd2ce0e9521ea23c1f93c73cc8bc9
parenta255ff5f509225c3258aa9546d9cbd4ce0c0fa0b (diff)
downloadIshtar-4fa501cb189c61d94a2ca53a604f3db7a212153c.tar.bz2
Ishtar-4fa501cb189c61d94a2ca53a604f3db7a212153c.zip
Manage a "custom_index" for base types
-rw-r--r--archaeological_context_records/migrations/0105_auto_20201117_0759.py25
-rw-r--r--archaeological_context_records/tests.py54
-rw-r--r--archaeological_files/migrations/0104_auto_20201117_0759.py25
-rw-r--r--archaeological_finds/migrations/0107_auto_20201117_0759.py35
-rw-r--r--archaeological_finds/models_finds.py11
-rw-r--r--archaeological_operations/migrations/0105_auto_20201117_0759.py35
-rw-r--r--archaeological_warehouse/migrations/0106_auto_20201117_0759.py30
-rw-r--r--archaeological_warehouse/models.py5
-rw-r--r--ishtar_common/migrations/0207_auto_20201117_1021.py70
-rw-r--r--ishtar_common/models.py51
-rw-r--r--ishtar_common/models_common.py84
11 files changed, 411 insertions, 14 deletions
diff --git a/archaeological_context_records/migrations/0105_auto_20201117_0759.py b/archaeological_context_records/migrations/0105_auto_20201117_0759.py
new file mode 100644
index 000000000..b51627b83
--- /dev/null
+++ b/archaeological_context_records/migrations/0105_auto_20201117_0759.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2020-11-17 07:59
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_context_records', '0104_auto_20201104_0959'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='contextrecord',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='historicalcontextrecord',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ ]
diff --git a/archaeological_context_records/tests.py b/archaeological_context_records/tests.py
index cd547bc07..6c2c256a0 100644
--- a/archaeological_context_records/tests.py
+++ b/archaeological_context_records/tests.py
@@ -488,6 +488,60 @@ class ContextRecordTest(ContextRecordInit, TestCase):
obj.fix()
self.assertEqual(obj.datings.count(), 2)
+ def test_custom_index(self):
+ profile, created = IshtarSiteProfile.objects.get_or_create(
+ slug='default', active=True)
+
+ # key: operation
+ profile.contextrecord_custom_index = 'operation_id'
+ profile.save()
+ cr1 = self.context_records[0]
+ cr1.save()
+ cr1 = models.ContextRecord.objects.get(pk=cr1.pk)
+ self.assertEqual(cr1.custom_index, 1)
+ cr2 = self.context_records[1]
+ cr2.operation = cr1.operation
+ cr2.save()
+ cr2 = models.ContextRecord.objects.get(pk=cr2.pk)
+ self.assertEqual(cr2.custom_index, 2)
+ ope = self.create_operation()[-1]
+ cr3 = self.create_context_record(
+ data={"operation": ope})[-1]
+ cr3 = models.ContextRecord.objects.get(pk=cr3.pk)
+ self.assertEqual(cr3.custom_index, 1)
+
+ # key: operation, unit
+ profile.contextrecord_custom_index = 'unit_id;operation_id'
+ profile.save()
+
+ su = models.Unit.objects.get(txt_idx='stratigraphic-unit')
+ dest = models.Unit.objects.get(txt_idx='sector')
+ cr1.unit, cr2.unit = su, dest
+ cr1.save()
+ cr2.save()
+ cr2 = models.ContextRecord.objects.get(pk=cr2.pk)
+ # no change if custom_index not reinit
+ self.assertEqual(cr2.custom_index, 2)
+ cr1 = models.ContextRecord.objects.get(pk=cr1.pk)
+ self.assertEqual(cr1.custom_index, 1)
+ cr2.custom_index = None
+ cr2.save()
+ cr2 = models.ContextRecord.objects.get(pk=cr2.pk)
+ # different unit -> 1
+ self.assertEqual(cr2.custom_index, 1)
+ cr2.unit = cr1.unit
+ cr2.custom_index = None
+ cr2.save()
+ cr2 = models.ContextRecord.objects.get(pk=cr2.pk)
+ # same unit and operation -> 2
+ self.assertEqual(cr2.custom_index, 2)
+ cr3.unit = cr1.unit
+ cr3.custom_index = None
+ cr3.save()
+ cr3 = models.ContextRecord.objects.get(pk=cr3.pk)
+ # same unit and other operation -> 1
+ self.assertEqual(cr3.custom_index, 1)
+
class ContextRecordSearchTest(ContextRecordInit, TestCase, SearchText):
fixtures = CONTEXT_RECORD_TOWNS_FIXTURES
diff --git a/archaeological_files/migrations/0104_auto_20201117_0759.py b/archaeological_files/migrations/0104_auto_20201117_0759.py
new file mode 100644
index 000000000..3bb881ef3
--- /dev/null
+++ b/archaeological_files/migrations/0104_auto_20201117_0759.py
@@ -0,0 +1,25 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2020-11-17 07:59
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_files', '0103_auto_20201104_1000'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='file',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='historicalfile',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ ]
diff --git a/archaeological_finds/migrations/0107_auto_20201117_0759.py b/archaeological_finds/migrations/0107_auto_20201117_0759.py
new file mode 100644
index 000000000..c451c601a
--- /dev/null
+++ b/archaeological_finds/migrations/0107_auto_20201117_0759.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2020-11-17 07:59
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_finds', '0106_auto_20201104_1000'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='basefind',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='find',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='historicalbasefind',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='historicalfind',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ ]
diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py
index a9f554380..9b1f43cb6 100644
--- a/archaeological_finds/models_finds.py
+++ b/archaeological_finds/models_finds.py
@@ -343,6 +343,10 @@ class BaseFind(BulkUpdatedItem, BaseHistorizedItem, GeoItem,
def natural_key(self):
return (self.uuid, )
+ @property
+ def operation(self):
+ return self.context_record.operation
+
def public_representation(self):
dct = super(BaseFind, self).public_representation()
dct.update({
@@ -1853,6 +1857,13 @@ class Find(BulkUpdatedItem, ValueGetter, DocumentItem, BaseHistorizedItem,
bf.context_record.operation.get_reference(),
self.index)
+ @property
+ def operation(self):
+ bf = self.get_first_base_find()
+ if not bf or not bf.context_record or not bf.context_record.operation:
+ return
+ return bf.context_record.operation
+
def context_records_lbl(self):
return " - ".join(
[bf.context_record.cached_label for bf in self.base_finds.all()]
diff --git a/archaeological_operations/migrations/0105_auto_20201117_0759.py b/archaeological_operations/migrations/0105_auto_20201117_0759.py
new file mode 100644
index 000000000..7514368e5
--- /dev/null
+++ b/archaeological_operations/migrations/0105_auto_20201117_0759.py
@@ -0,0 +1,35 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2020-11-17 07:59
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_operations', '0104_auto_20201104_0959'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='archaeologicalsite',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='historicalarchaeologicalsite',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='historicaloperation',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='operation',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ ]
diff --git a/archaeological_warehouse/migrations/0106_auto_20201117_0759.py b/archaeological_warehouse/migrations/0106_auto_20201117_0759.py
new file mode 100644
index 000000000..39a30b34c
--- /dev/null
+++ b/archaeological_warehouse/migrations/0106_auto_20201117_0759.py
@@ -0,0 +1,30 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2020-11-17 07:59
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('archaeological_warehouse', '0105_auto_20201104_1000'),
+ ]
+
+ operations = [
+ migrations.AddField(
+ model_name='container',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='historicalwarehouse',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='warehouse',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ ]
diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py
index 5ae4de5a0..872cc1d68 100644
--- a/archaeological_warehouse/models.py
+++ b/archaeological_warehouse/models.py
@@ -610,8 +610,9 @@ class ContainerTree(models.Model):
db_table = 'containers_tree'
-class Container(DocumentItem, Merge, LightHistorizedItem, CompleteIdentifierItem, GeoItem,
- OwnPerms, MainItem, DivisionContainer, ValueGetter):
+class Container(DocumentItem, Merge, LightHistorizedItem,
+ CompleteIdentifierItem, GeoItem, OwnPerms, MainItem,
+ DivisionContainer, ValueGetter):
SLUG = 'container'
APP = "archaeological-warehouse"
MODEL = "container"
diff --git a/ishtar_common/migrations/0207_auto_20201117_1021.py b/ishtar_common/migrations/0207_auto_20201117_1021.py
new file mode 100644
index 000000000..bd6d970fe
--- /dev/null
+++ b/ishtar_common/migrations/0207_auto_20201117_1021.py
@@ -0,0 +1,70 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.11.27 on 2020-11-17 10:21
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ dependencies = [
+ ('ishtar_common', '0206_auto_20201110_1030'),
+ ]
+
+ operations = [
+ migrations.RenameField(
+ model_name='ishtarsiteprofile',
+ old_name='context_record_complete_identifier',
+ new_name='contextrecord_complete_identifier',
+ ),
+ migrations.AddField(
+ model_name='document',
+ name='custom_index',
+ field=models.IntegerField(blank=True, null=True, verbose_name='Custom index'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='basefind_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage base find custom index.', verbose_name='Base find custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='container_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage container custom index.', verbose_name='Container custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='contextrecord_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage context record custom index.', verbose_name='Context record custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='document_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage document custom index.', verbose_name='Document custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='file_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage archaeological file custom index.', verbose_name='Archaeological file custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='find_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage find custom index.', verbose_name='Find custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='operation_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage operation custom index.', verbose_name='Operation custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='site_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage archaeological site custom index.', verbose_name='Archaeological site custom index key'),
+ ),
+ migrations.AddField(
+ model_name='ishtarsiteprofile',
+ name='warehouse_custom_index',
+ field=models.TextField(default='', help_text='Key to be used to manage warehouse custom index.', verbose_name='Warehouse custom index key'),
+ ),
+ ]
diff --git a/ishtar_common/models.py b/ishtar_common/models.py
index bba04488b..6e8e0409e 100644
--- a/ishtar_common/models.py
+++ b/ishtar_common/models.py
@@ -808,11 +808,20 @@ class IshtarSiteProfile(models.Model, Cached):
_("Operation complete identifier"),
default="",
help_text=_("Formula to manage operation complete identifier."))
+ operation_custom_index = models.TextField(
+ _("Operation custom index key"),
+ default="",
+ help_text=_("Key to be used to manage operation custom index."))
site_complete_identifier = models.TextField(
_("Archaeological site complete identifier"),
default="",
help_text=_("Formula to manage archaeological site complete"
" identifier."))
+ site_custom_index = models.TextField(
+ _("Archaeological site custom index key"),
+ default="",
+ help_text=_("Key to be used to manage archaeological site custom"
+ " index."))
file_external_id = models.TextField(
_("File external id"),
default="{year}-{numeric_reference}",
@@ -825,6 +834,11 @@ class IshtarSiteProfile(models.Model, Cached):
default="",
help_text=_("Formula to manage archaeological file complete "
"identifier."))
+ file_custom_index = models.TextField(
+ _("Archaeological file custom index key"),
+ default="",
+ help_text=_("Key to be used to manage archaeological file custom "
+ "index."))
parcel_external_id = models.TextField(
_("Parcel external id"),
default="{associated_file__external_id}{operation__code_patriarche}-"
@@ -840,10 +854,14 @@ class IshtarSiteProfile(models.Model, Cached):
"Change this with care. With incorrect formula, the "
"application might be unusable and import of external "
"data can be destructive."))
- context_record_complete_identifier = models.TextField(
+ contextrecord_complete_identifier = models.TextField(
_("Context record complete identifier"),
default="",
help_text=_("Formula to manage context record complete identifier."))
+ contextrecord_custom_index = models.TextField(
+ _("Context record custom index key"),
+ default="",
+ help_text=_("Key to be used to manage context record custom index."))
base_find_external_id = models.TextField(
_("Base find external id"),
default="{context_record__external_id}-{label}",
@@ -855,6 +873,10 @@ class IshtarSiteProfile(models.Model, Cached):
_("Base find complete identifier"),
default="",
help_text=_("Formula to manage base find complete identifier."))
+ basefind_custom_index = models.TextField(
+ _("Base find custom index key"),
+ default="",
+ help_text=_("Key to be used to manage base find custom index."))
find_external_id = models.TextField(
_("Find external id"),
default="{get_first_base_find__context_record__external_id}-{label}",
@@ -866,6 +888,10 @@ class IshtarSiteProfile(models.Model, Cached):
_("Find complete identifier"),
default="",
help_text=_("Formula to manage find complete identifier."))
+ find_custom_index = models.TextField(
+ _("Find custom index key"),
+ default="",
+ help_text=_("Key to be used to manage find custom index."))
container_external_id = models.TextField(
_("Container external id"),
default="{parent_external_id}-{container_type__txt_idx}-"
@@ -878,6 +904,10 @@ class IshtarSiteProfile(models.Model, Cached):
_("Container complete identifier"),
default="",
help_text=_("Formula to manage container complete identifier."))
+ container_custom_index = models.TextField(
+ _("Container custom index key"),
+ default="",
+ help_text=_("Key to be used to manage container custom index."))
warehouse_external_id = models.TextField(
_("Warehouse external id"),
default="{name|slug}",
@@ -889,6 +919,10 @@ class IshtarSiteProfile(models.Model, Cached):
_("Warehouse complete identifier"),
default="",
help_text=_("Formula to manage warehouse complete identifier."))
+ warehouse_custom_index = models.TextField(
+ _("Warehouse custom index key"),
+ default="",
+ help_text=_("Key to be used to manage warehouse custom index."))
document_external_id = models.TextField(
_("Document external id"),
default="{index}",
@@ -900,6 +934,10 @@ class IshtarSiteProfile(models.Model, Cached):
_("Document complete identifier"),
default="",
help_text=_("Formula to manage document complete identifier."))
+ document_custom_index = models.TextField(
+ _("Document custom index key"),
+ default="",
+ help_text=_("Key to be used to manage document custom index."))
person_raw_name = models.TextField(
_("Raw name for person"),
default="{name|upper} {surname}",
@@ -3036,6 +3074,17 @@ class Document(BaseHistorizedItem, CompleteIdentifierItem, OwnPerms, ImageModel,
def __str__(self):
return self.title
+ def get_index_operation(self):
+ current_operation = None
+ ope_nb = self.operations.count()
+ if ope_nb > 1:
+ return
+ elif ope_nb == 1:
+ key = 'operations__pk'
+ cr_nb = self.context_records.count()
+ if cr_nb:
+ self.context_records
+
def natural_key(self):
return (self.external_id,)
diff --git a/ishtar_common/models_common.py b/ishtar_common/models_common.py
index d2e118c7a..4abc81a76 100644
--- a/ishtar_common/models_common.py
+++ b/ishtar_common/models_common.py
@@ -42,7 +42,7 @@ from django.core.serializers import serialize
from django.core.urlresolvers import reverse, NoReverseMatch
from django.core.validators import validate_slug
from django.db import connection
-from django.db.models import Q, Count
+from django.db.models import Q, Count, Max
from django.db.models.signals import post_save, post_delete, m2m_changed
from django.template.defaultfilters import slugify
from django.utils.safestring import SafeText, mark_safe
@@ -62,15 +62,6 @@ from ishtar_common.utils import get_cache, disable_for_loaddata, \
get_all_field_names, merge_tsvectors, cached_label_changed, post_save_geo, \
task, duplicate_item, get_generated_id, get_current_profile
-"""
-from ishtar_common.models import get_external_id, \
- LightHistorizedItem, OwnPerms, Address, post_save_cache, \
- DashboardFormItem, document_attached_changed, SearchAltName, \
- DynamicRequest, GeoItem, QRCodeItem, SearchVectorConfig, DocumentItem, \
- QuickAction, MainItem, Merge
-
-
-"""
logger = logging.getLogger(__name__)
@@ -637,6 +628,18 @@ class HierarchicalType(GeneralType):
lbls.append(item.label)
return " > ".join(reversed(lbls))
+ @property
+ def first_parent(self):
+ parent = self.parent
+ parents = []
+ while parent:
+ if parent in parents: # prevent circular
+ return parent
+ parents.append(parent)
+ if not parent.parent:
+ return parent
+ parent = parent.parent
+
class StatisticItem:
STATISTIC_MODALITIES = [] # example: "year", "operation_type__label"
@@ -2645,6 +2648,7 @@ class CompleteIdentifierItem(models.Model, ImageContainerModel):
HAS_QR_CODE = True
complete_identifier = models.TextField(_("Complete identifier"),
blank=True, null=True)
+ custom_index = models.IntegerField("Custom index", blank=True, null=True)
qrcode = models.ImageField(upload_to=get_image_path, blank=True, null=True,
max_length=255)
@@ -2707,9 +2711,67 @@ class CompleteIdentifierItem(models.Model, ImageContainerModel):
complete_identifier = getattr(self, cached_label_key)
return complete_identifier
+ def generate_custom_index(self, force=False):
+ if not self.pk:
+ return
+ if self.custom_index and not force:
+ return self.custom_index
+ SLUG = getattr(self, "SLUG", None)
+ if not SLUG:
+ return
+ k = SLUG + "_custom_index"
+ profile = get_current_profile()
+ if not hasattr(profile, k):
+ return
+ key = getattr(profile, k)
+ if not key or not key.strip():
+ return
+ keys = key.strip().split(";")
+ if len(key) == 1 and hasattr(self, "get_index_" + key): # custom index
+ # generation
+ return getattr(self, "get_index_" + key)()
+ model = self.__class__
+ try:
+ self_keys = set(
+ list(model.objects.filter(pk=self.pk).values_list(*keys)))
+ except Exception: # bad settings - not managed here
+ return
+ if len(self_keys) != 1: # key is not distinct
+ return
+ self_key = self_keys.pop()
+ return self._get_index(keys, self_key)
+
+ def _get_index(self, keys: list, self_keys: list):
+ model = self.__class__
+ q = model.objects
+ if self.pk:
+ q = model.objects.exclude(pk=self.pk)
+ for idx, key in enumerate(keys):
+ q = q.filter(**{key: self_keys[idx]})
+ try:
+ r = q.aggregate(max_index=Max('custom_index'))
+ except Exception: # bad settings
+ return
+ if not r['max_index']:
+ return 1
+ return r['max_index'] + 1
+
def save(self, *args, **kwargs):
- self.complete_identifier = self.generate_complete_identifier()
super(CompleteIdentifierItem, self).save(*args, **kwargs)
+ if getattr(self, "_prevent_loop", False):
+ return
+ modified = False
+ custom_index = self.generate_custom_index()
+ if custom_index != self.custom_index:
+ modified = True
+ self.custom_index = custom_index
+ complete_id = self.generate_complete_identifier()
+ if complete_id:
+ modified = True
+ self.complete_identifier = complete_id
+ if modified:
+ self._prevent_loop = True
+ self.save()
class SearchVectorConfig: