From 742abc8c535d2ffbe23c370d82408a8b323e226f Mon Sep 17 00:00:00 2001 From: Adam Murray Date: Fri, 10 Jun 2022 14:41:04 +0100 Subject: [PATCH] fix: AliasContent Admin Category Ordering (#127) * fix: Added queryset annotation to allow ordering, regardless of case --- CHANGELOG.rst | 1 + djangocms_alias/admin.py | 9 +- tests/requirements/requirements_base.txt | 1 + tests/test_admin.py | 129 +++++++++++++++++++++++ 4 files changed, 139 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 98b9695a..96fbbd40 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,7 @@ Changelog Unreleased ========== +* fix: AliasContent Category admin_order_field incorrect ordering * fix: Alias field in plugin should be disabled unless site/category is populated 1.7.0 (2022-05-31) diff --git a/djangocms_alias/admin.py b/djangocms_alias/admin.py index ba42c771..1c9a82f7 100644 --- a/djangocms_alias/admin.py +++ b/djangocms_alias/admin.py @@ -1,4 +1,5 @@ from django.contrib import admin +from django.db.models.functions import Lower from django.template.loader import render_to_string from django.utils.translation import gettext_lazy as _ @@ -111,12 +112,18 @@ class AliasContentAdmin(*alias_content_admin_classes): actions = None change_form_template = "admin/djangocms_alias/aliascontent/change_form.html" + def get_queryset(self, request): + queryset = super().get_queryset(request) + # Force the category set to Lower, to be able to sort the category in ascending/descending order + queryset = queryset.annotate(alias_category_translations_ordered=Lower("alias__category__translations__name")) + return queryset + # Add Alias category in the admin manager list and order field def get_category(self, obj): return obj.alias.category get_category.short_description = _('category') - get_category.admin_order_field = "alias__category" + get_category.admin_order_field = "alias_category_translations_ordered" def has_add_permission(self, request, obj=None): # FIXME: It is not currently possible to add an alias from the django admin changelist issue #97 diff --git a/tests/requirements/requirements_base.txt b/tests/requirements/requirements_base.txt index 2dd48899..6c757b9e 100644 --- a/tests/requirements/requirements_base.txt +++ b/tests/requirements/requirements_base.txt @@ -1,3 +1,4 @@ +bs4 coverage django-app-helper flake8 diff --git a/tests/test_admin.py b/tests/test_admin.py index 26c71a64..73762c24 100644 --- a/tests/test_admin.py +++ b/tests/test_admin.py @@ -6,6 +6,8 @@ from cms.test_utils.testcases import CMSTestCase from cms.utils.urlutils import admin_reverse +from bs4 import BeautifulSoup + from djangocms_alias.constants import USAGE_ALIAS_URL_NAME from djangocms_alias.models import Alias as AliasModel, AliasContent, Category from djangocms_alias.utils import is_versioning_enabled @@ -241,3 +243,130 @@ def test_alias_content_manager_rendering_preview_add_url(self): add_aliascontent_url, response_content_decoded, ) + + def _create_alias_and_categories(self, category_name, alias_content_name=None): + if not alias_content_name: + alias_content_name = category_name + category = Category.objects.create(name=category_name) + alias = AliasModel.objects.create(category=category, position=0) + alias_content = AliasContent.objects.create( + alias=alias, + name=alias_content_name, + language="en" + ) + return category, alias, alias_content + + @skipUnless(is_versioning_enabled(), 'Test only relevant for versioning') + def test_category_field_ordering_versioned(self): + """ + Related category can be ordered by name, both in ascending and descending order, with versioning + """ + # Create a number of categories, aliases, and alias content to order + first_category, first_alias, first_alias_content = self._create_alias_and_categories("First Order Test Case") + # Previously lowercase and upper case would be sorted separately, test they are ordered together + first_category_lower, first_alias_lower, first_alias_content_lower = self._create_alias_and_categories( + "first order test case lower" + ) + middle_category, middle_alias, middle_alias_content = self._create_alias_and_categories( + "Middle Order Test Case" + ) + # Previously lowercase and upper case would be sorted separately, test they are ordered together + last_category_lower, last_alias_lower, last_alias_content_lower = self._create_alias_and_categories( + "z order test case lower" + ) + last_category, last_alias, last_alias_content = self._create_alias_and_categories( + "Z Order Test Case Upper" + ) + # Create the versions for each alias content + from djangocms_versioning.models import Version + Version.objects.create(content=first_alias_content, created_by=self.superuser) + Version.objects.create(content=first_alias_content_lower, created_by=self.superuser) + Version.objects.create(content=middle_alias_content, created_by=self.superuser) + Version.objects.create(content=last_alias_content_lower, created_by=self.superuser) + Version.objects.create(content=last_alias_content, created_by=self.superuser) + + with self.login_user_context(self.superuser): + base_url = self.get_admin_url(AliasContent, "changelist") + # o=1 indicates ascending alphabetical order on list_displays second entry + base_url += "?o=1" + # en is the default language configured for the site + response = self.client.get(base_url) + soup = BeautifulSoup(response.content, "html.parser") + results = soup.find_all("td", class_="field-get_category") + + # Test results are in ascending alphabetical order + self.assertEqual(results[0].text, first_alias_content.name) + self.assertEqual(results[1].text, first_alias_content_lower.name) + self.assertEqual(results[2].text, middle_alias_content.name) + self.assertEqual(results[3].text, last_alias_content_lower.name) + self.assertEqual(results[4].text, last_alias_content.name) + + with self.login_user_context(self.superuser): + base_url = self.get_admin_url(AliasContent, "changelist") + # o=-1 indicates descending alphabetical order on list_displays second entry + base_url += "?o=-1" + # en is the default language configured for the site + response = self.client.get(base_url) + soup = BeautifulSoup(response.content, "html.parser") + results = soup.find_all("td", class_="field-get_category") + + # Test results are in descending alphabetical order + self.assertEqual(results[4].text, first_alias_content.name) + self.assertEqual(results[3].text, first_alias_content_lower.name) + self.assertEqual(results[2].text, middle_alias_content.name) + self.assertEqual(results[1].text, last_alias_content_lower.name) + self.assertEqual(results[0].text, last_alias_content.name) + + @skipUnless(not is_versioning_enabled(), 'Test only relevant for versioning') + def test_category_field_ordering_unversioned(self): + """ + Related category can be ordered by name, both in ascending and descending order, without versioning + """ + # Create a number of categories, aliases, and alias content to order + first_category, first_alias, first_alias_content = self._create_alias_and_categories("First Order Test Case") + # Previously lowercase and upper case would be sorted separately, test they are ordered together + first_category_lower, first_alias_lower, first_alias_content_lower = self._create_alias_and_categories( + "first order test case lower" + ) + middle_category, middle_alias, middle_alias_content = self._create_alias_and_categories( + "Middle Order Test Case" + ) + # Previously lowercase and upper case would be sorted separately, test they are ordered together + last_category_lower, last_alias_lower, last_alias_content_lower = self._create_alias_and_categories( + "z order test case lower" + ) + last_category, last_alias, last_alias_content = self._create_alias_and_categories( + "Z Order Test Case Upper" + ) + + with self.login_user_context(self.superuser): + base_url = self.get_admin_url(AliasContent, "changelist") + # o=1 indicates ascending alphabetical order on list_displays second entry + base_url += "?o=1" + # en is the default language configured for the site + response = self.client.get(base_url) + soup = BeautifulSoup(response.content, "html.parser") + results = soup.find_all("td", class_="field-get_category") + + # Test results are in ascending alphabetical order + self.assertEqual(results[0].text, first_alias_content.name) + self.assertEqual(results[1].text, first_alias_content_lower.name) + self.assertEqual(results[2].text, middle_alias_content.name) + self.assertEqual(results[3].text, last_alias_content_lower.name) + self.assertEqual(results[4].text, last_alias_content.name) + + with self.login_user_context(self.superuser): + base_url = self.get_admin_url(AliasContent, "changelist") + # o=-1 indicates descending alphabetical order on list_displays second entry + base_url += "?o=-1" + # en is the default language configured for the site + response = self.client.get(base_url) + soup = BeautifulSoup(response.content, "html.parser") + results = soup.find_all("td", class_="field-get_category") + + # Test results are in descending alphabetical order + self.assertEqual(results[4].text, first_alias_content.name) + self.assertEqual(results[3].text, first_alias_content_lower.name) + self.assertEqual(results[2].text, middle_alias_content.name) + self.assertEqual(results[1].text, last_alias_content_lower.name) + self.assertEqual(results[0].text, last_alias_content.name)