Skip to content

Commit

Permalink
fix: added custom category filter to allow sorting by name (#122)
Browse files Browse the repository at this point in the history
  • Loading branch information
Bernardvdv authored May 13, 2022
1 parent f01d6c6 commit 808da7f
Show file tree
Hide file tree
Showing 5 changed files with 119 additions and 8 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ Changelog
Unreleased
==========
* fix: Moved category list filter after site
* fix: Ordering category filter by name

1.6.0 (2022-04-29)
==================
Expand Down
7 changes: 3 additions & 4 deletions djangocms_alias/admin.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

from .cms_config import AliasCMSConfig
from .constants import USAGE_ALIAS_URL_NAME
from .filters import LanguageFilter, SiteFilter
from .filters import CategoryFilter, LanguageFilter, SiteFilter
from .forms import AliasContentForm
from .models import Alias, AliasContent, Category
from .urls import urlpatterns
Expand All @@ -28,7 +28,7 @@

alias_content_admin_classes = [admin.ModelAdmin]
alias_content_admin_list_display = ('name', 'get_category',)
alias_content_admin_list_filter = (SiteFilter, LanguageFilter, 'alias__category', )
alias_content_admin_list_filter = (SiteFilter, CategoryFilter, LanguageFilter,)
djangocms_versioning_enabled = AliasCMSConfig.djangocms_versioning_enabled

if djangocms_versioning_enabled:
Expand All @@ -37,8 +37,7 @@
from .filters import UnpublishedFilter
alias_content_admin_classes.insert(0, ExtendedVersionAdminMixin)
alias_content_admin_list_display = ('name', 'get_category',)
alias_content_admin_list_filter = (SiteFilter, LanguageFilter, UnpublishedFilter)
alias_content_admin_list_filter = (SiteFilter, 'alias__category', LanguageFilter, UnpublishedFilter)
alias_content_admin_list_filter = (SiteFilter, CategoryFilter, LanguageFilter, UnpublishedFilter)


@admin.register(Category)
Expand Down
1 change: 1 addition & 0 deletions djangocms_alias/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,4 @@
SITE_FILTER_URL_PARAM = "site"
SITE_FILTER_NO_SITE_VALUE = "no_site"
UNPUBLISHED_FILTER_URL_PARAM = "unpublished"
CATEGORY_FILTER_PARAM = "category"
35 changes: 35 additions & 0 deletions djangocms_alias/filters.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,18 @@
from django.contrib import admin
from django.utils.encoding import smart_str
from django.utils.translation import gettext_lazy as _

from cms.forms.utils import get_sites
from cms.utils.i18n import get_language_tuple, get_site_language_from_request

from .cms_config import AliasCMSConfig
from .constants import (
CATEGORY_FILTER_PARAM,
LANGUAGE_FILTER_URL_PARAM,
SITE_FILTER_NO_SITE_VALUE,
SITE_FILTER_URL_PARAM,
)
from .models import Category


djangocms_versioning_enabled = AliasCMSConfig.djangocms_versioning_enabled
Expand Down Expand Up @@ -82,6 +85,38 @@ def choices(self, changelist):
}


class CategoryFilter(admin.SimpleListFilter):
title = _("Category")
parameter_name = CATEGORY_FILTER_PARAM

def lookups(self, request, model_admin):
qs = model_admin.get_queryset(request)
cat_id = qs.values_list('alias__category', flat=True).distinct()
# Ensure the category is ordered by the name alphabetically by default
cat = Category.objects.filter(pk__in=cat_id).order_by('translations__name')
for obj in cat:
yield str(obj.pk), smart_str(obj)

def queryset(self, request, queryset):
if self.value():
return queryset.filter(alias__category=self.value()).distinct()

def choices(self, changelist):
yield {
"selected": self.value() is None,
"query_string": changelist.get_query_string(remove=[self.parameter_name]),
"display": _("All"),
}
for lookup, title in self.lookup_choices:
yield {
"selected": self.value() == str(lookup),
"query_string": changelist.get_query_string(
{self.parameter_name: lookup}
),
"display": title,
}


