diff --git a/district/migrations/0065_alter_districtgeofeaturedetailpage_sort_order.py b/district/migrations/0065_alter_districtgeofeaturedetailpage_sort_order.py new file mode 100644 index 0000000000000000000000000000000000000000..444ee744078a3c60e6e4542a2eaa825a1b4042ac --- /dev/null +++ b/district/migrations/0065_alter_districtgeofeaturedetailpage_sort_order.py @@ -0,0 +1,24 @@ +# Generated by Django 4.0.3 on 2022-05-03 05:41 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("district", "0064_alter_districtgeofeaturedetailpage_options_and_more"), + ] + + operations = [ + migrations.AlterField( + model_name="districtgeofeaturedetailpage", + name="sort_order", + field=models.IntegerField( + blank=True, + default=0, + help_text="Čím větší hodnotu zadáte, tím později ve výpise položek bude. Můžete tím tedy ovlivňovat očíslování položky ve výpisu.", + null=True, + verbose_name="Index řazení", + ), + ), + ] diff --git a/district/models.py b/district/models.py index d7a17f6535302b828033257cd9166f65e5368e07..9da207a351f96a93759085eb62669227257e84c3 100644 --- a/district/models.py +++ b/district/models.py @@ -1,9 +1,11 @@ import json import random +from django.core.cache import cache from django.core.exceptions import ValidationError from django.core.paginator import Paginator from django.db import models +from django.db.models import signals from django.shortcuts import render from django.utils.translation import gettext_lazy from modelcluster.contrib.taggit import ClusterTaggableManager @@ -1178,7 +1180,13 @@ class DistrictGeoFeatureCollectionPage( verbose_name = "Stránka s mapovou kolekcí" def get_features_by_category(self): - features = self.get_children().live().specific().select_related("category") + features = ( + self.get_children() + .live() + .specific() + .prefetch_related("category") + .order_by("districtgeofeaturedetailpage__sort_order") + ) categories = sorted(set(f.category for f in features), key=lambda c: c.name) return [ @@ -1244,6 +1252,10 @@ class DistrictGeoFeatureCollectionCategory(Orderable): return f"{self.page} / {self.name}" +def make_feature_index_cache_key(feature: "DistrictGeoFeatureDetailPage"): + return f"DistrictGeoFeatureDetailPage::{feature.id}::index" + + class DistrictGeoFeatureDetailPage( ExtendedMetadataPageMixin, MetadataPageMixin, SubpageMixin, Page, Orderable ): @@ -1286,7 +1298,9 @@ class DistrictGeoFeatureDetailPage( "Index řazení", null=True, blank=True, - help_text="Čím větší hodnotu zadáte, tím později ve výpise položk abude.", + help_text="Čím větší hodnotu zadáte, tím později ve výpise položek bude. Můžete tím tedy ovlivňovat očíslování " + "položky ve výpisu.", + default=0, ) sort_order_field = "sort_order" @@ -1322,14 +1336,21 @@ class DistrictGeoFeatureDetailPage( @property def index(self): - if not hasattr(self, "__index"): - self.__index = ( + key = make_feature_index_cache_key(self) + cached_index = cache.get(key) + + if cached_index is None: + cached_index = ( list( - self.get_siblings(inclusive=True).values_list("pk", flat=True) + self.get_siblings(inclusive=True) + .order_by("districtgeofeaturedetailpage__sort_order") + .values_list("pk", flat=True) ).index(self.pk) + 1 ) - return self.__index + cache.set(key, cached_index) + + return cached_index def get_meta_image(self): return self.image @@ -1369,3 +1390,18 @@ class DistrictGeoFeatureDetailPage( ) except ValueError as exc: raise ValidationError({"geojson": str(exc)}) from exc + + +def invalidate_feature_index_cache(sender, **kwargs): + """When DistrictGeoFeatureDetailPage changes, delete all sibling index cache keys to force recompute.""" + if kwargs.get("instance"): + keys = [ + make_feature_index_cache_key(feature) + for feature in kwargs["instance"].get_siblings(inclusive=True) + ] + cache.delete_many(keys) + + +signals.post_save.connect( + invalidate_feature_index_cache, sender=DistrictGeoFeatureDetailPage +)