diff options
| -rw-r--r-- | archaeological_context_records/migrations/0105_auto_20201117_0759.py | 25 | ||||
| -rw-r--r-- | archaeological_context_records/tests.py | 54 | ||||
| -rw-r--r-- | archaeological_files/migrations/0104_auto_20201117_0759.py | 25 | ||||
| -rw-r--r-- | archaeological_finds/migrations/0107_auto_20201117_0759.py | 35 | ||||
| -rw-r--r-- | archaeological_finds/models_finds.py | 11 | ||||
| -rw-r--r-- | archaeological_operations/migrations/0105_auto_20201117_0759.py | 35 | ||||
| -rw-r--r-- | archaeological_warehouse/migrations/0106_auto_20201117_0759.py | 30 | ||||
| -rw-r--r-- | archaeological_warehouse/models.py | 5 | ||||
| -rw-r--r-- | ishtar_common/migrations/0207_auto_20201117_1021.py | 70 | ||||
| -rw-r--r-- | ishtar_common/models.py | 51 | ||||
| -rw-r--r-- | ishtar_common/models_common.py | 84 | 
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:  | 
