Fixed #17972 -- Ensured that admin filters on a foreign key respect the `to_field` attribute. This fixes a regression introduced in [14674] and Django 1.3. Thanks to graveyboat and Karen Tracey for the report.
git-svn-id: http://code.djangoproject.com/svn/django/trunk@17854 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
ad355e48ce
commit
c39e1cff99
|
@ -155,7 +155,10 @@ class FieldListFilter(ListFilter):
|
|||
class RelatedFieldListFilter(FieldListFilter):
|
||||
def __init__(self, field, request, params, model, model_admin, field_path):
|
||||
other_model = get_model_from_relation(field)
|
||||
rel_name = other_model._meta.pk.name
|
||||
if hasattr(field, 'rel'):
|
||||
rel_name = field.rel.get_related_field().name
|
||||
else:
|
||||
rel_name = other_model._meta.pk.name
|
||||
self.lookup_kwarg = '%s__%s__exact' % (field_path, rel_name)
|
||||
self.lookup_kwarg_isnull = '%s__isnull' % field_path
|
||||
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
|
||||
|
|
|
@ -245,7 +245,7 @@ class BaseModelAdmin(object):
|
|||
# if foo has been specificially included in the lookup list; so
|
||||
# drop __id if it is the last part. However, first we need to find
|
||||
# the pk attribute name.
|
||||
pk_attr_name = None
|
||||
rel_name = None
|
||||
for part in parts[:-1]:
|
||||
try:
|
||||
field, _, _, _ = model._meta.get_field_by_name(part)
|
||||
|
@ -255,13 +255,13 @@ class BaseModelAdmin(object):
|
|||
return True
|
||||
if hasattr(field, 'rel'):
|
||||
model = field.rel.to
|
||||
pk_attr_name = model._meta.pk.name
|
||||
rel_name = field.rel.get_related_field().name
|
||||
elif isinstance(field, RelatedObject):
|
||||
model = field.model
|
||||
pk_attr_name = model._meta.pk.name
|
||||
rel_name = model._meta.pk.name
|
||||
else:
|
||||
pk_attr_name = None
|
||||
if pk_attr_name and len(parts) > 1 and parts[-1] == pk_attr_name:
|
||||
rel_name = None
|
||||
if rel_name and len(parts) > 1 and parts[-1] == rel_name:
|
||||
parts.pop()
|
||||
|
||||
if len(parts) == 1:
|
||||
|
|
|
@ -13,3 +13,18 @@ class Book(models.Model):
|
|||
|
||||
def __unicode__(self):
|
||||
return self.title
|
||||
|
||||
|
||||
class Department(models.Model):
|
||||
code = models.CharField(max_length=4, unique=True)
|
||||
description = models.CharField(max_length=50, blank=True, null=True)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.description
|
||||
|
||||
class Employee(models.Model):
|
||||
department = models.ForeignKey(Department, to_field="code")
|
||||
name = models.CharField(max_length=100)
|
||||
|
||||
def __unicode__(self):
|
||||
return self.name
|
|
@ -4,7 +4,6 @@ import datetime
|
|||
|
||||
from django.contrib.admin import (site, ModelAdmin, SimpleListFilter,
|
||||
BooleanFieldListFilter)
|
||||
from django.contrib.admin.options import IncorrectLookupParameters
|
||||
from django.contrib.admin.views.main import ChangeList
|
||||
from django.contrib.auth.admin import UserAdmin
|
||||
from django.contrib.auth.models import User
|
||||
|
@ -13,7 +12,7 @@ from django.test import TestCase, RequestFactory
|
|||
from django.test.utils import override_settings
|
||||
from django.utils.encoding import force_unicode
|
||||
|
||||
from .models import Book
|
||||
from .models import Book, Department, Employee
|
||||
|
||||
|
||||
def select_by(dictlist, key, value):
|
||||
|
@ -113,6 +112,9 @@ class DecadeFilterBookAdminParameterEndsWith__In(ModelAdmin):
|
|||
class DecadeFilterBookAdminParameterEndsWith__Isnull(ModelAdmin):
|
||||
list_filter = (DecadeListFilterParameterEndsWith__Isnull,)
|
||||
|
||||
class EmployeeAdmin(ModelAdmin):
|
||||
list_display = ['name', 'department']
|
||||
list_filter = ['department']
|
||||
|
||||
|
||||
class ListFiltersTests(TestCase):
|
||||
|
@ -633,4 +635,64 @@ class ListFiltersTests(TestCase):
|
|||
choices = list(filterspec.choices(changelist))
|
||||
self.assertEqual(choices[2]['display'], u'the 1990\'s')
|
||||
self.assertEqual(choices[2]['selected'], True)
|
||||
self.assertEqual(choices[2]['query_string'], '?decade__isnull=the+90s')
|
||||
self.assertEqual(choices[2]['query_string'], '?decade__isnull=the+90s')
|
||||
|
||||
def test_fk_with_to_field(self):
|
||||
"""
|
||||
Ensure that a filter on a FK respects the FK's to_field attribute.
|
||||
Refs #17972.
|
||||
"""
|
||||
modeladmin = EmployeeAdmin(Employee, site)
|
||||
|
||||
dev = Department.objects.create(code='DEV', description='Development')
|
||||
design = Department.objects.create(code='DSN', description='Design')
|
||||
john = Employee.objects.create(name='John Blue', department=dev)
|
||||
jack = Employee.objects.create(name='Jack Red', department=design)
|
||||
|
||||
request = self.request_factory.get('/', {})
|
||||
changelist = self.get_changelist(request, Employee, modeladmin)
|
||||
|
||||
# Make sure the correct queryset is returned
|
||||
queryset = changelist.get_query_set(request)
|
||||
self.assertEqual(list(queryset), [john, jack])
|
||||
|
||||
filterspec = changelist.get_filters(request)[0][-1]
|
||||
self.assertEqual(force_unicode(filterspec.title), u'department')
|
||||
choices = list(filterspec.choices(changelist))
|
||||
|
||||
self.assertEqual(choices[0]['display'], u'All')
|
||||
self.assertEqual(choices[0]['selected'], True)
|
||||
self.assertEqual(choices[0]['query_string'], '?')
|
||||
|
||||
self.assertEqual(choices[1]['display'], u'Development')
|
||||
self.assertEqual(choices[1]['selected'], False)
|
||||
self.assertEqual(choices[1]['query_string'], '?department__code__exact=DEV')
|
||||
|
||||
self.assertEqual(choices[2]['display'], u'Design')
|
||||
self.assertEqual(choices[2]['selected'], False)
|
||||
self.assertEqual(choices[2]['query_string'], '?department__code__exact=DSN')
|
||||
|
||||
# Filter by Department=='Development' --------------------------------
|
||||
|
||||
request = self.request_factory.get('/', {'department__code__exact': 'DEV'})
|
||||
changelist = self.get_changelist(request, Employee, modeladmin)
|
||||
|
||||
# Make sure the correct queryset is returned
|
||||
queryset = changelist.get_query_set(request)
|
||||
self.assertEqual(list(queryset), [john])
|
||||
|
||||
filterspec = changelist.get_filters(request)[0][-1]
|
||||
self.assertEqual(force_unicode(filterspec.title), u'department')
|
||||
choices = list(filterspec.choices(changelist))
|
||||
|
||||
self.assertEqual(choices[0]['display'], u'All')
|
||||
self.assertEqual(choices[0]['selected'], False)
|
||||
self.assertEqual(choices[0]['query_string'], '?')
|
||||
|
||||
self.assertEqual(choices[1]['display'], u'Development')
|
||||
self.assertEqual(choices[1]['selected'], True)
|
||||
self.assertEqual(choices[1]['query_string'], '?department__code__exact=DEV')
|
||||
|
||||
self.assertEqual(choices[2]['display'], u'Design')
|
||||
self.assertEqual(choices[2]['selected'], False)
|
||||
self.assertEqual(choices[2]['query_string'], '?department__code__exact=DSN')
|
||||
|
|
Loading…
Reference in New Issue