diff options
| -rw-r--r-- | archaeological_context_records/models.py | 35 | ||||
| -rw-r--r-- | archaeological_finds/migrations/0055_auto_20181227_1643.py | 75 | ||||
| -rw-r--r-- | archaeological_finds/models_finds.py | 20 | ||||
| -rw-r--r-- | archaeological_finds/templates/ishtar/sheet_find.html | 2 | ||||
| -rw-r--r-- | ishtar_common/models.py | 19 | ||||
| -rw-r--r-- | ishtar_common/templates/ishtar/blocks/window_field_flex_historized_multiple.html | 8 | ||||
| -rw-r--r-- | ishtar_common/templatetags/window_field.py | 29 | ||||
| -rw-r--r-- | ishtar_common/utils.py | 18 | 
8 files changed, 200 insertions, 6 deletions
| diff --git a/archaeological_context_records/models.py b/archaeological_context_records/models.py index 82527acb1..cce36236c 100644 --- a/archaeological_context_records/models.py +++ b/archaeological_context_records/models.py @@ -17,12 +17,12 @@  # See the file COPYING for details. -import time +import datetime  from django.conf import settings  from django.contrib.gis.db import models  from django.core.urlresolvers import reverse -from django.db import connection, transaction +from django.db import connection  from django.db.models import Q  from django.db.models.signals import post_delete, post_save, m2m_changed  from django.utils.translation import ugettext_lazy as _, pgettext, \ @@ -84,6 +84,37 @@ class Dating(models.Model):              return unicode(self.period)          return u"%s (%s-%s)" % (self.period, start_date, end_date) +    SEP = u"$|£|$" +    HISTORY_ATTR = ["period", "start_date", "end_date", "dating_type", +                    "quality", "precise_dating"] + +    def history_compress(self): +        values = [] +        for attr in self.HISTORY_ATTR: +            val = getattr(self, attr) +            if hasattr(val, 'history_compress'): +                values.append(val.history_compress()) +            elif hasattr(val, 'isoformat'): +                values.append(val.isoformat()) +            else: +                values.append(unicode(val)) +        return self.SEP.join(values) + +    @classmethod +    def history_decompress(cls, value): +        if not value: +            value = "" +        res = {} +        for idx, val in enumerate(value.split(cls.SEP)): +            key = cls.HISTORY_ATTR[idx] +            if key in ("period", "dating_type", "quality"): +                field = cls._meta.get_field(key) +                val = field.to.model.objects.get(txt_idx=val) +            elif key in ("start_date", "end_date"): +                val = datetime.datetime.fromisoformat(val) +            res[key] = val +        return res +      @classmethod      def is_identical(cls, dating_1, dating_2):          """ diff --git a/archaeological_finds/migrations/0055_auto_20181227_1643.py b/archaeological_finds/migrations/0055_auto_20181227_1643.py new file mode 100644 index 000000000..094fbaf12 --- /dev/null +++ b/archaeological_finds/migrations/0055_auto_20181227_1643.py @@ -0,0 +1,75 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.10 on 2018-12-27 16:43 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + +    dependencies = [ +        ('archaeological_finds', '0054_migrate_main_image'), +    ] + +    operations = [ +        migrations.AddField( +            model_name='find', +            name='historical_communicabilities', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='find', +            name='historical_datings', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='find', +            name='historical_integrities', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='find', +            name='historical_material_types', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='find', +            name='historical_object_types', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='find', +            name='historical_remarkabilities', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='historicalfind', +            name='historical_communicabilities', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='historicalfind', +            name='historical_datings', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='historicalfind', +            name='historical_integrities', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='historicalfind', +            name='historical_material_types', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='historicalfind', +            name='historical_object_types', +            field=models.TextField(blank=True, null=True), +        ), +        migrations.AddField( +            model_name='historicalfind', +            name='historical_remarkabilities', +            field=models.TextField(blank=True, null=True), +        ), +    ] diff --git a/archaeological_finds/models_finds.py b/archaeological_finds/models_finds.py index 33ec2df0b..c7aec5dee 100644 --- a/archaeological_finds/models_finds.py +++ b/archaeological_finds/models_finds.py @@ -31,7 +31,8 @@ from django.utils.translation import ugettext_lazy as _, pgettext_lazy, \      activate, deactivate  from ishtar_common.data_importer import post_importer_action, ImporterError -from ishtar_common.utils import cached_label_changed, post_save_point +from ishtar_common.utils import cached_label_changed, post_save_point, \ +    m2m_historization_changed  from ishtar_common.alternative_configs import ALTERNATE_CONFIGS @@ -1044,6 +1045,10 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms,          ('warehouse', 'container__location__pk'),          ('site', 'base_finds__context_record__archaeological_site__pk')      ] +    HISTORICAL_M2M = [ +        'material_types', 'datings', 'object_types', 'integrities', +        'remarkabilities', 'communicabilities', +    ]      objects = ExternalIdManager()      # fields @@ -1069,6 +1074,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms,          MaterialType, verbose_name=_(u"Material types"), related_name='finds',          blank=True      ) +    historical_material_types = models.TextField(blank=True, null=True)      material_type_quality = models.ForeignKey(          MaterialTypeQualityType,          verbose_name=_(u"Material type quality"), related_name='finds', @@ -1088,6 +1094,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms,          verbose_name=_(u"Downstream treatment"), on_delete=models.SET_NULL)      datings = models.ManyToManyField(Dating, verbose_name=_(u"Dating"),                                       related_name='find') +    historical_datings = models.TextField(blank=True, null=True)      container = models.ForeignKey(          "archaeological_warehouse.Container", verbose_name=_(u"Container"),          blank=True, null=True, @@ -1103,6 +1110,7 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms,          ObjectType, verbose_name=_(u"Object types"), related_name='find',          blank=True      ) +    historical_object_types = models.TextField(blank=True, null=True)      object_type_quality = models.ForeignKey(          ObjectTypeQualityType,          verbose_name=_(u"Object type quality"), related_name='finds', @@ -1111,12 +1119,15 @@ class Find(BulkUpdatedItem, ValueGetter, BaseHistorizedItem, OwnPerms,      integrities = models.ManyToManyField(          IntegrityType, verbose_name=_(u"Integrity / interest"),          related_name='find', blank=True) +    historical_integrities = models.TextField(blank=True, null=True)      remarkabilities = models.ManyToManyField(          RemarkabilityType, verbose_name=_(u"Remarkability"),          related_name='find', blank=True) +    historical_remarkabilities = models.TextField(blank=True, null=True)      communicabilities = models.ManyToManyField(          CommunicabilityType, verbose_name=_(u"Communicability"),          related_name='find', blank=True) +    historical_communicabilities = models.TextField(blank=True, null=True)      min_number_of_individuals = models.IntegerField(          _(u"Minimum number of individuals (MNI)"), blank=True, null=True)      length = models.FloatField(_(u"Length (cm)"), blank=True, null=True) @@ -1951,7 +1962,8 @@ def base_find_find_changed(sender, **kwargs):      obj = kwargs.get('instance', None)      if not obj:          return -    # recalculate complete id and external id +    obj.skip_history_when_saving = True +    # recalculate cached_label, complete id and external id      obj.save() @@ -1960,6 +1972,10 @@ m2m_changed.connect(base_find_find_changed, sender=Find.base_finds.through)  m2m_changed.connect(document_attached_changed,                      sender=Find.documents.through) +for attr in Find.HISTORICAL_M2M: +    m2m_changed.connect(m2m_historization_changed, +                        sender=getattr(Find, attr).through) +  class Property(LightHistorizedItem):      find = models.ForeignKey(Find, verbose_name=_(u"Find")) diff --git a/archaeological_finds/templates/ishtar/sheet_find.html b/archaeological_finds/templates/ishtar/sheet_find.html index cfbefa306..1ff5e21f4 100644 --- a/archaeological_finds/templates/ishtar/sheet_find.html +++ b/archaeological_finds/templates/ishtar/sheet_find.html @@ -140,7 +140,7 @@        <div class='row'>            {% field_flex_full "Description" item.description "<pre>" "</pre>" %}            {% field_flex "Is complete?" item.is_complete %} -          {% field_flex_multiple "Material types" item.material_types %} +          {% field_flex_multiple_obj "Material types" item 'material_types' %}            {% field_flex "Material type quality" item.material_type_quality %}            {% field_flex_multiple "Object types" item.object_types %}            {% field_flex "Object type quality" item.object_type_quality %} diff --git a/ishtar_common/models.py b/ishtar_common/models.py index e1318ef62..2915c4997 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -69,7 +69,7 @@ from ishtar_common.models_imports import ImporterModel, ImporterType, \      Import, TargetKeyGroup  from ishtar_common.utils import get_cache, disable_for_loaddata, create_slug, \      get_all_field_names, merge_tsvectors, cached_label_changed, \ -    generate_relation_graph +    generate_relation_graph, HISTORY_M2M_SPLIT  __all__ = [      'ImporterModel', 'ImporterType', 'ImporterDefault', 'ImporterDefaultValues', @@ -507,6 +507,21 @@ class GeneralType(Cached, models.Model):      def natural_key(self):          return (self.txt_idx,) +    def history_compress(self): +        return self.txt_idx + +    @classmethod +    def history_decompress(cls, value=""): +        if not value: +            value = "" +        res = [] +        for txt_idx in value.split(HISTORY_M2M_SPLIT): +            try: +                res.append(cls.objects.get(txt_idx=txt_idx)) +            except cls.DoesNotExist: +                continue +        return res +      @property      def explicit_label(self):          return u"{} ({})".format(self.label, self._meta.verbose_name) @@ -1433,6 +1448,8 @@ class BaseHistorizedItem(DocumentItem, FullSearch, Imported, JsonData,      IS_BASKET = False      EXTERNAL_ID_KEY = ''      EXTERNAL_ID_DEPENDENCIES = [] +    HISTORICAL_M2M = [] +      history_modifier = models.ForeignKey(          User, related_name='+', on_delete=models.SET_NULL,          verbose_name=_(u"Last editor"), blank=True, null=True) diff --git a/ishtar_common/templates/ishtar/blocks/window_field_flex_historized_multiple.html b/ishtar_common/templates/ishtar/blocks/window_field_flex_historized_multiple.html new file mode 100644 index 000000000..a68bd0cb4 --- /dev/null +++ b/ishtar_common/templates/ishtar/blocks/window_field_flex_historized_multiple.html @@ -0,0 +1,8 @@ +{% load i18n %}{% if data %} +<dl class="col-12 {% if size == 2 %}col-lg-6{% else %}col-md-6 col-lg-4{% endif %} d-flex flex-wrap row"> +    <dt class="col-5">{% trans caption %}</dt> +    <dd class="col-7">{% for d in data %} +        {% if forloop.counter0 %} ; {% endif %}{{ d }} +    {% endfor %}</dd> +</dl> +{% endif %} diff --git a/ishtar_common/templatetags/window_field.py b/ishtar_common/templatetags/window_field.py index a5bae3b72..30a711ed9 100644 --- a/ishtar_common/templatetags/window_field.py +++ b/ishtar_common/templatetags/window_field.py @@ -95,6 +95,27 @@ def field_multiple(caption, data, li=False, size=None):      return {'caption': caption, 'data': data, 'li': li, "size": size} +from django.template import Library, loader, Context + + +@register.simple_tag +def field_multiple_obj(caption, item, attr, li=False, size=None): +    data = getattr(item, attr) +    if not hasattr(item, '_step') or not hasattr(item, 'historical_' + attr): +        t = loader.get_template('ishtar/blocks/window_field_flex_multiple.html') +        return t.render( +            {'caption': caption, 'data': data, 'li': li, "size": size} +        ) +    rel_model = data.model +    data = getattr(item, 'historical_' + attr) +    data = rel_model.history_decompress(data) +    t = loader.get_template( +        'ishtar/blocks/window_field_flex_historized_multiple.html') +    return t.render( +        {'caption': caption, 'data': data, 'li': li, "size": size} +    ) + +  @register.inclusion_tag('ishtar/blocks/window_field_multiple.html')  def field_li_multiple(caption, data):      return field_multiple(caption, data, li=True) @@ -108,6 +129,14 @@ def field_flex_multiple(caption, data, small=False):      return field_multiple(caption, data, size=size) +@register.simple_tag +def field_flex_multiple_obj(caption, item, attr, small=False): +    size = None +    if small: +        size = 2 +    return field_multiple_obj(caption, item, attr, size=size) + +  @register.inclusion_tag('ishtar/blocks/window_field_flex_multiple_full.html')  def field_flex_multiple_full(caption, data, small=False):      size = None diff --git a/ishtar_common/utils.py b/ishtar_common/utils.py index ff67fc470..94e71c655 100644 --- a/ishtar_common/utils.py +++ b/ishtar_common/utils.py @@ -929,3 +929,21 @@ def get_urls_for_model(model, views, own=False, autocomplete=False,          ]      return urls + + +HISTORY_M2M_SPLIT = u"*||*" + + +def m2m_historization_changed(sender, **kwargs): +    obj = kwargs.get('instance', None) +    if not obj: +        return +    for attr in obj.HISTORICAL_M2M: +        values = [] +        for value in getattr(obj, attr).all(): +            if not hasattr(value, "history_compress"): +                continue +            values.append(value.history_compress()) +        setattr(obj, 'historical_' + attr, HISTORY_M2M_SPLIT.join(values)) +    obj.skip_history_when_saving = True +    obj.save() | 
