diff options
author | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-03-19 11:23:36 +0100 |
---|---|---|
committer | Étienne Loks <etienne.loks@iggdrasil.net> | 2021-03-19 11:23:36 +0100 |
commit | fe8b8f657a4640bdc814651ef11aced916fdc9e3 (patch) | |
tree | cc628849cc6a15d19d68f8d0f0d953b1e2e833c0 /archaeological_warehouse/models.py | |
parent | ced270d071384046eb3b9a85572dc817c7ef042c (diff) | |
download | Ishtar-fe8b8f657a4640bdc814651ef11aced916fdc9e3.tar.bz2 Ishtar-fe8b8f657a4640bdc814651ef11aced916fdc9e3.zip |
Format - black: warehouse
Diffstat (limited to 'archaeological_warehouse/models.py')
-rw-r--r-- | archaeological_warehouse/models.py | 1049 |
1 files changed, 591 insertions, 458 deletions
diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index fc0184990..29615b6ef 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -1,4 +1,4 @@ -#!/usr/bin/env python +#!/usr/bin/env python3 # -*- coding: utf-8 -*- # Copyright (C) 2012-2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> @@ -27,24 +27,38 @@ from django.contrib.postgres.indexes import GinIndex from django.core.exceptions import ObjectDoesNotExist from django.core.urlresolvers import reverse from django.db.models import Q, Max, Count -from django.db.models.signals import post_save, post_delete, m2m_changed, \ - pre_delete +from django.db.models.signals import post_save, post_delete, m2m_changed, pre_delete from django.template.defaultfilters import slugify from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy from django.apps import apps -from ishtar_common.data_importer import post_importer_action, \ - pre_importer_action +from ishtar_common.data_importer import post_importer_action, pre_importer_action from ishtar_common.model_managers import ExternalIdManager, UUIDModelManager from ishtar_common.models import ValueGetter, get_current_profile -from ishtar_common.models_common import GeneralType, \ - LightHistorizedItem, OwnPerms, Address, post_save_cache, \ - DashboardFormItem, document_attached_changed, SearchAltName, \ - DynamicRequest, GeoItem, CompleteIdentifierItem, SearchVectorConfig, \ - DocumentItem, QuickAction, MainItem, Merge +from ishtar_common.models_common import ( + GeneralType, + LightHistorizedItem, + OwnPerms, + Address, + post_save_cache, + DashboardFormItem, + document_attached_changed, + SearchAltName, + DynamicRequest, + GeoItem, + CompleteIdentifierItem, + SearchVectorConfig, + DocumentItem, + QuickAction, + MainItem, + Merge, +) from ishtar_common.model_merging import merge_model_objects -from ishtar_common.utils import cached_label_changed, \ - cached_label_and_geo_changed, get_generated_id +from ishtar_common.utils import ( + cached_label_changed, + cached_label_and_geo_changed, + get_generated_id, +) from ishtar_common.data_importer import ImporterError @@ -81,7 +95,7 @@ class DivisionContainer(DashboardFormItem): def number_divisions(self): q = { self.BASE_QUERY_LOCATION + "__id": self.pk, - "container_type__stationary": True + "container_type__stationary": True, } return Container.objects.filter(**q).count() @@ -89,7 +103,7 @@ class DivisionContainer(DashboardFormItem): def number_containers(self): q = { self.BASE_QUERY_LOCATION + "__id": self.pk, - "container_type__stationary": False + "container_type__stationary": False, } return Container.objects.filter(**q).count() @@ -111,27 +125,30 @@ class DivisionContainer(DashboardFormItem): @property def number_of_containers(self): - return Container.objects.filter( - **{self.BASE_QUERY_LOCATION: self}).count() + return Container.objects.filter(**{self.BASE_QUERY_LOCATION: self}).count() def _number_of_finds_by_place(self): Find = apps.get_model("archaeological_finds", "Find") return self._number_of_items_by_place( - Find, division_key='inside_container__container__') + Find, division_key="inside_container__container__" + ) @property def number_of_finds_by_place(self, update=False): - return self._get_or_set_stats('_number_of_finds_by_place', update, - expected_type=list) + return self._get_or_set_stats( + "_number_of_finds_by_place", update, expected_type=list + ) def _number_of_containers_by_place(self): return self._number_of_items_by_place( - ContainerTree, 'container_parent__', 'container__children') + ContainerTree, "container_parent__", "container__children" + ) @property def number_of_containers_by_place(self, update=False): - return self._get_or_set_stats('_number_of_containers_by_place', update, - expected_type=list) + return self._get_or_set_stats( + "_number_of_containers_by_place", update, expected_type=list + ) def _get_divisions(self, current_path, remaining_division, depth=0): if not remaining_division: @@ -144,7 +161,7 @@ class DivisionContainer(DashboardFormItem): base_q = Container.objects.filter(**{query_location: self}) q = base_q - if self.BASE_QUERY_LOCATION == 'location': + if self.BASE_QUERY_LOCATION == "location": exclude = "parent_" for idx in range(depth): exclude += "_parent_" @@ -161,31 +178,28 @@ class DivisionContainer(DashboardFormItem): if not q.count(): return [current_path] q = q.values( - 'id', 'reference', 'container_type__label', 'container_type_id' - ).order_by('container_type__label', 'reference') + "id", "reference", "container_type__label", "container_type_id" + ).order_by("container_type__label", "reference") for ref in q.all(): - if ref['reference'] == old_ref and \ - ref["container_type__label"] == ct: + if ref["reference"] == old_ref and ref["container_type__label"] == ct: continue - old_ref = ref['reference'] + old_ref = ref["reference"] ct = ref["container_type__label"] cpath = current_path[:] lbl = self.DIVISION_TEMPLATE.format( - id=ref["id"], container=ref["container_type__label"], - ref=ref['reference']) + id=ref["id"], + container=ref["container_type__label"], + ref=ref["reference"], + ) cpath.append((ref["id"], lbl)) query = { - "containers__parent__reference": ref['reference'], - "containers__parent__container_type_id": ref[ - "container_type_id"], - "containers__" + self.BASE_QUERY_LOCATION: self + "containers__parent__reference": ref["reference"], + "containers__parent__container_type_id": ref["container_type_id"], + "containers__" + self.BASE_QUERY_LOCATION: self, } - remaining_division = list( - ContainerType.objects.filter( - **query).distinct()) - for r in self._get_divisions(cpath, remaining_division[:], - depth + 1): + remaining_division = list(ContainerType.objects.filter(**query).distinct()) + for r in self._get_divisions(cpath, remaining_division[:], depth + 1): res.append(r) return res @@ -195,13 +209,10 @@ class DivisionContainer(DashboardFormItem): :return: ordered list of available paths. Each path is a list of tuple with the container type and the full reference. """ - q = { - "containers__" + self.BASE_QUERY_LOCATION: self - } - if self.BASE_QUERY_LOCATION == 'location': + q = {"containers__" + self.BASE_QUERY_LOCATION: self} + if self.BASE_QUERY_LOCATION == "location": q["containers__parent"] = None - top_divisions = list( - ContainerType.objects.filter(**q).distinct()) + top_divisions = list(ContainerType.objects.filter(**q).distinct()) divisions = self._get_divisions([], top_divisions) return divisions @@ -218,9 +229,7 @@ class DivisionContainer(DashboardFormItem): for idx, p in enumerate(reversed(cpath)): container_id, __ = p div_key = division_key + "parent__" * idx - attrs = { - div_key + "id": container_id - } + attrs = {div_key + "id": container_id} q = q.filter(**attrs) if count_filter: q = q.filter(**{count_filter: None}) @@ -236,10 +245,10 @@ class DivisionContainer(DashboardFormItem): final_res.append(current_res[:]) current_res = [] depth = len(path) - if path[-1] == '-': + if path[-1] == "-": continue path = [k[1] for k in path] - path = path + ['' for __ in range(len_divisions - len(path))] + path = path + ["" for __ in range(len_divisions - len(path))] current_res.append((path, nb)) final_res.append(current_res[:]) return final_res @@ -249,25 +258,32 @@ class WarehouseType(GeneralType): class Meta: verbose_name = _("Warehouse type") verbose_name_plural = _("Warehouse types") - ordering = ('label',) + ordering = ("label",) post_save.connect(post_save_cache, sender=WarehouseType) post_delete.connect(post_save_cache, sender=WarehouseType) -NO_DIVISION_ERROR = _( - "The division number {} has not been set for the warehouse {}.") +NO_DIVISION_ERROR = _("The division number {} has not been set for the warehouse {}.") -class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, - OwnPerms, MainItem, DivisionContainer, ValueGetter): - SLUG = 'warehouse' +class Warehouse( + Address, + DocumentItem, + GeoItem, + CompleteIdentifierItem, + OwnPerms, + MainItem, + DivisionContainer, + ValueGetter, +): + SLUG = "warehouse" APP = "archaeological-warehouse" MODEL = "warehouse" - SHOW_URL = 'show-warehouse' - DELETE_URL = 'delete-warehouse' - TABLE_COLS = ['name', 'warehouse_type__label'] + SHOW_URL = "show-warehouse" + DELETE_URL = "delete-warehouse" + TABLE_COLS = ["name", "warehouse_type__label"] NEW_QUERY_ENGINE = True BASE_SEARCH_VECTORS = [ SearchVectorConfig("name"), @@ -278,7 +294,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, SearchVectorConfig("comment", "local"), ] COL_LABELS = { - 'warehouse_type__label': _("Type"), + "warehouse_type__label": _("Type"), } EXTRA_REQUEST_KEYS = { @@ -288,28 +304,28 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, } # alternative names of fields for searches ALT_NAMES = { - 'name': SearchAltName( - pgettext_lazy("key for text search", "name"), - 'name__iexact' + "name": SearchAltName( + pgettext_lazy("key for text search", "name"), "name__iexact" ), - 'warehouse_type': SearchAltName( + "warehouse_type": SearchAltName( pgettext_lazy("key for text search", "type"), - 'warehouse_type__label__iexact' + "warehouse_type__label__iexact", + ), + "town": SearchAltName( + pgettext_lazy("key for text search", "town"), + "precise_town__cached_label__iexact", ), - 'town': - SearchAltName( - pgettext_lazy("key for text search", "town"), - 'precise_town__cached_label__iexact' - ), } GEO_LABEL = "name" DOWN_MODEL_UPDATE = ["containers"] CACHED_LABELS = [] QA_LOCK = QuickAction( - url="warehouse-qa-lock", icon_class="fa fa-lock", - text=_("Lock/Unlock"), target="many", - rights=['change_warehouse', 'change_own_warehouse'] + url="warehouse-qa-lock", + icon_class="fa fa-lock", + text=_("Lock/Unlock"), + target="many", + rights=["change_warehouse", "change_own_warehouse"], ) QUICK_ACTIONS = [QA_LOCK] @@ -317,35 +333,53 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, uuid = models.UUIDField(default=uuid.uuid4) name = models.CharField(_("Name"), max_length=200) - warehouse_type = models.ForeignKey(WarehouseType, - verbose_name=_("Warehouse type")) + warehouse_type = models.ForeignKey(WarehouseType, verbose_name=_("Warehouse type")) person_in_charge = models.ForeignKey( - "ishtar_common.Person", on_delete=models.SET_NULL, - related_name='warehouse_in_charge', - verbose_name=_("Person in charge"), null=True, blank=True) + "ishtar_common.Person", + on_delete=models.SET_NULL, + related_name="warehouse_in_charge", + verbose_name=_("Person in charge"), + null=True, + blank=True, + ) organization = models.ForeignKey( - "ishtar_common.Organization", blank=True, null=True, - related_name='warehouses', verbose_name=_("Organization"), - on_delete=models.SET_NULL) + "ishtar_common.Organization", + blank=True, + null=True, + related_name="warehouses", + verbose_name=_("Organization"), + on_delete=models.SET_NULL, + ) comment = models.TextField(_("Comment"), blank=True, default="") associated_divisions = models.ManyToManyField( - 'WarehouseDivision', verbose_name=_("Divisions"), blank=True, - through='WarehouseDivisionLink' + "WarehouseDivision", + verbose_name=_("Divisions"), + blank=True, + through="WarehouseDivisionLink", ) documents = models.ManyToManyField( - "ishtar_common.Document", related_name='warehouses', + "ishtar_common.Document", + related_name="warehouses", verbose_name=_("Documents"), - blank=True) + blank=True, + ) main_image = models.ForeignKey( - "ishtar_common.Document", related_name='main_image_warehouses', + "ishtar_common.Document", + related_name="main_image_warehouses", on_delete=models.SET_NULL, - verbose_name=_("Main image"), blank=True, null=True) + verbose_name=_("Main image"), + blank=True, + null=True, + ) external_id = models.TextField(_("External ID"), blank=True, default="") auto_external_id = models.BooleanField( - _("External ID is set automatically"), default=False) + _("External ID is set automatically"), default=False + ) max_division_number = models.IntegerField( - _("Maximum number of divisions"), default=0, - help_text=_("Automatically generated")) + _("Maximum number of divisions"), + default=0, + help_text=_("Automatically generated"), + ) SUB_ADDRESSES = ["organization", "person_in_charge"] class Meta: @@ -359,7 +393,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, ("delete_own_warehouse", "Can delete own Warehouse"), ) indexes = [ - GinIndex(fields=['data']), + GinIndex(fields=["data"]), ] def __str__(self): @@ -373,8 +407,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, :param place: place number :return: container type, other location or None, None """ - q = WarehouseDivisionLink.objects.filter( - warehouse=self).order_by('order') + q = WarehouseDivisionLink.objects.filter(warehouse=self).order_by("order") previous_container_types = [] for idx, division_link in enumerate(q.all()): if idx == place: @@ -388,6 +421,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, @post_importer_action def add_localisations(self, context, value): self._add_localisations(context, value) + add_localisations.post_save = True def _add_localisations(self, context, value, return_errors=False): @@ -415,17 +449,20 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, values = value.split(";") - divisions = list(WarehouseDivisionLink.objects.filter( - warehouse=self).order_by('order')) + divisions = list( + WarehouseDivisionLink.objects.filter(warehouse=self).order_by("order") + ) parent = None for idx, value in enumerate(values): if idx >= len(divisions): if return_errors: return str( - _("{} values for only {} default divisions set for " - "warehouse {}")).format( - len(values), len(divisions), self.name) + _( + "{} values for only {} default divisions set for " + "warehouse {}" + ) + ).format(len(values), len(divisions), self.name) return value = value.replace(TMP_SEMI_COLON, ";").strip() if not value or value == "-": @@ -434,7 +471,8 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, location=self, reference=value, container_type_id=divisions[idx].container_type_id, - parent=parent) + parent=parent, + ) if created and import_object: parent.imports.add(import_object) @@ -443,7 +481,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, return self.name def natural_key(self): - return (self.uuid, ) + return (self.uuid,) def _get_base_image_path(self): return "{}/{}".format(self.SLUG, self.external_id) @@ -462,8 +500,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, orga_type = q.all()[0] else: orga_type, __ = OrganizationType.objects.get_or_create( - txt_idx="undefined", - defaults={"label": _("Undefined")} + txt_idx="undefined", defaults={"label": _("Undefined")} ) dct_orga["organization_type"] = orga_type dct_orga["name"] = self.name @@ -491,53 +528,52 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, @property def default_location_types(self): return [ - wd.container_type.label - for wd in WarehouseDivisionLink.objects.filter( - warehouse=self).order_by('order').all() if wd.container_type + wd.container_type.label + for wd in WarehouseDivisionLink.objects.filter(warehouse=self) + .order_by("order") + .all() + if wd.container_type ] @property def associated_filename(self): - return datetime.date.today().strftime('%Y-%m-%d') + '-' + \ - slugify(str(self)) + return datetime.date.today().strftime("%Y-%m-%d") + "-" + slugify(str(self)) @classmethod def get_query_owns(cls, ishtaruser): - return cls._construct_query_own( - '', cls._get_query_owns_dicts(ishtaruser)) + return cls._construct_query_own("", cls._get_query_owns_dicts(ishtaruser)) @classmethod def _get_query_owns_dicts(cls, ishtaruser): - return [{'person_in_charge__ishtaruser': ishtaruser}] + return [{"person_in_charge__ishtaruser": ishtaruser}] def merge(self, item, keep_old=False): # do not recreate missing divisions available_divisions = [ - wd.division - for wd in WarehouseDivisionLink.objects.filter(warehouse=self) + wd.division for wd in WarehouseDivisionLink.objects.filter(warehouse=self) ] for container in list(item.containers.all()): container.location = self container.save() - for loca in ContainerLocalisation.objects.filter( - container=container).all(): + for loca in ContainerLocalisation.objects.filter(container=container).all(): if loca.division.division in available_divisions: div = WarehouseDivisionLink.objects.get( - warehouse=self, - division=loca.division.division + warehouse=self, division=loca.division.division ) ContainerLocalisation.objects.create( - container=container, division=div, - reference=loca.reference + container=container, division=div, reference=loca.reference ) loca.delete() container.save() # force label regeneration for container in list(item.containers.all()): - if Container.objects.filter(index=container.index, - location=self).count(): - container.index = Container.objects.filter( - location=self).exclude(id=container.id).all().aggregate( - Max("index"))["index__max"] + 1 + if Container.objects.filter(index=container.index, location=self).count(): + container.index = ( + Container.objects.filter(location=self) + .exclude(id=container.id) + .all() + .aggregate(Max("index"))["index__max"] + + 1 + ) container.location = self container.save() for wdiv in WarehouseDivisionLink.objects.filter(warehouse=item).all(): @@ -550,7 +586,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, self.skip_history_when_saving = True if not self.external_id or self.auto_external_id: - external_id = get_generated_id('warehouse_external_id', self) + external_id = get_generated_id("warehouse_external_id", self) if external_id != self.external_id: self.auto_external_id = True self.external_id = external_id @@ -559,8 +595,7 @@ class Warehouse(Address, DocumentItem, GeoItem, CompleteIdentifierItem, return -m2m_changed.connect(document_attached_changed, - sender=Warehouse.documents.through) +m2m_changed.connect(document_attached_changed, sender=Warehouse.documents.through) post_save.connect(cached_label_and_geo_changed, sender=Warehouse) @@ -577,28 +612,35 @@ post_delete.connect(post_save_cache, sender=WarehouseDivision) class WarehouseDivisionLinkManager(models.Manager): def get_by_natural_key(self, warehouse, container_type): - return self.get(warehouse__uuid=warehouse, - container_type__txt_idx=container_type) + return self.get( + warehouse__uuid=warehouse, container_type__txt_idx=container_type + ) class ContainerType(GeneralType): stationary = models.BooleanField( - _("Stationary"), default=False, - help_text=_("Container that will not usually be moved. Ex: building, " - "room, span, shelf.")) + _("Stationary"), + default=False, + help_text=_( + "Container that will not usually be moved. Ex: building, " + "room, span, shelf." + ), + ) length = models.IntegerField(_("Length (mm)"), blank=True, null=True) width = models.IntegerField(_("Width (mm)"), blank=True, null=True) height = models.IntegerField(_("Height (mm)"), blank=True, null=True) volume = models.FloatField(_("Volume (l)"), blank=True, null=True) tare_weight = models.FloatField(_("Tare weight (g)"), blank=True, null=True) - reference = models.CharField(_("Ref."), max_length=300, blank=True, - null=True) + reference = models.CharField(_("Ref."), max_length=300, blank=True, null=True) order = models.IntegerField(_("Order"), default=10) class Meta: verbose_name = _("Container type") verbose_name_plural = _("Container types") - ordering = ('order', 'label',) + ordering = ( + "order", + "label", + ) post_save.connect(post_save_cache, sender=ContainerType) @@ -608,18 +650,18 @@ post_delete.connect(post_save_cache, sender=ContainerType) class WarehouseDivisionLink(models.Model): RELATED_SET_NAME = "divisions" RELATED_ATTRS = ["order", "container_type"] - RELATIVE_MODELS = {Warehouse: 'warehouse'} - warehouse = models.ForeignKey(Warehouse, related_name='divisions') + RELATIVE_MODELS = {Warehouse: "warehouse"} + warehouse = models.ForeignKey(Warehouse, related_name="divisions") container_type = models.ForeignKey(ContainerType, blank=True, null=True) division = models.ForeignKey( - WarehouseDivision, help_text=_("Deprecated - do not use"), - blank=True, null=True) + WarehouseDivision, help_text=_("Deprecated - do not use"), blank=True, null=True + ) order = models.IntegerField(_("Order"), default=10) objects = WarehouseDivisionLinkManager() class Meta: - ordering = ('warehouse', 'order') - unique_together = ('warehouse', 'division') + ordering = ("warehouse", "order") + unique_together = ("warehouse", "division") def __str__(self): return "{} - {}".format(self.warehouse, self.container_type) @@ -682,31 +724,47 @@ class ContainerTree(models.Model): DROP VIEW IF EXISTS containers_tree; """ container = models.OneToOneField( - "archaeological_warehouse.Container", verbose_name=_("Container"), - related_name="container_tree_child", primary_key=True) + "archaeological_warehouse.Container", + verbose_name=_("Container"), + related_name="container_tree_child", + primary_key=True, + ) container_parent = models.ForeignKey( "archaeological_warehouse.Container", verbose_name=_("Container parent"), - related_name="container_tree_parent") + related_name="container_tree_parent", + ) class Meta: managed = False - db_table = 'containers_tree' - - -class Container(DocumentItem, Merge, LightHistorizedItem, - CompleteIdentifierItem, GeoItem, OwnPerms, MainItem, - DivisionContainer, ValueGetter): - SLUG = 'container' + db_table = "containers_tree" + + +class Container( + DocumentItem, + Merge, + LightHistorizedItem, + CompleteIdentifierItem, + GeoItem, + OwnPerms, + MainItem, + DivisionContainer, + ValueGetter, +): + SLUG = "container" APP = "archaeological-warehouse" MODEL = "container" - SHOW_URL = 'show-container' - DELETE_URL = 'delete-container' + SHOW_URL = "show-container" + DELETE_URL = "delete-container" NEW_QUERY_ENGINE = True - TABLE_COLS = ['container_type__label', 'reference', - 'location__name', - 'cached_division', 'old_reference'] - IMAGE_PREFIX = 'containers/' + TABLE_COLS = [ + "container_type__label", + "reference", + "location__name", + "cached_division", + "old_reference", + ] + IMAGE_PREFIX = "containers/" BASE_SEARCH_VECTORS = [ SearchVectorConfig("reference"), SearchVectorConfig("container_type__label"), @@ -720,210 +778,208 @@ class Container(DocumentItem, Merge, LightHistorizedItem, ] PARENT_SEARCH_VECTORS = ["parent"] - STATISTIC_MODALITIES_OPTIONS = OrderedDict([ - ("location__name", _("Location (warehouse)")), - ("responsibility__name", _("Responsibility (warehouse)")), - ('finds__base_finds__context_record__operation__cached_label', - _("Operation")), - ]) - STATISTIC_MODALITIES = [ - key for key, lbl in STATISTIC_MODALITIES_OPTIONS.items()] + STATISTIC_MODALITIES_OPTIONS = OrderedDict( + [ + ("location__name", _("Location (warehouse)")), + ("responsibility__name", _("Responsibility (warehouse)")), + ( + "finds__base_finds__context_record__operation__cached_label", + _("Operation"), + ), + ] + ) + STATISTIC_MODALITIES = [key for key, lbl in STATISTIC_MODALITIES_OPTIONS.items()] GET_VALUES_EXCLUDE_FIELDS = ValueGetter.GET_VALUES_EXCLUDE_FIELDS + [ - "inside_container", "parent"] + "inside_container", + "parent", + ] # search parameters EXTRA_REQUEST_KEYS = { - 'location': 'location__pk', - 'location__name': "location__name", - 'location_id': 'location__pk', - 'responsibility_id': 'responsibility__pk', - 'container_type': 'container_type__pk', - 'reference': 'reference__icontains', - 'old_reference': 'old_reference__icontains', - 'finds__base_finds__context_record__operation': - 'finds__base_finds__context_record__operation', - 'finds__base_finds__context_record': - 'finds__base_finds__context_record', - 'finds': 'finds', - 'container_type__label': 'container_type__label', - + "location": "location__pk", + "location__name": "location__name", + "location_id": "location__pk", + "responsibility_id": "responsibility__pk", + "container_type": "container_type__pk", + "reference": "reference__icontains", + "old_reference": "old_reference__icontains", + "finds__base_finds__context_record__operation": "finds__base_finds__context_record__operation", + "finds__base_finds__context_record": "finds__base_finds__context_record", + "finds": "finds", + "container_type__label": "container_type__label", # dynamic tables - 'container_tree_child__container_parent__id': - 'container_tree_child__container_parent__id' + "container_tree_child__container_parent__id": "container_tree_child__container_parent__id", } COL_LABELS = { - 'cached_location': _("Location - index"), - 'cached_division': _("Precise localisation"), - 'container_type__label': _("Type"), - "location__name": _("Warehouse") + "cached_location": _("Location - index"), + "cached_division": _("Precise localisation"), + "container_type__label": _("Type"), + "location__name": _("Warehouse"), } GEO_LABEL = "cached_label" - CACHED_LABELS = ['cached_division', 'cached_label', 'cached_location', - 'cached_weight'] + CACHED_LABELS = [ + "cached_division", + "cached_label", + "cached_location", + "cached_weight", + ] # alternative names of fields for searches ALT_NAMES = { - 'location_name': SearchAltName( - pgettext_lazy("key for text search", "location"), - 'location__name__iexact' + "location_name": SearchAltName( + pgettext_lazy("key for text search", "location"), "location__name__iexact" ), - 'responsibility_name': SearchAltName( + "responsibility_name": SearchAltName( pgettext_lazy("key for text search", "responsibility"), - 'responsibility__name__iexact' + "responsibility__name__iexact", ), - 'container_type': SearchAltName( + "container_type": SearchAltName( pgettext_lazy("key for text search", "type"), - 'container_type__label__iexact' + "container_type__label__iexact", ), - 'reference': SearchAltName( - pgettext_lazy("key for text search", "reference"), - 'reference__iexact' + "reference": SearchAltName( + pgettext_lazy("key for text search", "reference"), "reference__iexact" ), - 'old_reference': SearchAltName( + "old_reference": SearchAltName( pgettext_lazy("key for text search", "old-reference"), - 'old_reference__iexact' + "old_reference__iexact", ), - 'comment': SearchAltName( - pgettext_lazy("key for text search", "comment"), - 'comment__iexact' + "comment": SearchAltName( + pgettext_lazy("key for text search", "comment"), "comment__iexact" ), - 'operation_town': - SearchAltName( - pgettext_lazy("key for text search", "operation-town"), - 'finds__base_finds__context_record__operation__' - 'towns__cached_label__iexact' - ), - 'operation_scientist': - SearchAltName( - pgettext_lazy("key for text search", "operation-scientist"), - 'finds__base_finds__context_record__operation__' - 'scientist__cached_label__iexact' - ), - 'code_patriarche': - SearchAltName( - pgettext_lazy("key for text search", "code-patriarche"), - 'finds__base_finds__context_record__operation__' - 'code_patriarche__iexact' - ), - 'archaeological_sites': - SearchAltName( - pgettext_lazy("key for text search", "site"), - 'finds__base_finds__context_record__operation__' - 'archaeological_sites__cached_label__icontains'), - 'archaeological_sites_name': - SearchAltName( - pgettext_lazy("key for text search", "site-name"), - 'finds__base_finds__context_record__operation__' - 'archaeological_sites__name__iexact'), - 'archaeological_sites_context_record': - SearchAltName( - pgettext_lazy("key for text search", "context-record-site"), - 'finds__base_finds__context_record__archaeological_site__' - 'cached_label__icontains'), - 'archaeological_sites_context_record_name': - SearchAltName( - pgettext_lazy("key for text search", - "context-record-site-name"), - 'finds__base_finds__context_record__archaeological_site__' - 'name__iexact'), - 'context_record': - SearchAltName( - pgettext_lazy("key for text search", "context-record"), - 'finds__base_finds__context_record__cached_label__icontains'), - 'find_label': - SearchAltName( - pgettext_lazy("key for text search", "find-label"), - 'finds__label__icontains'), - 'find_denomination': - SearchAltName( - pgettext_lazy("key for text search", "find-denomination"), - 'finds__denomination__icontains'), - 'material_types': - SearchAltName( - pgettext_lazy("key for text search", "material"), - 'finds__material_types__label__iexact'), - 'object_types': - SearchAltName( - pgettext_lazy("key for text search", "object-type"), - 'finds__object_types__label__iexact'), - 'preservation_to_considers': - SearchAltName( - pgettext_lazy("key for text search", "preservation"), - 'finds__preservation_to_considers__label__iexact'), - 'conservatory_state': - SearchAltName( - pgettext_lazy("key for text search", "conservatory"), - 'finds__conservatory_state__label__iexact'), - 'integrities': - SearchAltName( - pgettext_lazy("key for text search", "integrity"), - 'finds__integrities__label__iexact'), - 'remarkabilities': - SearchAltName( - pgettext_lazy("key for text search", "remarkability"), - 'finds__remarkabilities__label__iexact'), - 'alterations': - SearchAltName( - pgettext_lazy("key for text search", "alterations"), - 'finds__alterations__label__iexact'), - 'alteration_causes': - SearchAltName( - pgettext_lazy("key for text search", "alteration-causes"), - 'finds__alteration_causes__label__iexact'), - 'treatment_emergency': - SearchAltName( - pgettext_lazy("key for text search", "treatment-emergency"), - 'finds__treatment_emergency__label__iexact'), - 'description': - SearchAltName( - pgettext_lazy("key for text search", "find-description"), - 'finds__description__iexact'), - 'empty': SearchAltName( - pgettext_lazy("key for text search", "empty"), - 'finds' + "operation_town": SearchAltName( + pgettext_lazy("key for text search", "operation-town"), + "finds__base_finds__context_record__operation__" + "towns__cached_label__iexact", + ), + "operation_scientist": SearchAltName( + pgettext_lazy("key for text search", "operation-scientist"), + "finds__base_finds__context_record__operation__" + "scientist__cached_label__iexact", + ), + "code_patriarche": SearchAltName( + pgettext_lazy("key for text search", "code-patriarche"), + "finds__base_finds__context_record__operation__" "code_patriarche__iexact", + ), + "archaeological_sites": SearchAltName( + pgettext_lazy("key for text search", "site"), + "finds__base_finds__context_record__operation__" + "archaeological_sites__cached_label__icontains", + ), + "archaeological_sites_name": SearchAltName( + pgettext_lazy("key for text search", "site-name"), + "finds__base_finds__context_record__operation__" + "archaeological_sites__name__iexact", + ), + "archaeological_sites_context_record": SearchAltName( + pgettext_lazy("key for text search", "context-record-site"), + "finds__base_finds__context_record__archaeological_site__" + "cached_label__icontains", + ), + "archaeological_sites_context_record_name": SearchAltName( + pgettext_lazy("key for text search", "context-record-site-name"), + "finds__base_finds__context_record__archaeological_site__" "name__iexact", + ), + "context_record": SearchAltName( + pgettext_lazy("key for text search", "context-record"), + "finds__base_finds__context_record__cached_label__icontains", + ), + "find_label": SearchAltName( + pgettext_lazy("key for text search", "find-label"), + "finds__label__icontains", + ), + "find_denomination": SearchAltName( + pgettext_lazy("key for text search", "find-denomination"), + "finds__denomination__icontains", + ), + "material_types": SearchAltName( + pgettext_lazy("key for text search", "material"), + "finds__material_types__label__iexact", + ), + "object_types": SearchAltName( + pgettext_lazy("key for text search", "object-type"), + "finds__object_types__label__iexact", + ), + "preservation_to_considers": SearchAltName( + pgettext_lazy("key for text search", "preservation"), + "finds__preservation_to_considers__label__iexact", + ), + "conservatory_state": SearchAltName( + pgettext_lazy("key for text search", "conservatory"), + "finds__conservatory_state__label__iexact", + ), + "integrities": SearchAltName( + pgettext_lazy("key for text search", "integrity"), + "finds__integrities__label__iexact", + ), + "remarkabilities": SearchAltName( + pgettext_lazy("key for text search", "remarkability"), + "finds__remarkabilities__label__iexact", + ), + "alterations": SearchAltName( + pgettext_lazy("key for text search", "alterations"), + "finds__alterations__label__iexact", + ), + "alteration_causes": SearchAltName( + pgettext_lazy("key for text search", "alteration-causes"), + "finds__alteration_causes__label__iexact", ), - 'contain_containers': SearchAltName( + "treatment_emergency": SearchAltName( + pgettext_lazy("key for text search", "treatment-emergency"), + "finds__treatment_emergency__label__iexact", + ), + "description": SearchAltName( + pgettext_lazy("key for text search", "find-description"), + "finds__description__iexact", + ), + "empty": SearchAltName(pgettext_lazy("key for text search", "empty"), "finds"), + "contain_containers": SearchAltName( pgettext_lazy("key for text search", "contain-containers"), - 'children__isnull' + "children__isnull", ), - 'is_stationary': SearchAltName( + "is_stationary": SearchAltName( pgettext_lazy("key for text search", "is-stationary"), - 'container_type__stationary' - ) + "container_type__stationary", + ), } REVERSED_BOOL_FIELDS = [ - 'children__isnull', - 'documents__image__isnull', - 'documents__associated_file__isnull', - 'documents__associated_url__isnull', + "children__isnull", + "documents__image__isnull", + "documents__associated_file__isnull", + "documents__associated_url__isnull", ] - BOOL_FIELDS = ['container_type__stationary'] - REVERSED_MANY_COUNTED_FIELDS = ['finds', 'finds_ref'] + BOOL_FIELDS = ["container_type__stationary"] + REVERSED_MANY_COUNTED_FIELDS = ["finds", "finds_ref"] ALT_NAMES.update(LightHistorizedItem.ALT_NAMES) ALT_NAMES.update(DocumentItem.ALT_NAMES) DYNAMIC_REQUESTS = { - 'division': DynamicRequest( + "division": DynamicRequest( label=_("Division -"), - app_name='archaeological_warehouse', model_name='WarehouseDivision', - form_key='division', - search_key=pgettext_lazy("key for text search", - 'division'), - type_query='division__division__division__txt_idx', - search_query='division__reference__iexact' + app_name="archaeological_warehouse", + model_name="WarehouseDivision", + form_key="division", + search_key=pgettext_lazy("key for text search", "division"), + type_query="division__division__division__txt_idx", + search_query="division__reference__iexact", ), } QA_EDIT = QuickAction( - url="container-qa-bulk-update", icon_class="fa fa-pencil", - text=_("Bulk update"), target="many", - rights=['change_container', 'change_own_container']) + url="container-qa-bulk-update", + icon_class="fa fa-pencil", + text=_("Bulk update"), + target="many", + rights=["change_container", "change_own_container"], + ) QA_LOCK = QuickAction( - url="container-qa-lock", icon_class="fa fa-lock", - text=_("Lock/Unlock"), target="many", - rights=['change_container', 'change_own_container'] + url="container-qa-lock", + icon_class="fa fa-lock", + text=_("Lock/Unlock"), + target="many", + rights=["change_container", "change_own_container"], ) QUICK_ACTIONS = [QA_EDIT, QA_LOCK] @@ -934,52 +990,76 @@ class Container(DocumentItem, Merge, LightHistorizedItem, # fields uuid = models.UUIDField(default=uuid.uuid4) location = models.ForeignKey( - Warehouse, verbose_name=_("Location (warehouse)"), - related_name='containers') + Warehouse, verbose_name=_("Location (warehouse)"), related_name="containers" + ) responsible = models.ForeignKey( - Warehouse, verbose_name=_("Responsible warehouse"), - related_name='owned_containers', blank=True, null=True, - help_text=_("Deprecated - do not use") + Warehouse, + verbose_name=_("Responsible warehouse"), + related_name="owned_containers", + blank=True, + null=True, + help_text=_("Deprecated - do not use"), ) responsibility = models.ForeignKey( - Warehouse, verbose_name=_("Responsibility"), - related_name='responsibilities', blank=True, null=True, - help_text=_("Warehouse that owns the container") + Warehouse, + verbose_name=_("Responsibility"), + related_name="responsibilities", + blank=True, + null=True, + help_text=_("Warehouse that owns the container"), + ) + container_type = models.ForeignKey( + ContainerType, verbose_name=_("Container type"), related_name="containers" ) - container_type = models.ForeignKey(ContainerType, - verbose_name=_("Container type"), - related_name="containers") reference = models.TextField(_("Container ref.")) comment = models.TextField(_("Comment"), blank=True, default="") - cached_label = models.TextField(_("Localisation"), blank=True, default="", - db_index=True) - cached_location = models.TextField(_("Cached location"), - blank=True, default="", db_index=True) - cached_division = models.TextField(_("Cached division"), - blank=True, default="", db_index=True) - parent = models.ForeignKey("Container", verbose_name=_("Parent container"), - on_delete=models.SET_NULL, - related_name="children", blank=True, null=True) - index = models.IntegerField(_("Container ID"), blank=True, null=True, - db_index=True) + cached_label = models.TextField( + _("Localisation"), blank=True, default="", db_index=True + ) + cached_location = models.TextField( + _("Cached location"), blank=True, default="", db_index=True + ) + cached_division = models.TextField( + _("Cached division"), blank=True, default="", db_index=True + ) + parent = models.ForeignKey( + "Container", + verbose_name=_("Parent container"), + on_delete=models.SET_NULL, + related_name="children", + blank=True, + null=True, + ) + index = models.IntegerField(_("Container ID"), blank=True, null=True, db_index=True) weight = models.FloatField(_("Measured weight (g)"), blank=True, null=True) calculated_weight = models.FloatField( - _("Calculated weight (g)"), blank=True, null=True) + _("Calculated weight (g)"), blank=True, null=True + ) cached_weight = models.FloatField( - _("Cached weight (g)"), blank=True, null=True, - help_text=_("Entered weight if available otherwise calculated weight.") + _("Cached weight (g)"), + blank=True, + null=True, + help_text=_("Entered weight if available otherwise calculated weight."), ) old_reference = models.TextField(_("Old reference"), blank=True, default="") external_id = models.TextField(_("External ID"), blank=True, default="") auto_external_id = models.BooleanField( - _("External ID is set automatically"), default=False) + _("External ID is set automatically"), default=False + ) documents = models.ManyToManyField( - "ishtar_common.Document", related_name='containers', - verbose_name=_("Documents"), blank=True) + "ishtar_common.Document", + related_name="containers", + verbose_name=_("Documents"), + blank=True, + ) main_image = models.ForeignKey( - "ishtar_common.Document", related_name='main_image_containers', + "ishtar_common.Document", + related_name="main_image_containers", on_delete=models.SET_NULL, - verbose_name=_("Main image"), blank=True, null=True) + verbose_name=_("Main image"), + blank=True, + null=True, + ) DISABLE_POLYGONS = False MERGE_ATTRIBUTE = "get_merge_key" @@ -988,9 +1068,12 @@ class Container(DocumentItem, Merge, LightHistorizedItem, class Meta: verbose_name = _("Container") verbose_name_plural = _("Containers") - ordering = ('location', 'index', 'cached_label',) - unique_together = [('location', 'container_type', 'parent', - 'reference')] + ordering = ( + "location", + "index", + "cached_label", + ) + unique_together = [("location", "container_type", "parent", "reference")] permissions = ( ("view_container", "Can view all Containers"), ("view_own_container", "Can view own Container"), @@ -999,7 +1082,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, ("delete_own_container", "Can delete own Container"), ) indexes = [ - GinIndex(fields=['data']), + GinIndex(fields=["data"]), ] def __str__(self): @@ -1017,8 +1100,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, return depth def get_max_division_number(self): - return self.location.get_max_division_number() \ - - self.start_division_number + return self.location.get_max_division_number() - self.start_division_number @property def number_of_finds_hosted(self): @@ -1049,13 +1131,12 @@ class Container(DocumentItem, Merge, LightHistorizedItem, return self.parent.external_id def natural_key(self): - return (self.uuid, ) + return (self.uuid,) @classmethod @pre_importer_action def import_get_location(cls, context, value): - if context.get("container_type", None) and context.get( - "reference", None): + if context.get("container_type", None) and context.get("reference", None): try: context["location"] = Warehouse.objects.get(external_id=value) return @@ -1085,15 +1166,23 @@ class Container(DocumentItem, Merge, LightHistorizedItem, :return: True if calculated weight is changed """ profile = get_current_profile() - if profile.calculate_weight_on_full and self.finds.filter( - weight__isnull=True).count(): + if ( + profile.calculate_weight_on_full + and self.finds.filter(weight__isnull=True).count() + ): weight = None else: weight = sum( - w for w in self.finds.filter(weight__isnull=False).values_list( - "weight", flat=True).all()) - weight += self.container_type.tare_weight \ - if self.container_type.tare_weight else 0 + w + for w in self.finds.filter(weight__isnull=False) + .values_list("weight", flat=True) + .all() + ) + weight += ( + self.container_type.tare_weight + if self.container_type.tare_weight + else 0 + ) if weight != self.calculated_weight: self.calculated_weight = weight return True @@ -1103,8 +1192,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, def get_calculated_weight_percent(self): if not self.calculated_weight or not self.weight: return 0 - return (self.calculated_weight - - self.weight) / self.calculated_weight * 100 + return (self.calculated_weight - self.weight) / self.calculated_weight * 100 @property def get_cached_division(self): @@ -1113,8 +1201,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, @property def get_merge_key(self): try: - return str(self.location.uuid) + "|" + \ - self._generate_cached_division() + return str(self.location.uuid) + "|" + self._generate_cached_division() except Warehouse.DoesNotExist: return @@ -1123,11 +1210,13 @@ class Container(DocumentItem, Merge, LightHistorizedItem, try: doc = Document.objects.get(**{key: value}) except Document.DoesNotExist: - raise ImporterError(str(_("Document with {}: {} does not " - "exists")).format(key, value)) + raise ImporterError( + str(_("Document with {}: {} does not " "exists")).format(key, value) + ) except Document.MultipleObjectsReturned: raise ImporterError( - str(_("Multiple document with {}: {}")).format(key, value)) + str(_("Multiple document with {}: {}")).format(key, value) + ) doc.container_id = self.pk doc.container_ref_id = self.pk doc.skip_history_when_saving = True @@ -1136,16 +1225,19 @@ class Container(DocumentItem, Merge, LightHistorizedItem, @post_importer_action def put_document_by_external_id(self, context, value): self.put_document_by_key(value, "external_id") + put_document_by_external_id.post_save = True @post_importer_action def put_document_by_reference(self, context, value): self.put_document_by_key(value, "reference") + put_document_by_reference.post_save = True @post_importer_action def put_document_by_complete_identifier(self, context, value): self.put_document_by_key(value, "complete_identifier") + put_document_by_complete_identifier.post_save = True def _generate_cached_division(self): @@ -1163,8 +1255,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, for loca in reversed(parents) ] try: - locas.append("{} {}".format(self.container_type.name, - self.reference)) + locas.append("{} {}".format(self.container_type.name, self.reference)) except ObjectDoesNotExist: # generate too early on item creation pass return " | ".join(locas) @@ -1174,8 +1265,9 @@ class Container(DocumentItem, Merge, LightHistorizedItem, @classmethod def _change_child_location(cls, parent): - for child in cls.objects.filter( - parent=parent).exclude(location=parent.location).all(): + for child in ( + cls.objects.filter(parent=parent).exclude(location=parent.location).all() + ): if child.location != parent.location: child.location = parent.location child.save() @@ -1198,13 +1290,15 @@ class Container(DocumentItem, Merge, LightHistorizedItem, child.parent = self child.save() self._change_child_location(self) - super(Container, self).merge(item, keep_old=keep_old, - exclude_fields=exclude_fields) + super(Container, self).merge( + item, keep_old=keep_old, exclude_fields=exclude_fields + ) @classmethod def get_query_owns(cls, ishtaruser): - return Q(history_creator=ishtaruser.user_ptr) | \ - Q(location__person_in_charge__ishtaruser=ishtaruser) + return Q(history_creator=ishtaruser.user_ptr) | Q( + location__person_in_charge__ishtaruser=ishtaruser + ) def get_precise_points(self): precise_points = super(Container, self).get_precise_points() @@ -1232,7 +1326,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, @property def associated_filename(self): - filename = datetime.date.today().strftime('%Y-%m-%d') + filename = datetime.date.today().strftime("%Y-%m-%d") filename += "-" + self.reference filename += "-" + self.location.name filename += "-" + str(self.index) @@ -1324,8 +1418,10 @@ class Container(DocumentItem, Merge, LightHistorizedItem, error_msg = str(NO_DIVISION_ERROR).format(place + 1, self.location) - current_container_type, previous_container_types = \ - self.location.get_container_type_by_place(place) + ( + current_container_type, + previous_container_types, + ) = self.location.get_container_type_by_place(place) if not current_container_type: # no division link set at this place if return_errors: @@ -1349,7 +1445,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, "reference": value, "container_type": current_container_type, "parent": current_parent, - "location": self.location + "location": self.location, } q = Container.objects.filter(**dct) if q.count(): @@ -1358,8 +1454,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, if static: if return_errors: error_msg = str( - _("The division {} {} do not exist for the " - "location {}.") + _("The division {} {} do not exist for the " "location {}.") ).format(current_container_type, value, self.location) return None, error_msg return @@ -1376,103 +1471,128 @@ class Container(DocumentItem, Merge, LightHistorizedItem, @post_importer_action def set_localisation_1(self, context, value): return self.set_localisation(0, value) + set_localisation_1.post_save = True @post_importer_action def set_localisation_2(self, context, value): return self.set_localisation(1, value) + set_localisation_2.post_save = True @post_importer_action def set_localisation_3(self, context, value): return self.set_localisation(2, value) + set_localisation_3.post_save = True @post_importer_action def set_localisation_4(self, context, value): return self.set_localisation(3, value) + set_localisation_4.post_save = True @post_importer_action def set_localisation_5(self, context, value): return self.set_localisation(4, value) + set_localisation_5.post_save = True @post_importer_action def set_localisation_6(self, context, value): return self.set_localisation(5, value) + set_localisation_6.post_save = True @post_importer_action def set_localisation_7(self, context, value): return self.set_localisation(6, value) + set_localisation_7.post_save = True @post_importer_action def set_localisation_8(self, context, value): return self.set_localisation(7, value) + set_localisation_8.post_save = True @post_importer_action def set_localisation_9(self, context, value): return self.set_localisation(8, value) + set_localisation_9.post_save = True @post_importer_action def set_static_localisation_1(self, context, value): return self.set_static_localisation(0, value) + set_static_localisation_1.post_save = True @post_importer_action def set_static_localisation_2(self, context, value): return self.set_static_localisation(1, value) + set_static_localisation_2.post_save = True @post_importer_action def set_static_localisation_3(self, context, value): return self.set_static_localisation(2, value) + set_static_localisation_3.post_save = True @post_importer_action def set_static_localisation_4(self, context, value): return self.set_static_localisation(3, value) + set_static_localisation_4.post_save = True @post_importer_action def set_static_localisation_5(self, context, value): return self.set_static_localisation(4, value) + set_static_localisation_5.post_save = True @post_importer_action def set_static_localisation_6(self, context, value): return self.set_static_localisation(5, value) + set_static_localisation_6.post_save = True @post_importer_action def set_static_localisation_7(self, context, value): return self.set_static_localisation(6, value) + set_static_localisation_7.post_save = True @post_importer_action def set_static_localisation_8(self, context, value): return self.set_static_localisation(7, value) + set_static_localisation_8.post_save = True @post_importer_action def set_static_localisation_9(self, context, value): return self.set_static_localisation(8, value) + set_static_localisation_9.post_save = True DOC_VALUES = [ - ("operation_", _("Associated operation - use it with caution, " - "only return the first found operation")), - ("context_record_", - _("Associated context record - use it with caution, " - "only return the first found context_record")), - ("material_types", - _("Material types inside the container - string")), - ("material_types_code", - _("Material types code - string")), + ( + "operation_", + _( + "Associated operation - use it with caution, " + "only return the first found operation" + ), + ), + ( + "context_record_", + _( + "Associated context record - use it with caution, " + "only return the first found context_record" + ), + ), + ("material_types", _("Material types inside the container - string")), + ("material_types_code", _("Material types code - string")), ("finds", _("List of associated finds")), ] @@ -1482,8 +1602,8 @@ class Container(DocumentItem, Merge, LightHistorizedItem, """ materials = set() for material in self.finds.exclude( - material_types__code__isnull=True).values_list( - "material_types__code", flat=True): + material_types__code__isnull=True + ).values_list("material_types__code", flat=True): materials.add(material) return "|".join(sorted(materials)) @@ -1493,38 +1613,43 @@ class Container(DocumentItem, Merge, LightHistorizedItem, """ materials = set() for material in self.finds.exclude( - material_types__label__isnull=True).values_list( - "material_types__label", flat=True): + material_types__label__isnull=True + ).values_list("material_types__label", flat=True): materials.add(material) return ", ".join(sorted(materials)) - def get_values(self, prefix='', no_values=False, filtr=None, **kwargs): + def get_values(self, prefix="", no_values=False, filtr=None, **kwargs): values = super(Container, self).get_values( - prefix=prefix, no_values=no_values, filtr=filtr, **kwargs) - from_find = prefix.startswith("container_") or \ - prefix.startswith("container_ref_") - if (not filtr or prefix + 'finds' in filtr) and not from_find and \ - "finds" not in kwargs.get("exclude", []): + prefix=prefix, no_values=no_values, filtr=filtr, **kwargs + ) + from_find = prefix.startswith("container_") or prefix.startswith( + "container_ref_" + ) + if ( + (not filtr or prefix + "finds" in filtr) + and not from_find + and "finds" not in kwargs.get("exclude", []) + ): kwargs["exclude"] = [prefix + "container", prefix + "container_ref"] # prevent recursive call - values[prefix + 'finds'] = [ - f.get_values( - prefix=prefix, no_values=True, filtr=None, **kwargs) - for f in self.finds.distinct().all()] + values[prefix + "finds"] = [ + f.get_values(prefix=prefix, no_values=True, filtr=None, **kwargs) + for f in self.finds.distinct().all() + ] if not self.finds.count(): return values operation_in_filter = filtr and any( - k for k in filtr if k.startswith(prefix + 'operation')) + k for k in filtr if k.startswith(prefix + "operation") + ) cr_in_filter = filtr and any( - k for k in filtr if k.startswith(prefix + 'context_record')) - if not filtr or prefix + 'material_types' in filtr: - values[prefix + 'material_types'] = self.get_material_types() - if not filtr or prefix + 'material_types_code' in filtr: - values[prefix + 'material_types_code'] = \ - self.get_material_types_code() - if not from_find and ( - not filtr or operation_in_filter or cr_in_filter): + k for k in filtr if k.startswith(prefix + "context_record") + ) + if not filtr or prefix + "material_types" in filtr: + values[prefix + "material_types"] = self.get_material_types() + if not filtr or prefix + "material_types_code" in filtr: + values[prefix + "material_types_code"] = self.get_material_types_code() + if not from_find and (not filtr or operation_in_filter or cr_in_filter): # assume that only one operation is in this container... # you should know what you are doing when using theses variables f = self.finds.all()[0] @@ -1534,15 +1659,15 @@ class Container(DocumentItem, Merge, LightHistorizedItem, if not filtr or cr_in_filter: kwargs["exclude"] = [prefix + "operation"] for k, v in cr.get_values( - prefix=prefix, no_values=True, filtr=None, - **kwargs).items(): - values[prefix + 'context_record_' + k] = v + prefix=prefix, no_values=True, filtr=None, **kwargs + ).items(): + values[prefix + "context_record_" + k] = v if not filtr or operation_in_filter: kwargs["exclude"] = [prefix + "context_records"] for k, v in cr.operation.get_values( - prefix=prefix, no_values=True, filtr=None, - **kwargs).items(): - values[prefix + 'operation_' + k] = v + prefix=prefix, no_values=True, filtr=None, **kwargs + ).items(): + values[prefix + "operation_" + k] = v return values def get_extra_actions(self, request): @@ -1551,11 +1676,17 @@ class Container(DocumentItem, Merge, LightHistorizedItem, """ # url, base_text, icon, extra_text, extra css class, is a quick action actions = super(Container, self).get_extra_actions(request) - can_edit_find = self.can_do(request, 'change_find') + can_edit_find = self.can_do(request, "change_find") if can_edit_find: actions += [ - (reverse('container-add-treatment', args=[self.pk]), - _("Add treatment"), "fa fa-flask", "", "", False), + ( + reverse("container-add-treatment", args=[self.pk]), + _("Add treatment"), + "fa fa-flask", + "", + "", + False, + ), ] return actions @@ -1579,8 +1710,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, return q = Container.objects.filter(location=self.location) if q.count(): - self.index = int( - q.all().aggregate(Max("index"))["index__max"]) + 1 + self.index = int(q.all().aggregate(Max("index"))["index__max"]) + 1 else: self.index = 1 if not self.cached_division: @@ -1591,8 +1721,7 @@ class Container(DocumentItem, Merge, LightHistorizedItem, parent = self.parent_id while parent: number += 1 - parent = Container.objects.filter(pk=parent).values_list( - "parent_id")[0][0] + parent = Container.objects.filter(pk=parent).values_list("parent_id")[0][0] if number > self.location.max_division_number: self.location.max_division_number = number self.location.save() @@ -1608,15 +1737,17 @@ class Container(DocumentItem, Merge, LightHistorizedItem, if not self.index and not self.container_type.stationary: self.skip_history_when_saving = True - q = Container.objects.filter( - location=self.location - ).exclude(pk=self.pk).order_by('-index') + q = ( + Container.objects.filter(location=self.location) + .exclude(pk=self.pk) + .order_by("-index") + ) self.index = q.all()[0].index + 1 if q.count() else 1 updated = True self.skip_history_when_saving = True if not self.external_id or self.auto_external_id: - external_id = get_generated_id('container_external_id', self) + external_id = get_generated_id("container_external_id", self) if external_id != self.external_id: updated = True self.auto_external_id = True @@ -1629,14 +1760,15 @@ class Container(DocumentItem, Merge, LightHistorizedItem, # remove old location in warehouse q = ContainerLocalisation.objects.filter(container=self).exclude( - division__warehouse=self.location) + division__warehouse=self.location + ) for loca in q.all(): loca.delete() def container_post_save(sender, **kwargs): cached_label_and_geo_changed(sender=sender, **kwargs) - #TODO: to be deleted??? + # TODO: to be deleted??? """ if not kwargs.get('instance'): return @@ -1657,8 +1789,7 @@ def container_post_save(sender, **kwargs): def container_pre_delete(sender, **kwargs): instance = kwargs["instance"] - q = Container.objects.filter( - container_tree_child__container_parent=instance) + q = Container.objects.filter(container_tree_child__container_parent=instance) q.update(cached_division="") @@ -1672,43 +1803,45 @@ def container_post_delete(sender, **kwargs): post_save.connect(container_post_save, sender=Container) pre_delete.connect(container_pre_delete, sender=Container) post_delete.connect(container_post_delete, sender=Container) -m2m_changed.connect(document_attached_changed, - sender=Container.documents.through) +m2m_changed.connect(document_attached_changed, sender=Container.documents.through) class ContainerLocalisationManager(models.Manager): - #TODO: to be deleted.... + # TODO: to be deleted.... def get_by_natural_key(self, container, warehouse, container_type): - return self.get(container__uuid=container, - division__warehouse__uuid=warehouse, - division__container_type__txt_idx=container_type) + return self.get( + container__uuid=container, + division__warehouse__uuid=warehouse, + division__container_type__txt_idx=container_type, + ) class ContainerLocalisation(models.Model): - #TODO: to be deleted.... - container = models.ForeignKey(Container, verbose_name=_("Container"), - related_name='division') - division = models.ForeignKey(WarehouseDivisionLink, - verbose_name=_("Division")) - reference = models.CharField(_("Reference"), max_length=200, default='') + # TODO: to be deleted.... + container = models.ForeignKey( + Container, verbose_name=_("Container"), related_name="division" + ) + division = models.ForeignKey(WarehouseDivisionLink, verbose_name=_("Division")) + reference = models.CharField(_("Reference"), max_length=200, default="") objects = ContainerLocalisationManager() TO_BE_DELETED = True class Meta: verbose_name = _("Container localisation") verbose_name_plural = _("Container localisations") - ordering = ('container', 'division__order') + ordering = ("container", "division__order") def __str__(self): - return " - ".join((str(self.container), str(self.division), - self.reference)) + return " - ".join((str(self.container), str(self.division), self.reference)) def natural_key(self): - return self.container.uuid, self.division.warehouse.uuid,\ - self.division.container_type.txt_idx + return ( + self.container.uuid, + self.division.warehouse.uuid, + self.division.container_type.txt_idx, + ) def save(self, *args, **kwargs): super(ContainerLocalisation, self).save(*args, **kwargs) self.container.skip_history_when_saving = True - cached_label_changed(Container, instance=self.container, - force_update=True) + cached_label_changed(Container, instance=self.container, force_update=True) |