mirror of
https://github.com/django/django.git
synced 2025-11-18 11:00:24 +00:00
Fix admin filters to respect related model Meta.ordering
RelatedFieldListFilter and RelatedOnlyFieldListFilter now fall back to the related model's Meta.ordering when ModelAdmin ordering is not set. This ensures consistent ordering in admin filters and resolves issues where ordering was previously ignored.
This commit is contained in:
parent
1f8382d34d
commit
818d8fc8cd
3 changed files with 104 additions and 2 deletions
|
|
@ -198,6 +198,8 @@ class RelatedFieldListFilter(FieldListFilter):
|
|||
related_admin = model_admin.admin_site._registry.get(field.remote_field.model)
|
||||
if related_admin is not None:
|
||||
ordering = related_admin.get_ordering(request)
|
||||
if not ordering:
|
||||
ordering = field.remote_field.model._meta.ordering
|
||||
return field.get_choices(include_blank=False, ordering=ordering)
|
||||
|
||||
def choices(self, changelist):
|
||||
|
|
@ -419,4 +421,10 @@ FieldListFilter.register(lambda f: True, AllValuesFieldListFilter)
|
|||
class RelatedOnlyFieldListFilter(RelatedFieldListFilter):
|
||||
def field_choices(self, field, request, model_admin):
|
||||
pk_qs = model_admin.get_queryset(request).distinct().values_list('%s__pk' % self.field_path, flat=True)
|
||||
return field.get_choices(include_blank=False, limit_choices_to={'pk__in': pk_qs})
|
||||
ordering = ()
|
||||
related_admin = model_admin.admin_site._registry.get(field.remote_field.model)
|
||||
if related_admin is not None:
|
||||
ordering = related_admin.get_ordering(request)
|
||||
if not ordering:
|
||||
ordering = field.remote_field.model._meta.ordering
|
||||
return field.get_choices(include_blank=False, limit_choices_to={'pk__in': pk_qs}, ordering=ordering)
|
||||
|
|
|
|||
|
|
@ -77,3 +77,20 @@ class Bookmark(models.Model):
|
|||
|
||||
def __str__(self):
|
||||
return self.url
|
||||
|
||||
|
||||
class ImplicitlyOrderedBook(models.Model):
|
||||
title = models.CharField(max_length=50)
|
||||
author = models.ForeignKey(
|
||||
User,
|
||||
models.SET_NULL,
|
||||
verbose_name="Verbose Author",
|
||||
related_name='implicit_books_authored',
|
||||
blank=True, null=True,
|
||||
)
|
||||
|
||||
class Meta:
|
||||
ordering = ('title',)
|
||||
|
||||
def __str__(self):
|
||||
return self.title
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ from django.contrib.auth.models import User
|
|||
from django.core.exceptions import ImproperlyConfigured
|
||||
from django.test import RequestFactory, TestCase, override_settings
|
||||
|
||||
from .models import Book, Bookmark, Department, Employee, TaggedItem
|
||||
from .models import Book, Bookmark, Department, Employee, ImplicitlyOrderedBook, TaggedItem
|
||||
|
||||
|
||||
def select_by(dictlist, key, value):
|
||||
|
|
@ -1253,3 +1253,80 @@ class ListFiltersTests(TestCase):
|
|||
changelist = modeladmin.get_changelist_instance(request)
|
||||
changelist.get_results(request)
|
||||
self.assertEqual(changelist.full_result_count, 4)
|
||||
|
||||
def test_relatedfieldlistfilter_foreignkey_ordering_fallback_to_model_meta(self):
|
||||
"""
|
||||
RelatedFieldListFilter ordering falls back to the related model's
|
||||
Meta.ordering when there's no ModelAdmin registered for it.
|
||||
"""
|
||||
# Create ImplicitlyOrderedBook instances with different titles
|
||||
# to test that ordering uses Meta.ordering
|
||||
ImplicitlyOrderedBook.objects.create(title='Zulu Book', author=self.alfred)
|
||||
ImplicitlyOrderedBook.objects.create(title='Alpha Book', author=self.bob)
|
||||
ImplicitlyOrderedBook.objects.create(title='Beta Book', author=self.lisa)
|
||||
|
||||
class ImplicitlyOrderedBookAdmin(ModelAdmin):
|
||||
list_filter = ('author',)
|
||||
|
||||
modeladmin = ImplicitlyOrderedBookAdmin(ImplicitlyOrderedBook, site)
|
||||
|
||||
request = self.request_factory.get('/')
|
||||
request.user = self.alfred
|
||||
changelist = modeladmin.get_changelist_instance(request)
|
||||
filterspec = changelist.get_filters(request)[0][0]
|
||||
|
||||
# User model doesn't have Meta.ordering, so should be ordered by pk
|
||||
# which is the default behavior
|
||||
expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob'), (self.lisa.pk, 'lisa')]
|
||||
self.assertEqual(filterspec.lookup_choices, expected)
|
||||
|
||||
def test_relatedonlyfieldlistfilter_foreignkey_ordering_with_model_admin(self):
|
||||
"""
|
||||
RelatedOnlyFieldListFilter ordering respects ModelAdmin.ordering.
|
||||
"""
|
||||
class EmployeeAdminWithOrdering(ModelAdmin):
|
||||
ordering = ('name',)
|
||||
|
||||
class BookAdmin(ModelAdmin):
|
||||
list_filter = (('employee', RelatedOnlyFieldListFilter),)
|
||||
|
||||
site.register(Employee, EmployeeAdminWithOrdering)
|
||||
self.addCleanup(lambda: site.unregister(Employee))
|
||||
|
||||
self.djangonaut_book.employee = self.john
|
||||
self.djangonaut_book.save()
|
||||
self.bio_book.employee = self.jack
|
||||
self.bio_book.save()
|
||||
|
||||
modeladmin = BookAdmin(Book, site)
|
||||
|
||||
request = self.request_factory.get('/')
|
||||
request.user = self.alfred
|
||||
changelist = modeladmin.get_changelist_instance(request)
|
||||
filterspec = changelist.get_filters(request)[0][0]
|
||||
expected = [(self.jack.pk, 'Jack Red'), (self.john.pk, 'John Blue')]
|
||||
self.assertEqual(filterspec.lookup_choices, expected)
|
||||
|
||||
def test_relatedonlyfieldlistfilter_foreignkey_ordering_fallback_to_model_meta(self):
|
||||
"""
|
||||
RelatedOnlyFieldListFilter ordering falls back to the related model's
|
||||
Meta.ordering when there's no ModelAdmin registered for it.
|
||||
"""
|
||||
# Create ImplicitlyOrderedBook instances
|
||||
book1 = ImplicitlyOrderedBook.objects.create(title='Zulu Book', author=self.alfred)
|
||||
book2 = ImplicitlyOrderedBook.objects.create(title='Alpha Book', author=self.bob)
|
||||
book3 = ImplicitlyOrderedBook.objects.create(title='Beta Book', author=self.lisa)
|
||||
|
||||
class ImplicitlyOrderedBookAdmin(ModelAdmin):
|
||||
list_filter = (('author', RelatedOnlyFieldListFilter),)
|
||||
|
||||
modeladmin = ImplicitlyOrderedBookAdmin(ImplicitlyOrderedBook, site)
|
||||
|
||||
request = self.request_factory.get('/')
|
||||
request.user = self.alfred
|
||||
changelist = modeladmin.get_changelist_instance(request)
|
||||
filterspec = changelist.get_filters(request)[0][0]
|
||||
|
||||
# User model doesn't have Meta.ordering, so should be ordered by pk
|
||||
expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob'), (self.lisa.pk, 'lisa')]
|
||||
self.assertEqual(filterspec.lookup_choices, expected)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue