Source code for eucrim.search.views

# SPDX-FileCopyrightText: 2024 Thomas Breitner <t.breitner@csl.mpg.de>
#
# SPDX-License-Identifier: EUPL-1.2

from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator
from django.db.models import Count
from django.shortcuts import render

from wagtail.models import Page
from django.conf import settings

from django.contrib.contenttypes.models import ContentType

from .forms import SearchForm, CONTENT_TYPE_CHOICES
from .utils import parse


# Number of results per page in search results
SEARCH_PAGE_SIZE = 10
# How many authors to show by default in the sidebar before "Show more"
SEARCH_AUTHOR_VISIBLE_LIMIT = getattr(settings, "SEARCH_AUTHOR_VISIBLE_LIMIT", 8)

MODEL_LABELS = {
    "articlepage": "Article",
    "newspage": "News",
    "eventpage": "Event",
    "profilepage": "Profile",
    "issuepage": "Issue",
    "procedurepage": "Case",
    "standardpage": "Page",
}


[docs] def get_content_type_facets(queryset, request, selected_content_types): """ Compute content type facets using Django ORM aggregation. This works on any QuerySet, not just search results. """ # Get counts per content type from the queryset facet_counts = ( queryset.values("content_type_id") .annotate(count=Count("id")) .order_by("-count") ) # Build a map of content_type_id -> count count_map = {str(item["content_type_id"]): item["count"] for item in facet_counts} # Get all content types we care about ct_models = [choice[0] for choice in CONTENT_TYPE_CHOICES] cts = ContentType.objects.filter(model__in=ct_models) ct_by_model = {ct.model: ct for ct in cts} # Build base params for link generation base_params = request.GET.copy() base_params.pop("page", None) facet_list = [] for model_name, label in CONTENT_TYPE_CHOICES: ct = ct_by_model.get(model_name) if ct is None: continue count = count_map.get(str(ct.id), 0) # Omit zero-count facets — don't show options that have no results if count == 0: continue # Build link for this facet params_for_facet = base_params.copy() params_for_facet.setlist("content_types", [model_name]) link = "?" + params_for_facet.urlencode() facet_list.append( { "content_type_model": model_name, "label": label, "count": count, "link": link, "selected": model_name in selected_content_types, } ) return facet_list
[docs] def get_author_facets(queryset, request): """ Compute author facets from ArticlePageAuthor and NewsPage.authors relationships. """ author_facets = [] try: # Import models here to avoid circular imports from eucrim.article.models import ArticlePageAuthor from eucrim.news.models import NewsPage # Aggregate from ArticlePageAuthor (articles) using DB-side filters article_authors = ( ArticlePageAuthor.objects.filter(page__in=queryset) .values("author_id", "author__first_name", "author__last_name") .annotate(count=Count("author_id")) .order_by("-count")[:20] ) # Aggregate from NewsPage.authors M2M using DB-side filters news_authors_qs = ( NewsPage.authors.through.objects.filter(newspage__in=queryset) .values( "profilepage_id", "profilepage__first_name", "profilepage__last_name", ) .annotate(count=Count("profilepage_id")) ) # Combine and deduplicate authors author_map = {} for a in article_authors: author_id = a["author_id"] if author_id: name = f"{a['author__first_name']} {a['author__last_name']}".strip() author_map[author_id] = author_map.get( author_id, {"name": name, "count": 0, "id": author_id} ) author_map[author_id]["count"] += a["count"] for a in news_authors_qs: author_id = a["profilepage_id"] if author_id: name = f"{a['profilepage__first_name']} {a['profilepage__last_name']}".strip() author_map[author_id] = author_map.get( author_id, {"name": name, "count": 0, "id": author_id} ) author_map[author_id]["count"] += a["count"] # Sort by count and take top 20, omitting zero-count entries author_facets = sorted( author_map.values(), key=lambda x: x["count"], reverse=True ) author_facets = [a for a in author_facets if a.get("count", 0) > 0][:20] except Exception: pass return author_facets