Fixed #30449 -- Fixed RelatedFieldListFilter/RelatedOnlyFieldListFilter to respect model's Meta.ordering.
Regression in 6d4e5feb79
.
Co-Authored-By: Mariusz Felisiak <felisiak.mariusz@gmail.com>
This commit is contained in:
parent
1f8382d34d
commit
00035672a4
|
@ -825,9 +825,11 @@ class Field(RegisterLookupMixin):
|
||||||
if hasattr(self.remote_field, 'get_related_field')
|
if hasattr(self.remote_field, 'get_related_field')
|
||||||
else 'pk'
|
else 'pk'
|
||||||
)
|
)
|
||||||
|
qs = rel_model._default_manager.complex_filter(limit_choices_to)
|
||||||
|
if ordering:
|
||||||
|
qs = qs.order_by(*ordering)
|
||||||
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 qs
|
||||||
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):
|
||||||
|
|
|
@ -122,8 +122,11 @@ class ForeignObjectRel(FieldCacheMixin):
|
||||||
Analog of django.db.models.fields.Field.get_choices(), provided
|
Analog of django.db.models.fields.Field.get_choices(), provided
|
||||||
initially for utilization by RelatedFieldListFilter.
|
initially for utilization by RelatedFieldListFilter.
|
||||||
"""
|
"""
|
||||||
|
qs = self.related_model._default_manager.all()
|
||||||
|
if ordering:
|
||||||
|
qs = qs.order_by(*ordering)
|
||||||
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.order_by(*ordering)
|
(x.pk, str(x)) for x in qs
|
||||||
]
|
]
|
||||||
|
|
||||||
def is_hidden(self):
|
def is_hidden(self):
|
||||||
|
|
|
@ -17,3 +17,8 @@ Bugfixes
|
||||||
:class:`~django.contrib.postgres.fields.JSONField` and
|
:class:`~django.contrib.postgres.fields.JSONField` and
|
||||||
:class:`~django.contrib.postgres.fields.HStoreField` when using on
|
:class:`~django.contrib.postgres.fields.HStoreField` when using on
|
||||||
expressions with params (:ticket:`30672`).
|
expressions with params (:ticket:`30672`).
|
||||||
|
|
||||||
|
* Fixed a regression in Django 2.2 where
|
||||||
|
:attr:`ModelAdmin.list_filter <django.contrib.admin.ModelAdmin.list_filter>`
|
||||||
|
choices to foreign objects don't respect a model's ``Meta.ordering``
|
||||||
|
(:ticket:`30449`).
|
||||||
|
|
|
@ -591,6 +591,22 @@ class ListFiltersTests(TestCase):
|
||||||
expected = [(self.john.pk, 'John Blue'), (self.jack.pk, 'Jack Red')]
|
expected = [(self.john.pk, 'John Blue'), (self.jack.pk, 'Jack Red')]
|
||||||
self.assertEqual(filterspec.lookup_choices, expected)
|
self.assertEqual(filterspec.lookup_choices, expected)
|
||||||
|
|
||||||
|
def test_relatedfieldlistfilter_foreignkey_default_ordering(self):
|
||||||
|
"""RelatedFieldListFilter ordering respects Model.ordering."""
|
||||||
|
class BookAdmin(ModelAdmin):
|
||||||
|
list_filter = ('employee',)
|
||||||
|
|
||||||
|
self.addCleanup(setattr, Employee._meta, 'ordering', Employee._meta.ordering)
|
||||||
|
Employee._meta.ordering = ('name',)
|
||||||
|
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_manytomany(self):
|
def test_relatedfieldlistfilter_manytomany(self):
|
||||||
modeladmin = BookAdmin(Book, site)
|
modeladmin = BookAdmin(Book, site)
|
||||||
|
|
||||||
|
@ -696,6 +712,23 @@ class ListFiltersTests(TestCase):
|
||||||
filterspec = changelist.get_filters(request)[0]
|
filterspec = changelist.get_filters(request)[0]
|
||||||
self.assertEqual(len(filterspec), 0)
|
self.assertEqual(len(filterspec), 0)
|
||||||
|
|
||||||
|
def test_relatedfieldlistfilter_reverse_relationships_default_ordering(self):
|
||||||
|
self.addCleanup(setattr, Book._meta, 'ordering', Book._meta.ordering)
|
||||||
|
Book._meta.ordering = ('title',)
|
||||||
|
modeladmin = CustomUserAdmin(User, 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.bio_book.pk, 'Django: a biography'),
|
||||||
|
(self.djangonaut_book.pk, 'Djangonaut: an art of living'),
|
||||||
|
(self.guitar_book.pk, 'Guitar for dummies'),
|
||||||
|
(self.django_book.pk, 'The Django Book')
|
||||||
|
]
|
||||||
|
self.assertEqual(filterspec.lookup_choices, expected)
|
||||||
|
|
||||||
def test_relatedonlyfieldlistfilter_foreignkey(self):
|
def test_relatedonlyfieldlistfilter_foreignkey(self):
|
||||||
modeladmin = BookAdminRelatedOnlyFilter(Book, site)
|
modeladmin = BookAdminRelatedOnlyFilter(Book, site)
|
||||||
|
|
||||||
|
@ -708,6 +741,30 @@ class ListFiltersTests(TestCase):
|
||||||
expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob')]
|
expected = [(self.alfred.pk, 'alfred'), (self.bob.pk, 'bob')]
|
||||||
self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
|
self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
|
||||||
|
|
||||||
|
def test_relatedonlyfieldlistfilter_foreignkey_default_ordering(self):
|
||||||
|
"""RelatedOnlyFieldListFilter ordering respects Meta.ordering."""
|
||||||
|
class BookAdmin(ModelAdmin):
|
||||||
|
list_filter = (
|
||||||
|
('employee', RelatedOnlyFieldListFilter),
|
||||||
|
)
|
||||||
|
|
||||||
|
albert = Employee.objects.create(name='Albert Green', department=self.dev)
|
||||||
|
self.djangonaut_book.employee = albert
|
||||||
|
self.djangonaut_book.save()
|
||||||
|
self.bio_book.employee = self.jack
|
||||||
|
self.bio_book.save()
|
||||||
|
|
||||||
|
self.addCleanup(setattr, Employee._meta, 'ordering', Employee._meta.ordering)
|
||||||
|
Employee._meta.ordering = ('name',)
|
||||||
|
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 = [(albert.pk, 'Albert Green'), (self.jack.pk, 'Jack Red')]
|
||||||
|
self.assertEqual(filterspec.lookup_choices, expected)
|
||||||
|
|
||||||
def test_relatedonlyfieldlistfilter_underscorelookup_foreignkey(self):
|
def test_relatedonlyfieldlistfilter_underscorelookup_foreignkey(self):
|
||||||
Department.objects.create(code='TEST', description='Testing')
|
Department.objects.create(code='TEST', description='Testing')
|
||||||
self.djangonaut_book.employee = self.john
|
self.djangonaut_book.employee = self.john
|
||||||
|
|
|
@ -222,9 +222,9 @@ class GetChoicesOrderingTests(TestCase):
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def setUpTestData(cls):
|
def setUpTestData(cls):
|
||||||
cls.foo1 = Foo.objects.create(a='a', d='12.34')
|
cls.foo1 = Foo.objects.create(a='a', d='12.35')
|
||||||
cls.foo2 = Foo.objects.create(a='b', d='12.34')
|
cls.foo2 = Foo.objects.create(a='b', d='12.34')
|
||||||
cls.bar1 = Bar.objects.create(a=cls.foo1, b='a')
|
cls.bar1 = Bar.objects.create(a=cls.foo1, b='b')
|
||||||
cls.bar2 = Bar.objects.create(a=cls.foo2, b='a')
|
cls.bar2 = Bar.objects.create(a=cls.foo2, b='a')
|
||||||
cls.field = Bar._meta.get_field('a')
|
cls.field = Bar._meta.get_field('a')
|
||||||
|
|
||||||
|
@ -241,6 +241,14 @@ class GetChoicesOrderingTests(TestCase):
|
||||||
[self.foo2, self.foo1]
|
[self.foo2, self.foo1]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_choices_default_ordering(self):
|
||||||
|
self.addCleanup(setattr, Foo._meta, 'ordering', Foo._meta.ordering)
|
||||||
|
Foo._meta.ordering = ('d',)
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
self.field.get_choices(include_blank=False),
|
||||||
|
[self.foo2, self.foo1]
|
||||||
|
)
|
||||||
|
|
||||||
def test_get_choices_reverse_related_field(self):
|
def test_get_choices_reverse_related_field(self):
|
||||||
self.assertChoicesEqual(
|
self.assertChoicesEqual(
|
||||||
self.field.remote_field.get_choices(include_blank=False, ordering=('a',)),
|
self.field.remote_field.get_choices(include_blank=False, ordering=('a',)),
|
||||||
|
@ -250,3 +258,11 @@ class GetChoicesOrderingTests(TestCase):
|
||||||
self.field.remote_field.get_choices(include_blank=False, ordering=('-a',)),
|
self.field.remote_field.get_choices(include_blank=False, ordering=('-a',)),
|
||||||
[self.bar2, self.bar1]
|
[self.bar2, self.bar1]
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_choices_reverse_related_field_default_ordering(self):
|
||||||
|
self.addCleanup(setattr, Bar._meta, 'ordering', Bar._meta.ordering)
|
||||||
|
Bar._meta.ordering = ('b',)
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
self.field.remote_field.get_choices(include_blank=False),
|
||||||
|
[self.bar2, self.bar1]
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue