Fixed #29919 -- Fixed RelatedOnlyFieldListFilter crash with reverse relationships.
This commit is contained in:
parent
f3855a8d2d
commit
bc94e3c1a2
|
@ -114,7 +114,10 @@ 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, ordering=()):
|
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.
|
||||||
|
@ -122,7 +125,8 @@ 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()
|
limit_choices_to = limit_choices_to or self.limit_choices_to
|
||||||
|
qs = self.related_model._default_manager.complex_filter(limit_choices_to)
|
||||||
if ordering:
|
if ordering:
|
||||||
qs = qs.order_by(*ordering)
|
qs = qs.order_by(*ordering)
|
||||||
return (blank_choice if include_blank else []) + [
|
return (blank_choice if include_blank else []) + [
|
||||||
|
|
|
@ -741,6 +741,43 @@ 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_reverse_relationships(self):
|
||||||
|
class EmployeeAdminReverseRelationship(ModelAdmin):
|
||||||
|
list_filter = (
|
||||||
|
('book', RelatedOnlyFieldListFilter),
|
||||||
|
)
|
||||||
|
|
||||||
|
self.djangonaut_book.employee = self.john
|
||||||
|
self.djangonaut_book.save()
|
||||||
|
self.django_book.employee = self.jack
|
||||||
|
self.django_book.save()
|
||||||
|
|
||||||
|
modeladmin = EmployeeAdminReverseRelationship(Employee, site)
|
||||||
|
request = self.request_factory.get('/')
|
||||||
|
request.user = self.alfred
|
||||||
|
changelist = modeladmin.get_changelist_instance(request)
|
||||||
|
filterspec = changelist.get_filters(request)[0][0]
|
||||||
|
self.assertEqual(filterspec.lookup_choices, [
|
||||||
|
(self.djangonaut_book.pk, 'Djangonaut: an art of living'),
|
||||||
|
(self.django_book.pk, 'The Django Book'),
|
||||||
|
])
|
||||||
|
|
||||||
|
def test_relatedonlyfieldlistfilter_manytomany_reverse_relationships(self):
|
||||||
|
class UserAdminReverseRelationship(ModelAdmin):
|
||||||
|
list_filter = (
|
||||||
|
('books_contributed', RelatedOnlyFieldListFilter),
|
||||||
|
)
|
||||||
|
|
||||||
|
modeladmin = UserAdminReverseRelationship(User, site)
|
||||||
|
request = self.request_factory.get('/')
|
||||||
|
request.user = self.alfred
|
||||||
|
changelist = modeladmin.get_changelist_instance(request)
|
||||||
|
filterspec = changelist.get_filters(request)[0][0]
|
||||||
|
self.assertEqual(
|
||||||
|
filterspec.lookup_choices,
|
||||||
|
[(self.guitar_book.pk, 'Guitar for dummies')],
|
||||||
|
)
|
||||||
|
|
||||||
def test_relatedonlyfieldlistfilter_foreignkey_ordering(self):
|
def test_relatedonlyfieldlistfilter_foreignkey_ordering(self):
|
||||||
"""RelatedOnlyFieldListFilter ordering respects ModelAdmin.ordering."""
|
"""RelatedOnlyFieldListFilter ordering respects ModelAdmin.ordering."""
|
||||||
class EmployeeAdminWithOrdering(ModelAdmin):
|
class EmployeeAdminWithOrdering(ModelAdmin):
|
||||||
|
|
|
@ -289,3 +289,14 @@ class GetChoicesLimitChoicesToTests(TestCase):
|
||||||
self.field.get_choices(include_blank=False, limit_choices_to={}),
|
self.field.get_choices(include_blank=False, limit_choices_to={}),
|
||||||
[self.foo1, self.foo2],
|
[self.foo1, self.foo2],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def test_get_choices_reverse_related_field(self):
|
||||||
|
field = self.field.remote_field
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
field.get_choices(include_blank=False, limit_choices_to={'b': 'b'}),
|
||||||
|
[self.bar1],
|
||||||
|
)
|
||||||
|
self.assertChoicesEqual(
|
||||||
|
field.get_choices(include_blank=False, limit_choices_to={}),
|
||||||
|
[self.bar1, self.bar2],
|
||||||
|
)
|
||||||
|
|
Loading…
Reference in New Issue