Fixed #29835 -- Made RelatedFieldListFilter respect ModelAdmin.ordering.
This commit is contained in:
parent
35a08b8541
commit
6d4e5feb79
|
@ -194,7 +194,11 @@ class RelatedFieldListFilter(FieldListFilter):
|
||||||
return [self.lookup_kwarg, self.lookup_kwarg_isnull]
|
return [self.lookup_kwarg, self.lookup_kwarg_isnull]
|
||||||
|
|
||||||
def field_choices(self, field, request, model_admin):
|
def field_choices(self, field, request, model_admin):
|
||||||
return field.get_choices(include_blank=False)
|
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)
|
||||||
|
return field.get_choices(include_blank=False, ordering=ordering)
|
||||||
|
|
||||||
def choices(self, changelist):
|
def choices(self, changelist):
|
||||||
yield {
|
yield {
|
||||||
|
|
|
@ -807,7 +807,7 @@ class Field(RegisterLookupMixin):
|
||||||
return return_None
|
return return_None
|
||||||
return str # return empty string
|
return str # return empty string
|
||||||
|
|
||||||
def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_choices_to=None):
|
def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, limit_choices_to=None, ordering=()):
|
||||||
"""
|
"""
|
||||||
Return choices with a default blank choices included, for use
|
Return choices with a default blank choices included, for use
|
||||||
as <select> choices for this field.
|
as <select> choices for this field.
|
||||||
|
@ -828,7 +828,7 @@ class Field(RegisterLookupMixin):
|
||||||
)
|
)
|
||||||
return (blank_choice if include_blank else []) + [
|
return (blank_choice if include_blank else []) + [
|
||||||
(choice_func(x), str(x))
|
(choice_func(x), str(x))
|
||||||
for x in rel_model._default_manager.complex_filter(limit_choices_to)
|
for x in rel_model._default_manager.complex_filter(limit_choices_to).order_by(*ordering)
|
||||||
]
|
]
|
||||||
|
|
||||||
def value_to_string(self, obj):
|
def value_to_string(self, obj):
|
||||||
|
|
|
@ -114,7 +114,7 @@ class ForeignObjectRel(FieldCacheMixin):
|
||||||
self.related_model._meta.model_name,
|
self.related_model._meta.model_name,
|
||||||
)
|
)
|
||||||
|
|
||||||
def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH):
|
def get_choices(self, include_blank=True, blank_choice=BLANK_CHOICE_DASH, ordering=()):
|
||||||
"""
|
"""
|
||||||
Return choices with a default blank choices included, for use
|
Return choices with a default blank choices included, for use
|
||||||
as <select> choices for this field.
|
as <select> choices for this field.
|
||||||
|
@ -123,7 +123,7 @@ class ForeignObjectRel(FieldCacheMixin):
|
||||||
initially for utilization by RelatedFieldListFilter.
|
initially for utilization by RelatedFieldListFilter.
|
||||||
"""
|
"""
|
||||||
return (blank_choice if include_blank else []) + [
|
return (blank_choice if include_blank else []) + [
|
||||||
(x.pk, str(x)) for x in self.related_model._default_manager.all()
|
(x.pk, str(x)) for x in self.related_model._default_manager.order_by(*ordering)
|
||||||
]
|
]
|
||||||
|
|
||||||
def is_hidden(self):
|
def is_hidden(self):
|
||||||
|
|
|
@ -548,6 +548,43 @@ class ListFiltersTests(TestCase):
|
||||||
self.assertIs(choice['selected'], True)
|
self.assertIs(choice['selected'], True)
|
||||||
self.assertEqual(choice['query_string'], '?author__id__exact=%d' % self.alfred.pk)
|
self.assertEqual(choice['query_string'], '?author__id__exact=%d' % self.alfred.pk)
|
||||||
|
|
||||||
|
def test_relatedfieldlistfilter_foreignkey_ordering(self):
|
||||||
|
"""RelatedFieldListFilter ordering respects ModelAdmin.ordering."""
|
||||||
|
class EmployeeAdminWithOrdering(ModelAdmin):
|
||||||
|
ordering = ('name',)
|
||||||
|
|
||||||
|
class BookAdmin(ModelAdmin):
|
||||||
|
list_filter = ('employee',)
|
||||||
|
|
||||||
|
site.register(Employee, EmployeeAdminWithOrdering)
|
||||||
|
self.addCleanup(lambda: site.unregister(Employee))
|
||||||
|
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_relatedfieldlistfilter_foreignkey_ordering_reverse(self):
|
||||||
|
class EmployeeAdminWithOrdering(ModelAdmin):
|
||||||
|
ordering = ('-name',)
|
||||||
|
|
||||||
|
class BookAdmin(ModelAdmin):
|
||||||
|
list_filter = ('employee',)
|
||||||
|
|
||||||
|
site.register(Employee, EmployeeAdminWithOrdering)
|
||||||
|
self.addCleanup(lambda: site.unregister(Employee))
|
||||||
|
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.john.pk, 'John Blue'), (self.jack.pk, 'Jack Red')]
|
||||||
|
self.assertEqual(filterspec.lookup_choices, expected)
|
||||||
|
|
||||||
def test_relatedfieldlistfilter_manytomany(self):
|
def test_relatedfieldlistfilter_manytomany(self):
|
||||||
modeladmin = BookAdmin(Book, site)
|
modeladmin = BookAdmin(Book, site)
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,7 @@ from django.test import SimpleTestCase, TestCase
|
||||||
from django.utils.functional import lazy
|
from django.utils.functional import lazy
|
||||||
|
|
||||||
from .models import (
|
from .models import (
|
||||||
Foo, RenamedField, VerboseNameField, Whiz, WhizIter, WhizIterEmpty,
|
Bar, Foo, RenamedField, VerboseNameField, Whiz, WhizIter, WhizIterEmpty,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
@ -157,3 +157,37 @@ class GetChoicesTests(SimpleTestCase):
|
||||||
lazy_func = lazy(lambda x: 0 / 0, int) # raises ZeroDivisionError if evaluated.
|
lazy_func = lazy(lambda x: 0 / 0, int) # raises ZeroDivisionError if evaluated.
|
||||||
f = models.CharField(choices=[(lazy_func('group'), (('a', 'A'), ('b', 'B')))])
|
f = models.CharField(choices=[(lazy_func('group'), (('a', 'A'), ('b', 'B')))])
|
||||||
self.assertEqual(f.get_choices(include_blank=True)[0], ('', '---------'))
|
self.assertEqual(f.get_choices(include_blank=True)[0], ('', '---------'))
|
||||||
|
|
||||||
|
|
||||||
|
class GetChoicesOrderingTests(TestCase):
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def setUpTestData(cls):
|
||||||
|
cls.foo1 = Foo.objects.create(a='a', d='12.34')
|
||||||
|
cls.foo2 = Foo.objects.create(a='b', d='12.34')
|
||||||
|
cls.bar1 = Bar.objects.create(a=cls.foo1, b='a')
|
||||||
|
cls.bar2 = Bar.objects.create(a=cls.foo2, b='a')
|
||||||
|
cls.field = Bar._meta.get_field('a')
|
||||||
|
|
||||||
|
def assertChoicesEqual(self, choices, objs):
|
||||||
|
self.assertEqual(choices, [(obj.pk, str(obj)) for obj in objs])
|
||||||
|
|
||||||
|
def test_get_choices(self):
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
self.field.get_choices(include_blank=False, ordering=('a',)),
|
||||||
|
[self.foo1, self.foo2]
|
||||||
|
)
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
self.field.get_choices(include_blank=False, ordering=('-a',)),
|
||||||
|
[self.foo2, self.foo1]
|
||||||
|
)
|
||||||
|
|
||||||
|
def test_get_choices_reverse_related_field(self):
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
self.field.remote_field.get_choices(include_blank=False, ordering=('a',)),
|
||||||
|
[self.bar1, self.bar2]
|
||||||
|
)
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
self.field.remote_field.get_choices(include_blank=False, ordering=('-a',)),
|
||||||
|
[self.bar2, self.bar1]
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue