summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--archaeological_context_records/models.py35
-rw-r--r--archaeological_finds/migrations/0055_auto_20181227_1643.py75
-rw-r--r--archaeological_finds/models_finds.py20
-rw-r--r--archaeological_finds/templates/ishtar/sheet_find.html2
-rw-r--r--ishtar_common/models.py19
-rw-r--r--ishtar_common/templates/ishtar/blocks/window_field_flex_historized_multiple.html8
-rw-r--r--ishtar_common/templatetags/window_field.py29
-rw-r--r--ishtar_common/utils.py18
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()