From b4d3b7d7d8a994f636c16697f245ac14d7a3f547 Mon Sep 17 00:00:00 2001 From: Étienne Loks Date: Wed, 30 Sep 2020 19:05:12 +0200 Subject: Stats: generation on demand --- .../templates/ishtar/sheet_operation.html | 19 ++++++++++- archaeological_operations/urls.py | 4 +++ archaeological_operations/views.py | 37 +++++++++++++++++++++- archaeological_warehouse/models.py | 6 ++-- .../templates/ishtar/sheet_container.html | 22 ++++++++++--- .../templates/ishtar/sheet_warehouse.html | 19 ++++++++++- archaeological_warehouse/urls.py | 8 +++++ archaeological_warehouse/views.py | 25 +++++++++++++++ ishtar_common/models.py | 31 +++++++++--------- 9 files changed, 147 insertions(+), 24 deletions(-) diff --git a/archaeological_operations/templates/ishtar/sheet_operation.html b/archaeological_operations/templates/ishtar/sheet_operation.html index ef5de7f59..868040666 100644 --- a/archaeological_operations/templates/ishtar/sheet_operation.html +++ b/archaeological_operations/templates/ishtar/sheet_operation.html @@ -408,7 +408,24 @@

{% trans "Statistics" %}

- {% trans "These numbers are updated hourly" %} + +
+
+ + {% with item.last_stats_update as last_stats_update%} + {% if last_stats_update %} + {% trans "Last update:" %} {{last_stats_update}} + {% endif %}{% endwith %} +
+

{% trans "Administrative acts" %}

