Fixed #27356 -- Fixed ModelAdmin.lookup_allowed() for some nested relations.

This commit is contained in:
Anton Samarchyan 2017-01-16 15:06:48 -05:00 committed by Tim Graham
parent 27793431cf
commit b27166b769
2 changed files with 39 additions and 6 deletions

View File

@ -371,16 +371,20 @@ class BaseModelAdmin(metaclass=forms.MediaDefiningClass):
if len(relation_parts) <= 1: if len(relation_parts) <= 1:
# Either a local field filter, or no fields at all. # Either a local field filter, or no fields at all.
return True 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: for filter_item in self.list_filter:
if isinstance(filter_item, type) and issubclass(filter_item, SimpleListFilter): 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)): elif isinstance(filter_item, (list, tuple)):
valid_lookups.append(filter_item[0]) valid_lookups.add(filter_item[0])
else: else:
valid_lookups.append(filter_item) valid_lookups.add(filter_item)
return clean_lookup in valid_lookups
# 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): def to_field_allowed(self, request, to_field):
""" """

View File

@ -8,8 +8,10 @@ from django.contrib.admin.options import (
from django.contrib.admin.sites import AdminSite from django.contrib.admin.sites import AdminSite
from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect from django.contrib.admin.widgets import AdminDateWidget, AdminRadioSelect
from django.contrib.auth.models import User from django.contrib.auth.models import User
from django.db import models
from django.forms.widgets import Select from django.forms.widgets import Select
from django.test import SimpleTestCase, TestCase from django.test import SimpleTestCase, TestCase
from django.test.utils import isolate_apps
from .models import Band, Concert from .models import Band, Concert
@ -90,6 +92,33 @@ class ModelAdminTests(TestCase):
ma = BandAdmin(Band, self.site) ma = BandAdmin(Band, self.site)
self.assertTrue(ma.lookup_allowed('name__nonexistent', 'test_value')) 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): def test_field_arguments(self):
# If fields is specified, fieldsets_add and fieldsets_change should # If fields is specified, fieldsets_add and fieldsets_change should
# just stick the fields into a formsets structure and return it. # just stick the fields into a formsets structure and return it.