summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAnton Samarchyan <anton.samarchyan@savoirfairelinux.com>2017-01-16 15:06:48 -0500
committerTim Graham <timograham@gmail.com>2017-02-07 19:33:26 -0500
commitb27166b7690fbe5d695b828361a74699ddd2678a (patch)
tree527dd0c1f0343a3364bb6ae73c38dee9d4729b13
parent27793431cf21a82809c0c39a7c0188a2d83bf475 (diff)
Fixed #27356 -- Fixed ModelAdmin.lookup_allowed() for some nested relations.
-rw-r--r--django/contrib/admin/options.py16
-rw-r--r--tests/modeladmin/tests.py29
2 files changed, 39 insertions, 6 deletions
diff --git a/django/contrib/admin/options.py b/django/contrib/admin/options.py
index 70b2ccba21..5a5682a6cd 100644
--- a/django/contrib/admin/options.py
+++ b/django/contrib/admin/options.py
@@ -371,16 +371,20 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
if len(relation_parts) <= 1:
# Either a local field filter, or no fields at all.
return True
- clean_lookup = LOOKUP_SEP.join(relation_parts)
- valid_lookups = [self.date_hierarchy]
+ valid_lookups = {self.date_hierarchy}
for filter_item in self.list_filter:
if isinstance(filter_item, type) and issubclass(filter_item, SimpleListFilter):
- valid_lookups.append(filter_item.parameter_name)
+ valid_lookups.add(filter_item.parameter_name)
elif isinstance(filter_item, (list, tuple)):
- valid_lookups.append(filter_item[0])
+ valid_lookups.add(filter_item[0])
else:
- valid_lookups.append(filter_item)
- return clean_lookup in valid_lookups
+ valid_lookups.add(filter_item)
+
+ # Is it a valid relational lookup?
+ return not {
+ LOOKUP_SEP.join(relation_parts),
+ LOOKUP_SEP.join(relation_parts + [part])
+ }.isdisjoint(valid_lookups)
def to_field_allowed(self, request, to_field):
"""
diff --git a/tests/modeladmin/tests.py b/tests/modeladmin/tests.py
index b85764a290..4862664dbc 100644
--- a/tests/modeladmin/tests.py
+++ b/tests/modeladmin/tests.py
@@ -8,8 +8,10 @@ from django.contrib.admin.options import (
from django.contrib.admin.sites import AdminSite
from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect
from django.contrib.auth.models import User
+from django.db import models
from django.forms.widgets import Select
from django.test import SimpleTestCase, TestCase
+from django.test.utils import isolate_apps
from .models import Band, Concert
@@ -90,6 +92,33 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site)
self.assertTrue(ma.lookup_allowed('name__nonexistent', 'test_value'))
+ @isolate_apps('modeladmin')
+ def test_lookup_allowed_onetoone(self):
+ class Department(models.Model):
+ code = models.CharField(max_length=4, unique=True)
+
+ class Employee(models.Model):
+ department = models.ForeignKey(Department, models.CASCADE, to_field="code")
+
+ class EmployeeProfile(models.Model):
+ employee = models.OneToOneField(Employee, models.CASCADE)
+
+ class EmployeeInfo(models.Model):
+ employee = models.OneToOneField(Employee, models.CASCADE)
+ description = models.CharField(max_length=100)
+
+ class EmployeeProfileAdmin(ModelAdmin):
+ list_filter = [
+ 'employee__employeeinfo__description',
+ 'employee__department__code',
+ ]
+
+ ma = EmployeeProfileAdmin(EmployeeProfile, self.site)
+ # Reverse OneToOneField
+ self.assertIs(ma.lookup_allowed('employee__employeeinfo__description', 'test_value'), True)
+ # OneToOneField and ForeignKey
+ self.assertIs(ma.lookup_allowed('employee__department__code', 'test_value'), True)
+
def test_field_arguments(self):
# If fields is specified, fieldsets_add and fieldsets_change should
# just stick the fields into a formsets structure and return it.