if djangocms_versioning_enabled:
from djangocms_versioning.constants import UNPUBLISHED

Expand Down
83 changes: 79 additions & 4 deletions tests/test_admin_filters.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
from unittest import skipUnless

from django.contrib import admin
from django.contrib.sites.models import Site

from cms.utils import get_current_site
Expand All @@ -9,6 +10,7 @@
SITE_FILTER_URL_PARAM,
UNPUBLISHED_FILTER_URL_PARAM,
)
from djangocms_alias.filters import CategoryFilter
from djangocms_alias.models import Alias as AliasModel, AliasContent, Category
from djangocms_alias.utils import is_versioning_enabled

Expand Down Expand Up @@ -252,9 +254,9 @@ def test_category_filter_no_verisoning(self):
with self.login_user_context(self.superuser):
response_default = self.client.get(base_url)
# category one should have a result
category_one_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_one.id}")
category_one_filter_response = self.client.get(f"{base_url}?category={category_one.id}")
# category two should have a result
category_two_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_two.id}")
category_two_filter_response = self.client.get(f"{base_url}?category={category_two.id}")

# By default all alias contents are shown
self.assertEqual(
Expand Down Expand Up @@ -310,9 +312,9 @@ def test_category_filter_with_verisoning(self):
with self.login_user_context(self.superuser):
response_default = self.client.get(base_url)
# category one should have a result
category_one_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_one.id}")
category_one_filter_response = self.client.get(f"{base_url}?category={category_one.id}")
# categopry two should have a result
category_two_filter_response = self.client.get(f"{base_url}?alias__category__id__exact={category_two.id}")
category_two_filter_response = self.client.get(f"{base_url}?category={category_two.id}")

# By default all alias contents are shown
self.assertEqual(
Expand All @@ -332,3 +334,76 @@ def test_category_filter_with_verisoning(self):
set(category_two_filter_response.context["cl"].queryset),
set([expected_category_two_content])
)

def test_category_filter_lookups_ordered_alphabetical(self):
"""
Category filter lookup choices should be ordered in alphabetical order
"""
category_one = Category.objects.create(name='b - category')
alias_one = AliasModel.objects.create(
category=category_one,
position=0,
)
AliasContent.objects.create(
alias=alias_one,
name="EN Alias Content one",
language="en",
)
category_two = Category.objects.create(name='a - category')
alias_two = AliasModel.objects.create(
category=category_two,
position=1,
)
AliasContent.objects.create(
alias=alias_two,
name="EN Alias Content two",
language="en",
)

version_admin = admin.site._registry[AliasContent]
category_filter = CategoryFilter(None, {"category": ""}, AliasContent, version_admin)
# Get the first choice in the filter lookup object
first_lookup_value = category_filter.lookup_choices[0][1]
# Lookup value should match the category name linked to alias content
self.assertEqual(
first_lookup_value, category_two.name
)
self.assertNotEqual(
first_lookup_value, category_one.name
)

def test_category_filter_lookup_should_only_show_aliases_linked_to_content(self):
"""
Category not linked to content should not be listed in the category filter lookups
"""
category_one = Category.objects.create(name='b - category')
alias_one = AliasModel.objects.create(
category=category_one,
position=0,
)
AliasContent.objects.create(
alias=alias_one,
name="EN Alias Content one",
language="en",
)
category_two = Category.objects.create(name='a - category')
AliasModel.objects.create(
category=category_two,
position=1,
)

version_admin = admin.site._registry[AliasContent]
category_filter = CategoryFilter(None, {"category": ""}, AliasContent, version_admin)

# Get the first choice in the filter lookup object
first_lookup_value = category_filter.lookup_choices[0][1]
# Lookup choices should only display the category linked to content
self.assertEqual(len(category_filter.lookup_choices), 1)
# Lookup value should match the category name linked to alias content
self.assertEqual(
first_lookup_value, category_one.name
)
# Category not linked to alias content should not be listed in the choices
self.assertNotEqual(
first_lookup_value, category_two.name
)

0 comments on commit 808da7f

Please sign in to comment.