Fixed #23616 - Fixed generic relations in ModelAdmin.list_filter.
Thanks ranjur for reporting bug, timgraham for review, and collinanderson for contributing tips.
This commit is contained in:
parent
466b38ea3d
commit
06b11b617e
|
@ -417,7 +417,10 @@ class BaseModelAdmin(six.with_metaclass(forms.MediaDefiningClass)):
|
||||||
# since it's ignored in ChangeList.get_filters().
|
# since it's ignored in ChangeList.get_filters().
|
||||||
return True
|
return True
|
||||||
model = field.rel.to
|
model = field.rel.to
|
||||||
rel_name = field.rel.get_related_field().name
|
if hasattr(field.rel, 'get_related_field'):
|
||||||
|
rel_name = field.rel.get_related_field().name
|
||||||
|
else:
|
||||||
|
rel_name = None
|
||||||
elif isinstance(field, RelatedObject):
|
elif isinstance(field, RelatedObject):
|
||||||
model = field.model
|
model = field.model
|
||||||
rel_name = model._meta.pk.name
|
rel_name = model._meta.pk.name
|
||||||
|
|
|
@ -113,3 +113,5 @@ Bugfixes
|
||||||
* Added a prompt to the migrations questioner when removing the null constraint
|
* Added a prompt to the migrations questioner when removing the null constraint
|
||||||
from a field to prevent an IntegrityError on existing NULL rows
|
from a field to prevent an IntegrityError on existing NULL rows
|
||||||
(:ticket:`23609`).
|
(:ticket:`23609`).
|
||||||
|
|
||||||
|
* Fixed generic relations in ``ModelAdmin.list_filter`` (:ticket:`23616`).
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
from django.contrib.auth.models import User
|
from django.contrib.auth.models import User
|
||||||
|
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
||||||
|
from django.contrib.contenttypes.models import ContentType
|
||||||
from django.db import models
|
from django.db import models
|
||||||
from django.utils.encoding import python_2_unicode_compatible
|
from django.utils.encoding import python_2_unicode_compatible
|
||||||
|
|
||||||
|
@ -35,3 +37,23 @@ class Employee(models.Model):
|
||||||
|
|
||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class TaggedItem(models.Model):
|
||||||
|
tag = models.SlugField()
|
||||||
|
content_type = models.ForeignKey(ContentType, related_name='tagged_items')
|
||||||
|
object_id = models.PositiveIntegerField()
|
||||||
|
content_object = GenericForeignKey('content_type', 'object_id')
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.tag
|
||||||
|
|
||||||
|
|
||||||
|
@python_2_unicode_compatible
|
||||||
|
class Bookmark(models.Model):
|
||||||
|
url = models.URLField()
|
||||||
|
tags = GenericRelation(TaggedItem)
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return self.url
|
||||||
|
|
|
@ -12,7 +12,7 @@ from django.test import TestCase, RequestFactory, override_settings
|
||||||
from django.utils.encoding import force_text
|
from django.utils.encoding import force_text
|
||||||
from django.utils import six
|
from django.utils import six
|
||||||
|
|
||||||
from .models import Book, Department, Employee
|
from .models import Book, Department, Employee, Bookmark, TaggedItem
|
||||||
|
|
||||||
|
|
||||||
def select_by(dictlist, key, value):
|
def select_by(dictlist, key, value):
|
||||||
|
@ -205,6 +205,10 @@ class DepartmentFilterDynamicValueBookAdmin(EmployeeAdmin):
|
||||||
list_filter = [DepartmentListFilterLookupWithDynamicValue, ]
|
list_filter = [DepartmentListFilterLookupWithDynamicValue, ]
|
||||||
|
|
||||||
|
|
||||||
|
class BookmarkAdminGenericRelation(ModelAdmin):
|
||||||
|
list_filter = ['tags__tag']
|
||||||
|
|
||||||
|
|
||||||
class ListFiltersTests(TestCase):
|
class ListFiltersTests(TestCase):
|
||||||
|
|
||||||
def setUp(self):
|
def setUp(self):
|
||||||
|
@ -539,6 +543,24 @@ class ListFiltersTests(TestCase):
|
||||||
expected = [(self.bob.pk, 'bob'), (self.lisa.pk, 'lisa')]
|
expected = [(self.bob.pk, 'bob'), (self.lisa.pk, 'lisa')]
|
||||||
self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
|
self.assertEqual(sorted(filterspec.lookup_choices), sorted(expected))
|
||||||
|
|
||||||
|
def test_listfilter_genericrelation(self):
|
||||||
|
django_bookmark = Bookmark.objects.create(url='https://www.djangoproject.com/')
|
||||||
|
python_bookmark = Bookmark.objects.create(url='https://www.python.org/')
|
||||||
|
kernel_bookmark = Bookmark.objects.create(url='https://www.kernel.org/')
|
||||||
|
|
||||||
|
TaggedItem.objects.create(content_object=django_bookmark, tag='python')
|
||||||
|
TaggedItem.objects.create(content_object=python_bookmark, tag='python')
|
||||||
|
TaggedItem.objects.create(content_object=kernel_bookmark, tag='linux')
|
||||||
|
|
||||||
|
modeladmin = BookmarkAdminGenericRelation(Bookmark, site)
|
||||||
|
|
||||||
|
request = self.request_factory.get('/', {'tags__tag': 'python'})
|
||||||
|
changelist = self.get_changelist(request, Bookmark, modeladmin)
|
||||||
|
queryset = changelist.get_queryset(request)
|
||||||
|
|
||||||
|
expected = [python_bookmark, django_bookmark]
|
||||||
|
self.assertEqual(list(queryset), expected)
|
||||||
|
|
||||||
def test_booleanfieldlistfilter(self):
|
def test_booleanfieldlistfilter(self):
|
||||||
modeladmin = BookAdmin(Book, site)
|
modeladmin = BookAdmin(Book, site)
|
||||||
self.verify_booleanfieldlistfilter(modeladmin)
|
self.verify_booleanfieldlistfilter(modeladmin)
|
||||||
|
|
Loading…
Reference in New Issue