diff --git a/archaeological_operations/urls.py b/archaeological_operations/urls.py index 77791058a..72e06641d 100644 --- a/archaeological_operations/urls.py +++ b/archaeological_operations/urls.py @@ -212,4 +212,8 @@ urlpatterns = [ 'change_own_archaeologicalsite'])( views.QAArchaeologicalSiteForm.as_view()), name='site-qa-bulk-update-confirm', kwargs={"confirm": True}), + + url(r'generate-stats-operation/(?P.+)/', + views.GenerateStatsOperation.as_view(), + name='generate-stats-operation'), ] diff --git a/archaeological_operations/views.py b/archaeological_operations/views.py index ecacdb560..897302828 100644 --- a/archaeological_operations/views.py +++ b/archaeological_operations/views.py @@ -25,6 +25,7 @@ from django.core.urlresolvers import reverse from django.db.models import Q from django.http import HttpResponse, HttpResponseRedirect, Http404 from django.shortcuts import render, redirect +from django.views.generic import RedirectView from ishtar_common.utils import ugettext_lazy as _, pgettext_lazy from archaeological_operations import models @@ -36,7 +37,8 @@ from ishtar_common.models import get_current_profile, IshtarSiteProfile, \ DocumentTemplate from ishtar_common.utils import put_session_message, check_rights_condition from ishtar_common.views import gen_generate_doc, QAItemEditForm, \ - QABaseLockView, wizard_is_available, QAItemForm + QABaseLockView, wizard_is_available, QAItemForm, IshtarMixin, \ + LoginRequiredMixin from ishtar_common.views_item import get_item, show_item, revert_item, \ new_qa_item from ishtar_common.wizards import SearchWizard @@ -644,3 +646,36 @@ class QAArchaeologicalSiteDuplicateFormView(QAItemForm): class QAArchaeologicalSiteForm(QAItemEditForm): model = models.ArchaeologicalSite form_class = forms.QAArchaeologicalSiteFormMulti + + +class GenerateStatsOperation(IshtarMixin, LoginRequiredMixin, RedirectView): + model = models.Operation + + def get_redirect_url(self, *args, **kwargs): + return reverse('display-item', + args=[self.model.SLUG, self.item.pk]) + "#statistics" + + def get(self, request, *args, **kwargs): + self.item = self.model.objects.get(pk=kwargs['pk']) + self.item._get_or_set_stats('_nb_acts', update=True) + self.item._get_or_set_stats('_nb_indexed_acts', update=True) + self.item._get_or_set_stats('_nb_context_records', update=True) + self.item._get_or_set_stats('_nb_context_records_by_type', update=True, + expected_type=list) + self.item._get_or_set_stats('_nb_context_records_by_periods', + update=True, expected_type=list) + self.item._get_or_set_stats('_nb_finds', update=True) + self.item._get_or_set_stats('_nb_finds_by_material_type', update=True, + expected_type=list) + self.item._get_or_set_stats('_nb_finds_by_types', update=True, + expected_type=list) + self.item._get_or_set_stats('_nb_finds_by_periods', update=True, + expected_type=list) + self.item._get_or_set_stats('_nb_documents', update=True) + self.item._get_or_set_stats('_nb_documents_by_types', update=True, + expected_type=list) + self.item._get_or_set_stats('_nb_stats_finds_by_ue', update=True) + + return super(GenerateStatsOperation, self).get(request, *args, **kwargs) + + diff --git a/archaeological_warehouse/models.py b/archaeological_warehouse/models.py index ffc491ddc..f89092dba 100644 --- a/archaeological_warehouse/models.py +++ b/archaeological_warehouse/models.py @@ -118,7 +118,8 @@ class DivisionContainer(DashboardFormItem): @property def number_of_finds_by_place(self, update=False): - return self._get_or_set_stats('_number_of_finds_by_place', update) + 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( @@ -126,7 +127,8 @@ class DivisionContainer(DashboardFormItem): @property def number_of_containers_by_place(self, update=False): - return self._get_or_set_stats('_number_of_containers_by_place', update) + 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: diff --git a/archaeological_warehouse/templates/ishtar/sheet_container.html b/archaeological_warehouse/templates/ishtar/sheet_container.html index 336684bc8..7ca39645d 100644 --- a/archaeological_warehouse/templates/ishtar/sheet_container.html +++ b/archaeological_warehouse/templates/ishtar/sheet_container.html @@ -154,7 +154,23 @@ role="tabpanel" aria-labelledby="{{window_id}}-stats-tab">

{% trans "Statistics" %}

- {% trans "These numbers are updated hourly" %} +
+
+ + {% with item.last_stats_update as last_stats_update%} + {% if last_stats_update %} + {% trans "Last update:" %} {{last_stats_update}} + {% endif %}{% endwith %} +
+
{% if not item.number_containers and not item.number_divisions %}
@@ -188,10 +204,8 @@ {% endif %} {% endfor %} -

{% trans "Containers" %}

- {% if item.number_of_containers_by_place %} -

{% trans "Containers by location in the warehouse" %}

+

{% trans "Containers by location" %}

{% for items in item.number_of_containers_by_place %} {% if items %}

{% trans "Statistics" %}

- {% trans "These numbers are updated hourly" %} + +
+
+ + {% with item.last_stats_update as last_stats_update%} + {% if last_stats_update %} + {% trans "Last update:" %} {{last_stats_update}} + {% endif %}{% endwith %} +
+
{% if not item.number_containers and not item.number_divisions %}
diff --git a/archaeological_warehouse/urls.py b/archaeological_warehouse/urls.py index 2f43d74a6..46d812def 100644 --- a/archaeological_warehouse/urls.py +++ b/archaeological_warehouse/urls.py @@ -128,4 +128,12 @@ urlpatterns = [ url(r'container-manual-merge-items/(?P[0-9_]+?)/$', views.ContainerManualMergeItems.as_view(), name='container_manual_merge_items'), + + url(r'generate-stats-container/(?P.+)/', + views.GenerateStatsContainer.as_view(), + name='generate-stats-container'), + + url(r'generate-stats-warehouse/(?P.+)/', + views.GenerateStatsWarehouse.as_view(), + name='generate-stats-warehouse'), ] diff --git a/archaeological_warehouse/views.py b/archaeological_warehouse/views.py index 34def58cf..de0c64d19 100644 --- a/archaeological_warehouse/views.py +++ b/archaeological_warehouse/views.py @@ -21,6 +21,7 @@ import json from django.core.urlresolvers import reverse from django.db.models import Q +from django.views.generic import RedirectView from django.views.generic.edit import FormView from django.http import HttpResponse, Http404, HttpResponseRedirect from django.shortcuts import redirect @@ -313,3 +314,27 @@ class QAContainerForm(QAItemEditForm): # item list is necessary to verify uniqueness rules kwargs['items'] = self.items return kwargs + + +class GenerateStats(IshtarMixin, LoginRequiredMixin, RedirectView): + model = None + + def get_redirect_url(self, *args, **kwargs): + return reverse('display-item', + args=[self.model.SLUG, self.item.pk]) + "#stats" + + def get(self, request, *args, **kwargs): + self.item = self.model.objects.get(pk=kwargs['pk']) + self.item._get_or_set_stats('_number_of_finds_by_place', update=True, + expected_type=list) + self.item._get_or_set_stats('_number_of_containers_by_place', + update=True, expected_type=list) + return super(GenerateStats, self).get(request, *args, **kwargs) + + +class GenerateStatsContainer(GenerateStats): + model = models.Container + + +class GenerateStatsWarehouse(GenerateStats): + model = models.Warehouse diff --git a/ishtar_common/models.py b/ishtar_common/models.py index 2d3320e2e..6eea042ce 100644 --- a/ishtar_common/models.py +++ b/ishtar_common/models.py @@ -3403,33 +3403,34 @@ class DashboardFormItem(object): Provide methods to manage statistics """ - def _get_or_set_stats(self, funcname, update, - timeout=settings.CACHE_TIMEOUT, + def last_stats_update(self): + model_name = self._meta.app_label + "." + self._meta.model_name + q = StatsCache.objects.filter( + model=model_name, model_pk=self.pk).order_by("-updated") + if not q.count(): + return + return q.all()[0].updated + + def _get_or_set_stats(self, funcname, update=False, expected_type=None): - values = {} - from_cache = False model_name = self._meta.app_label + "." + self._meta.model_name sc, __ = StatsCache.objects.get_or_create( model=model_name, model_pk=self.pk ) - now = datetime.datetime.now() - if not settings.DEBUG and ( - not update and sc.values and funcname in sc.values and ( - sc.updated + datetime.timedelta(seconds=timeout)) > now): + if not update: values = sc.values - from_cache = True - if funcname not in values: + if funcname not in values: + if expected_type is not None: + return expected_type() + return 0 + else: values = update_stats(sc, self, funcname) if funcname in values: values = values[funcname] else: values = 0 if expected_type is not None and not isinstance(values, expected_type): - if from_cache: - return self._get_or_set_stats(funcname, True, - expected_type=expected_type) - else: - return expected_type() + return expected_type() return values @classmethod -- cgit v1.2.3