diff --git a/integreat_cms/cms/templates/pois/poi_list.html b/integreat_cms/cms/templates/pois/poi_list.html index f6fe9a88cc..98a7cbae5f 100644 --- a/integreat_cms/cms/templates/pois/poi_list.html +++ b/integreat_cms/cms/templates/pois/poi_list.html @@ -2,6 +2,7 @@ {% load i18n %} {% load rules %} {% load static %} +{% load sort_tags %} {% load content_filters %} {% block content %} {% get_current_language as LANGUAGE_CODE %} @@ -62,14 +63,19 @@

+ {% translate "Street" as street_label %} + {% translate "Postal Code" as postcode_label %} + {% translate "City" as city_label %} + {% translate "Country" as country_label %} + {% translate "Category" as category_label %} - {% if backend_language and backend_language != language %} - - - - -
{% if perms.cms.change_poi %} {% endif %} - {% translate "Title in" %} {{ language.translated_name }} + + {% sort_link title_label "translations__title" %} @@ -93,20 +99,20 @@

{% translate "Publication status" %} - {% translate "Street" %} + + {% sort_link street_label "address" %} - {% translate "Postal Code" %} + + {% sort_link postcode_label "postcode" %} - {% translate "City" %} + + {% sort_link city_label "city" %} - {% translate "Country" %} + + {% sort_link country_label "country" %} - {% translate "Category" %} + + {% sort_link category_label "category" %} {% translate "Options" %} diff --git a/integreat_cms/cms/templatetags/sort_tags.py b/integreat_cms/cms/templatetags/sort_tags.py index f10b6211e8..2abffbffcf 100644 --- a/integreat_cms/cms/templatetags/sort_tags.py +++ b/integreat_cms/cms/templatetags/sort_tags.py @@ -1,5 +1,6 @@ from django import template from django.template.context import RequestContext +from django.utils.html import escape from django.utils.http import urlencode from django.utils.safestring import mark_safe @@ -31,7 +32,9 @@ def sort_link(context: RequestContext, label: str, field: str) -> str: url = f"?{urlencode(params, doseq=True)}" - return mark_safe(f'{label}{arrow}') + return mark_safe( + f'{escape(label)}{arrow}' + ) @register.inclusion_tag("_sortable_table_header.html", takes_context=True) diff --git a/integreat_cms/cms/views/mixins.py b/integreat_cms/cms/views/mixins.py index 4895ac8531..d14b319a0f 100644 --- a/integreat_cms/cms/views/mixins.py +++ b/integreat_cms/cms/views/mixins.py @@ -9,6 +9,7 @@ from django.conf import settings from django.contrib.auth.mixins import UserPassesTestMixin from django.core.paginator import EmptyPage, PageNotAnInteger, Paginator +from django.db.models import Min from django.urls import reverse from django.utils.translation import gettext_lazy as _ from django.views.generic.base import ContextMixin, TemplateResponseMixin @@ -237,5 +238,22 @@ def get_filtered_sorted_queryset(self, queryset: QuerySet) -> QuerySet: if order_by: # queryset.order_by([]) would override default ordering and result in an unordered queryset # so we only use order_by if "sort" is not empty - return queryset.order_by(*order_by) + annotations = {} + final_order = [] + for f in order_by: + bare = f.lstrip("-") + descending = f.startswith("-") + if "__" in bare: + # Sorting by a relational field via JOIN produces duplicate rows. + # Use Min annotation instead, which collapses via GROUP BY. + annotation_name = f"_sort_{bare.replace('__', '_')}" + annotations[annotation_name] = Min(bare) + final_order.append( + f"-{annotation_name}" if descending else annotation_name + ) + else: + final_order.append(f) + if annotations: + queryset = queryset.annotate(**annotations) + queryset = queryset.order_by(*final_order) return queryset diff --git a/integreat_cms/cms/views/pois/poi_list_view.py b/integreat_cms/cms/views/pois/poi_list_view.py index bdd5648621..98874cc9a8 100644 --- a/integreat_cms/cms/views/pois/poi_list_view.py +++ b/integreat_cms/cms/views/pois/poi_list_view.py @@ -41,6 +41,15 @@ class POIListView( #: The translation model of this list view (used to determine whether machine translations are permitted) translation_model = POITranslation model = POI + table_fields = [ + ("translations__title", _("Title")), + (None, _("Publication status")), + ("address", _("Street")), + ("postcode", _("Postal Code")), + ("city", _("City")), + ("country", _("Country")), + ("category", _("Category")), + ] def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: r""" @@ -105,5 +114,6 @@ def get(self, request: HttpRequest, *args: Any, **kwargs: Any) -> HttpResponse: "source_language": region.get_source_language(language.slug), "content_type": "locations", "is_archive": self.archived, + "title_label": "{} {}".format(_("Title in"), language.translated_name), }, ) diff --git a/integreat_cms/locale/de/LC_MESSAGES/django.po b/integreat_cms/locale/de/LC_MESSAGES/django.po index b1209572c8..a9b702ebbd 100644 --- a/integreat_cms/locale/de/LC_MESSAGES/django.po +++ b/integreat_cms/locale/de/LC_MESSAGES/django.po @@ -27,6 +27,7 @@ msgid "CMS" msgstr "CMS" #: cms/constants/administrative_division.py cms/templates/pois/poi_list.html +#: cms/views/pois/poi_list_view.py msgid "City" msgstr "Stadt" @@ -1941,7 +1942,7 @@ msgstr "{} hier eingeben" #: cms/templates/content_versions.html cms/templates/events/event_form.html #: cms/templates/events/event_list.html cms/templates/pages/page_form.html #: cms/templates/pages/pages_page_tree.html cms/templates/pois/poi_form.html -#: cms/templates/pois/poi_list.html +#: cms/templates/pois/poi_list.html cms/views/pois/poi_list_view.py msgid "Publication status" msgstr "Veröffentlichungsstatus" @@ -2071,6 +2072,7 @@ msgstr "Alle Kategorien" #: cms/templates/feedback/admin_feedback_list.html #: cms/templates/feedback/region_feedback_list.html #: cms/templates/pois/poi_list.html cms/views/feedback/feedback_resource.py +#: cms/views/pois/poi_list_view.py msgid "Category" msgstr "Kategorie" @@ -3664,7 +3666,7 @@ msgstr "Ob die Seite explizit archiviert ist oder nicht" #: cms/templates/events/event_form.html cms/templates/events/event_list.html #: cms/templates/pages/_generic_page_tree_header.html #: cms/templates/pages/page_form.html cms/templates/pois/poi_form.html -#: cms/templates/pois/poi_list.html +#: cms/templates/pois/poi_list.html cms/views/pois/poi_list_view.py msgid "Title in" msgstr "Titel auf" @@ -7649,6 +7651,7 @@ msgstr "Keine Änderungen vorgenommen." #: cms/templates/pages/_page_xliff_import_diff.html #: cms/templates/push_notifications/push_notification_list.html +#: cms/views/pois/poi_list_view.py msgid "Title" msgstr "Titel" @@ -8280,15 +8283,15 @@ msgid "" msgstr "" "Sie können Orte nur in der Standard-Sprache (%(default_language)s) anlegen." -#: cms/templates/pois/poi_list.html +#: cms/templates/pois/poi_list.html cms/views/pois/poi_list_view.py msgid "Street" msgstr "Straße" -#: cms/templates/pois/poi_list.html +#: cms/templates/pois/poi_list.html cms/views/pois/poi_list_view.py msgid "Postal Code" msgstr "Postleitzahl" -#: cms/templates/pois/poi_list.html +#: cms/templates/pois/poi_list.html cms/views/pois/poi_list_view.py msgid "Country" msgstr "Land"