diff --git a/district/models.py b/district/models.py index 4663c64c6384fa1df3e4c3f70d511e99d47f3514..3ccbf6fcce30f58544c41f71fdde8b5aee836f89 100644 --- a/district/models.py +++ b/district/models.py @@ -452,6 +452,12 @@ class DistrictArticlePage( return cleaned_data + @property + def get_tags(self): + if self.shared_from is not None: + return self.articles_page.search_tags_by_article_id([self.pk]) + return self.tags.all + def get_context(self, request): context = super().get_context(request) context["related_articles"] = ( @@ -556,9 +562,9 @@ class DistrictArticlesPage( # (tags__slug) context = super().get_context(request) - site_article_ids = self.append_all_shared_articles( + site_article_ids = self.append_all_shared_articles_ids( DistrictArticlePage.objects.child_of(self) - ).values_list("id", flat=True) + ) # Naplním "tag" a "article_page_list" parametry context.update(**self.get_tag_and_articles(request, site_article_ids)) @@ -574,15 +580,26 @@ class DistrictArticlesPage( pro danou stránku (site_article_ids). Lepší by bylo články a tag řešit separátně, ale pak by se musel rozpadnout ten try/except na více bloků. """ - article_page_qs = self.append_all_shared_articles( - DistrictArticlePage.objects - ).filter(id__in=site_article_ids) + + article_page_qs = None + tag = None try: tag = Tag.objects.filter(tag__slug=request.GET["tag"])[0].tag - article_page_qs = article_page_qs.filter(tags__slug=tag.slug) + article_page_qs = self.append_all_shared_articles( + DistrictArticlePage.objects.filter( + id__in=site_article_ids, tags__slug=tag.slug + ), + filter=lambda shared: shared.filter( + id__in=site_article_ids, tags__slug=tag.slug + ), + ) except (KeyError, IndexError): tag = None + article_page_qs = self.append_all_shared_articles( + DistrictArticlePage.objects.filter(id__in=site_article_ids), + filter=lambda shared: shared.filter(id__in=site_article_ids), + ) return { "article_page_list": Paginator( @@ -597,11 +614,12 @@ class DistrictArticlesPage( Getuje Tagy pouze pro DistrictArticlePage omezeno IDčky getnutých přes root_page. Počítá, kolik článků je s daným tagem. """ - return ( - Tag.objects.filter(**self.get_search_tags_params(site_article_ids)) - .order_by("slug") - .annotate(count=models.Count("slug")) - .values("name", "slug", "count") + return self.search_tags_by_article_id( + site_article_ids, + additional_query=lambda query: query.annotate(count=models.Count("slug")), + custom_query_to_values=lambda query: query.order_by("slug").values( + "name", "slug", "count" + ), ) diff --git a/district/templates/district/district_article_page.html b/district/templates/district/district_article_page.html index da90b00275bc082d1372c69d147eef746e0d2dac..67b066cd66d82962e158b40da5890364556cb574 100644 --- a/district/templates/district/district_article_page.html +++ b/district/templates/district/district_article_page.html @@ -24,7 +24,7 @@ </span> </div> <div class="my-4"> - {% for tag in page.tags.all %} + {% for tag in page.get_tags %} <a href="{{ articles_tag_page_url }}?tag={{ tag.slug }}" class="btn btn--grey-125 btn--condensed"> <div class="btn__body ">{{ tag }}</div> </a> diff --git a/shared/models.py b/shared/models.py index 144000d4ca2956fc42cd3c8e147be14ca93c3e10..eef7456d9567f9b8c5a36874b69ade1fdd69900a 100644 --- a/shared/models.py +++ b/shared/models.py @@ -1,4 +1,5 @@ import logging +from enum import Enum from functools import reduce from django.apps import apps @@ -6,7 +7,7 @@ from django.db import models from django.db.models.expressions import F, Value from django.utils import timezone from modelcluster.fields import ParentalKey, ParentalManyToManyField -from taggit.models import ItemBase, TagBase +from taggit.models import ItemBase, Tag, TagBase from wagtail.admin.panels import FieldPanel, MultiFieldPanel, PublishingPanel from wagtail.fields import StreamField from wagtail.models import Page @@ -280,6 +281,12 @@ class SharedTaggedMainArticle(ItemBase): ) +class SharedArticlesPageType(Enum): + DISTRICT = ("district",) + UNIWEB = ("uniweb",) + MAIN = "main" + + class ArticlesMixin(models.Model): shared_tags = ParentalManyToManyField( "shared.SharedTag", @@ -290,22 +297,32 @@ class ArticlesMixin(models.Model): content_panels = Page.content_panels + [FieldPanel("shared_tags")] - def append_all_shared_articles( - self, previous_query: models.QuerySet | None = None, filter=None - ): - """ - To prevent circular deps, we get class models during runtime - """ + def determine_page_type(self): DistrictArticlesPage = apps.get_model(app_label="district.DistrictArticlesPage") UniwebArticlesIndexPage = apps.get_model( app_label="uniweb.UniwebArticlesIndexPage" ) MainArticlesPage = apps.get_model(app_label="main.MainArticlesPage") + if isinstance(self, DistrictArticlesPage): + return SharedArticlesPageType.DISTRICT + elif isinstance(self, UniwebArticlesIndexPage): + return SharedArticlesPageType.UNIWEB + elif isinstance(self, MainArticlesPage): + return SharedArticlesPageType.MAIN + + def append_all_shared_articles_query( + self, previous_query: models.QuerySet | None = None, filter=None + ): + """ + To prevent circular deps, we get class models during runtime + """ DistrictArticlePage = apps.get_model(app_label="district.DistrictArticlePage") UniwebArticlePage = apps.get_model(app_label="uniweb.UniwebArticlePage") MainArticlePage = apps.get_model(app_label="main.MainArticlePage") + page_type = self.determine_page_type() + """ In order to balance union() requirements for tables with same-fields only, we are adding null fields using values(). These values must be in correct order @@ -424,17 +441,17 @@ class ArticlesMixin(models.Model): if previous_query is not None: prepared_query = previous_query.live().specific() - if isinstance(self, DistrictArticlesPage): + if page_type == SharedArticlesPageType.DISTRICT: prepared_query = prepared_query.values( **district_fields, union_shared_from_id=empty_shared_field, ) - elif isinstance(self, UniwebArticlesIndexPage): + elif page_type == SharedArticlesPageType.UNIWEB: prepared_query = prepared_query.values( **uniweb_fields, union_shared_from_id=empty_shared_field, ) - elif isinstance(self, MainArticlesPage): + elif page_type == SharedArticlesPageType.MAIN: prepared_query = prepared_query.values( **main_fields, union_shared_from_id=empty_shared_field, @@ -442,7 +459,31 @@ class ArticlesMixin(models.Model): results = results.union(prepared_query) - results = results.order_by("union_date") + return results.order_by("union_date") + + def append_all_shared_articles_ids( + self, previous_query: models.QuerySet | None = None, filter=None + ): + results = self.append_all_shared_articles_query(previous_query, filter) + return results.values_list("id", Flat=True) + + def append_all_shared_articles( + self, previous_query: models.QuerySet | None = None, filter=None + ): + """ + To prevent circular deps, we get class models during runtime + """ + page_type = self.determine_page_type() + + DistrictArticlePage = apps.get_model(app_label="district.DistrictArticlePage") + UniwebArticlePage = apps.get_model(app_label="uniweb.UniwebArticlePage") + MainArticlePage = apps.get_model(app_label="main.MainArticlePage") + + main_meta_fields = MainArticlePage._meta.fields + district_meta_fields = DistrictArticlePage._meta.fields + uniweb_meta_fields = UniwebArticlePage._meta.fields + + results = self.append_all_shared_articles_query(previous_query, filter) evaluated = list( results @@ -452,7 +493,7 @@ class ArticlesMixin(models.Model): field.column: unioned[f"union_{field.column}"] } - if isinstance(self, DistrictArticlesPage): + if page_type == SharedArticlesPageType.DISTRICT: return list( map( lambda unioned: DistrictArticlePage( @@ -462,7 +503,7 @@ class ArticlesMixin(models.Model): ) ) - if isinstance(self, UniwebArticlesIndexPage): + if page_type == SharedArticlesPageType.UNIWEB: return list( map( lambda unioned: UniwebArticlePage( @@ -472,7 +513,7 @@ class ArticlesMixin(models.Model): ) ) - if isinstance(self, MainArticlesPage): + if page_type == SharedArticlesPageType.MAIN: return list( map( lambda unioned: MainArticlePage( @@ -492,14 +533,38 @@ class ArticlesMixin(models.Model): slug = request.GET.get("sdilene", "") return self.get_article_page_by_slug(slug).serve(request) - def get_search_tags_params(self, site_article_ids: list): - return { - "districtarticlepage__id__in": site_article_ids, - "uniwebarticlepage__id__in": site_article_ids, - "mainarticlepage__id__in": site_article_ids, - } + def search_tags_by_article_id( + self, site_article_ids: list, additional_query=None, custom_query_to_values=None + ): + DistrictArticleTag = apps.get_model(app_label="district.DistrictArticleTag") + UniwebArticleTag = apps.get_model(app_label="uniweb.UniwebArticleTag") + MainArticleTag = apps.get_model(app_label="main.MainArticleTag") + + district_tags = DistrictArticleTag.objects.filter( + content_object_id__in=site_article_ids + ) + uniweb_tags = UniwebArticleTag.objects.filter( + content_object_id__in=site_article_ids + ) + main_tags = MainArticleTag.objects.filter( + content_object_id__in=site_article_ids + ) + + if additional_query is not None: + district_tags = additional_query(district_tags) + uniweb_tags = additional_query(uniweb_tags) + main_tags = additional_query(main_tags) + + union = district_tags.union(uniweb_tags).union(main_tags) + + if custom_query_to_values is not None: + union = custom_query_to_values(union) + return union + else: + union = union.values_list("id") + return Tag.objects.filter(id__in=union) - def get_search_article_params_by_tags(self, tag: str): + def search_tags_by_tag_name(self, tag: str): return { "uniwebarticlepage__tags__name": tag, "districtarticlepage__tags__name": tag, diff --git a/shared/templates/shared/article_preview.html b/shared/templates/shared/article_preview.html index 4add013a934881483d502b1443e71769f0bb2dfc..1ed708203349580d88d613e1d7272ae5183d89af 100644 --- a/shared/templates/shared/article_preview.html +++ b/shared/templates/shared/article_preview.html @@ -85,7 +85,7 @@ {{ article.perex }} </p> <div class="inline-block-nogap mt-4"> - {% for tag in article.tags.all %} + {% for tag in article.get_tags %} <a href="{{ articles_tag_page_url }}?tag={{ tag.slug }}" class="btn article-card__category-button btn--condensed text-sm font-light btn--grey-{% if article.is_black %}700{% else %}125{% endif %} btn--hoveractive" diff --git a/uniweb/models.py b/uniweb/models.py index ad9e2dde58d6c548598429dd86c9d7623204e5ef..e28e03c245789764c3117297eecfb1882303c98d 100644 --- a/uniweb/models.py +++ b/uniweb/models.py @@ -548,17 +548,17 @@ class UniwebArticlesIndexPage( num = request.GET.get("page") tag = request.GET.get("tag") + tag_params = self.search_tags_by_tag_name(tag) + articles = self.append_all_shared_articles( - UniwebArticlePage.objects.child_of(self) + UniwebArticlePage.objects.child_of(self), + filter=lambda articles: articles.filter(**tag_params), ) - if tag is not None: - articles = articles.filter(**self.get_search_article_params_by_tags(tag)) + articles_ids = list(map(lambda article: article.pk, articles)) context["articles"] = Paginator(articles, ARTICLES_PER_PAGE).get_page(num) - context["tags"] = Tag.objects.filter( - **self.get_search_tags_params(articles.values_list("id", flat=True)) - ) + context["tags"] = self.search_tags_by_article_id(articles_ids) context["active_tag"] = tag return context