mirror of
https://github.com/django/django.git
synced 2025-07-05 02:09:13 +00:00
[1.3.X] 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.
Backport of r17854 from trunk. git-svn-id: http://code.djangoproject.com/svn/django/branches/releases/1.3.X@17857 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
parent
0bbe7379ee
commit
e293d82c36
@ -74,9 +74,12 @@ class RelatedFilterSpec(FilterSpec):
|
|||||||
self.lookup_title = other_model._meta.verbose_name
|
self.lookup_title = other_model._meta.verbose_name
|
||||||
else:
|
else:
|
||||||
self.lookup_title = f.verbose_name # use field name
|
self.lookup_title = f.verbose_name # use field name
|
||||||
rel_name = other_model._meta.pk.name
|
if hasattr(f, 'rel'):
|
||||||
|
rel_name = f.rel.get_related_field().name
|
||||||
|
else:
|
||||||
|
rel_name = other_model._meta.pk.name
|
||||||
self.lookup_kwarg = '%s__%s__exact' % (self.field_path, rel_name)
|
self.lookup_kwarg = '%s__%s__exact' % (self.field_path, rel_name)
|
||||||
self.lookup_kwarg_isnull = '%s__isnull' % (self.field_path)
|
self.lookup_kwarg_isnull = '%s__isnull' % self.field_path
|
||||||
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
|
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
|
||||||
self.lookup_val_isnull = request.GET.get(
|
self.lookup_val_isnull = request.GET.get(
|
||||||
self.lookup_kwarg_isnull, None)
|
self.lookup_kwarg_isnull, None)
|
||||||
@ -176,7 +179,7 @@ FilterSpec.register(lambda f: bool(f.choices), ChoicesFilterSpec)
|
|||||||
|
|
||||||
class DateFieldFilterSpec(FilterSpec):
|
class DateFieldFilterSpec(FilterSpec):
|
||||||
def __init__(self, f, request, params, model, model_admin,
|
def __init__(self, f, request, params, model, model_admin,
|
||||||
field_path=None):
|
field_path=None):
|
||||||
super(DateFieldFilterSpec, self).__init__(f, request, params, model,
|
super(DateFieldFilterSpec, self).__init__(f, request, params, model,
|
||||||
model_admin,
|
model_admin,
|
||||||
field_path=field_path)
|
field_path=field_path)
|
||||||
|
@ -225,18 +225,18 @@ class BaseModelAdmin(object):
|
|||||||
# if foo has been specificially included in the lookup list; so
|
# 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
|
# drop __id if it is the last part. However, first we need to find
|
||||||
# the pk attribute name.
|
# the pk attribute name.
|
||||||
pk_attr_name = None
|
rel_name = None
|
||||||
for part in parts[:-1]:
|
for part in parts[:-1]:
|
||||||
field, _, _, _ = model._meta.get_field_by_name(part)
|
field, _, _, _ = model._meta.get_field_by_name(part)
|
||||||
if hasattr(field, 'rel'):
|
if hasattr(field, 'rel'):
|
||||||
model = field.rel.to
|
model = field.rel.to
|
||||||
pk_attr_name = model._meta.pk.name
|
rel_name = field.rel.get_related_field().name
|
||||||
elif isinstance(field, RelatedObject):
|
elif isinstance(field, RelatedObject):
|
||||||
model = field.model
|
model = field.model
|
||||||
pk_attr_name = model._meta.pk.name
|
rel_name = model._meta.pk.name
|
||||||
else:
|
else:
|
||||||
pk_attr_name = None
|
rel_name = None
|
||||||
if pk_attr_name and len(parts) > 1 and parts[-1] == pk_attr_name:
|
if rel_name and len(parts) > 1 and parts[-1] == rel_name:
|
||||||
parts.pop()
|
parts.pop()
|
||||||
|
|
||||||
try:
|
try:
|
||||||
|
@ -21,3 +21,18 @@ class BoolTest(models.Model):
|
|||||||
default=NO,
|
default=NO,
|
||||||
choices=YES_NO_CHOICES
|
choices=YES_NO_CHOICES
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
@ -6,7 +6,7 @@ from django.contrib import admin
|
|||||||
from django.contrib.admin.views.main import ChangeList
|
from django.contrib.admin.views.main import ChangeList
|
||||||
from django.utils.encoding import force_unicode
|
from django.utils.encoding import force_unicode
|
||||||
|
|
||||||
from models import Book, BoolTest
|
from models import Book, BoolTest, Employee, Department
|
||||||
|
|
||||||
def select_by(dictlist, key, value):
|
def select_by(dictlist, key, value):
|
||||||
return [x for x in dictlist if x[key] == value][0]
|
return [x for x in dictlist if x[key] == value][0]
|
||||||
@ -32,7 +32,6 @@ class FilterSpecsTests(TestCase):
|
|||||||
|
|
||||||
self.request_factory = RequestFactory()
|
self.request_factory = RequestFactory()
|
||||||
|
|
||||||
|
|
||||||
def get_changelist(self, request, model, modeladmin):
|
def get_changelist(self, request, model, modeladmin):
|
||||||
return ChangeList(request, model, modeladmin.list_display, modeladmin.list_display_links,
|
return ChangeList(request, model, modeladmin.list_display, modeladmin.list_display_links,
|
||||||
modeladmin.list_filter, modeladmin.date_hierarchy, modeladmin.search_fields,
|
modeladmin.list_filter, modeladmin.date_hierarchy, modeladmin.search_fields,
|
||||||
@ -200,6 +199,67 @@ class FilterSpecsTests(TestCase):
|
|||||||
self.assertEqual(choice['selected'], True)
|
self.assertEqual(choice['selected'], True)
|
||||||
self.assertEqual(choice['query_string'], '?completed__exact=1')
|
self.assertEqual(choice['query_string'], '?completed__exact=1')
|
||||||
|
|
||||||
|
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, admin.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()
|
||||||
|
self.assertEqual(list(queryset), [jack, 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'], 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()
|
||||||
|
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')
|
||||||
|
|
||||||
|
|
||||||
class CustomUserAdmin(UserAdmin):
|
class CustomUserAdmin(UserAdmin):
|
||||||
list_filter = ('books_authored', 'books_contributed')
|
list_filter = ('books_authored', 'books_contributed')
|
||||||
|
|
||||||
@ -209,3 +269,7 @@ class BookAdmin(admin.ModelAdmin):
|
|||||||
|
|
||||||
class BoolTestAdmin(admin.ModelAdmin):
|
class BoolTestAdmin(admin.ModelAdmin):
|
||||||
list_filter = ('completed',)
|
list_filter = ('completed',)
|
||||||
|
|
||||||
|
class EmployeeAdmin(admin.ModelAdmin):
|
||||||
|
list_display = ['name', 'department']
|
||||||
|
list_filter = ['department']
|
Loading…
x
Reference in New Issue
Block a user