diff options
Diffstat (limited to 'archaeological_warehouse/models.py')
-rw-r--r-- | archaeological_warehouse/models.py | 121 |
1 files changed, 115 insertions, 6 deletions
diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index 91184c907..96814339c 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -*- coding: utf-8 -*- -# Copyright (C) 2012 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> +# Copyright (C) 2012-2017 Étienne Loks <etienne.loks_AT_peacefrogsDOTnet> # This program is free software: you can redistribute it and/or modify # it under the terms of the GNU Affero General Public License as @@ -21,6 +21,7 @@ import datetime from django.conf import settings from django.contrib.gis.db import models +from django.db.models import Q, Count from django.db.models.signals import post_save, post_delete from django.template.defaultfilters import slugify from django.utils.translation import ugettext_lazy as _, ugettext @@ -28,7 +29,8 @@ from django.utils.translation import ugettext_lazy as _, ugettext from ishtar_common.utils import cached_label_changed from ishtar_common.models import GeneralType, get_external_id, \ - LightHistorizedItem, OwnPerms, Address, Person, post_save_cache + LightHistorizedItem, OwnPerms, Address, Person, post_save_cache, \ + ImageModel, DashboardFormItem class WarehouseType(GeneralType): @@ -40,7 +42,7 @@ post_save.connect(post_save_cache, sender=WarehouseType) post_delete.connect(post_save_cache, sender=WarehouseType) -class Warehouse(Address, OwnPerms): +class Warehouse(Address, DashboardFormItem, OwnPerms): SHOW_URL = 'show-warehouse' name = models.CharField(_(u"Name"), max_length=200) warehouse_type = models.ForeignKey(WarehouseType, @@ -78,6 +80,105 @@ class Warehouse(Address, OwnPerms): return datetime.date.today().strftime('%Y-%m-%d') + '-' + \ slugify(unicode(self)) + @classmethod + def get_query_owns(cls, user): + return Q(person_in_charge__ishtaruser=user.ishtaruser) + + @property + def number_of_finds(self): + from archaeological_finds.models import Find + return Find.objects.filter(container__responsible=self).count() + + @property + def number_of_finds_hosted(self): + from archaeological_finds.models import Find + return Find.objects.filter(container__location=self).count() + + @property + def number_of_containers(self): + return Container.objects.filter(location=self).count() + + def _get_divisions(self, current_path, remaining_division, depth=0): + if not remaining_division: + return [current_path] + current_division = remaining_division.pop(0) + q = ContainerLocalisation.objects.filter( + division=current_division, + ) + for div, ref in current_path: + q = q.filter( + container__division__division=div, + container__division__reference=ref + ) + res = [] + old_ref = None + for ref in q.values('reference').order_by('reference').all(): + if ref['reference'] == old_ref: + continue + old_ref = ref['reference'] + cpath = current_path[:] + cpath.append((current_division, ref['reference'])) + for r in self._get_divisions(cpath, remaining_division[:], + depth + 1): + res.append(r) + return res + + @property + def available_division_tuples(self): + """ + :return: ordered list of available paths. Each path is a list of + tuple with the WarehouseDivisionLink and the reference. + """ + divisions = list( + WarehouseDivisionLink.objects.filter(warehouse=self + ).order_by('order').all()) + return self._get_divisions([], divisions) + + def _number_of_items_by_place(self, model, division_key='division'): + res = {} + paths = self.available_division_tuples[:] + for path in paths: + q = model.objects + cpath = [] + for division, ref in path: + lbl = u"{} {}".format(division.division, ref) + cpath.append(lbl) + attrs = { + division_key + "__division": division, + division_key + "__reference": ref + } + q = q.filter(**attrs) + if tuple(cpath) not in res: + res[tuple(cpath)] = q.count() + res = [(k, res[k]) for k in res] + final_res, current_res, depth = [], [], 1 + for path, nb in sorted(res, key=lambda x: (len(x[0]), x[0])): + if depth != len(path): + final_res.append(current_res[:]) + current_res = [] + depth = len(path) + current_res.append((u" | ".join(path), nb)) + final_res.append(current_res[:]) + return final_res + + def _number_of_finds_by_place(self): + from archaeological_finds.models import Find + return self._number_of_items_by_place( + Find, division_key='container__division') + + @property + def number_of_finds_by_place(self, update=False): + return self._get_or_set_stats('_number_of_finds_by_place', update, + settings.CACHE_SMALLTIMEOUT) + + def _number_of_containers_by_place(self): + return self._number_of_items_by_place(Container) + + @property + def number_of_containers_by_place(self, update=False): + return self._get_or_set_stats('_number_of_containers_by_place', update, + settings.CACHE_SMALLTIMEOUT) + def save(self, *args, **kwargs): super(Warehouse, self).save(*args, **kwargs) for container in self.containers.all(): @@ -149,9 +250,10 @@ post_save.connect(post_save_cache, sender=ContainerType) post_delete.connect(post_save_cache, sender=ContainerType) -class Container(LightHistorizedItem): +class Container(LightHistorizedItem, ImageModel): TABLE_COLS = ['reference', 'container_type__label', 'cached_location', 'divisions_lbl'] + IMAGE_PREFIX = 'containers/' # search parameters EXTRA_REQUEST_KEYS = { @@ -182,7 +284,7 @@ class Container(LightHistorizedItem): null=True, blank=True) cached_location = models.CharField(_(u"Cached location"), max_length=500, null=True, blank=True) - index = models.IntegerField(u"Index", default=0) + index = models.IntegerField(u"ID", default=0) external_id = models.TextField(_(u"External ID"), blank=True, null=True) auto_external_id = models.BooleanField( _(u"External ID is set automatically"), default=False) @@ -207,6 +309,12 @@ class Container(LightHistorizedItem): cached_label = u" - ".join(items) return cached_label + @classmethod + def get_query_owns(cls, user): + return Q(history_creator=user) | \ + Q(location__person_in_charge__ishtaruser=user.ishtaruser) | \ + Q(responsible__person_in_charge__ishtaruser=user.ishtaruser) + @property def associated_filename(self): filename = datetime.date.today().strftime('%Y-%m-%d') @@ -275,7 +383,8 @@ post_save.connect(cached_label_changed, sender=Container) class ContainerLocalisation(models.Model): - container = models.ForeignKey(Container, verbose_name=_(u"Container")) + container = models.ForeignKey(Container, verbose_name=_(u"Container"), + related_name='division') division = models.ForeignKey(WarehouseDivisionLink, verbose_name=_(u"Division")) reference = models.CharField(_(u"Reference"), max_length=200, default='') |