mirror of
				https://github.com/django/django.git
				synced 2025-10-31 09:41:08 +00:00 
			
		
		
		
	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:
		| @@ -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) | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user