diff --git a/CHANGELOG.txt b/CHANGELOG.txt index a45a643ecc..69c9ff8169 100644 --- a/CHANGELOG.txt +++ b/CHANGELOG.txt @@ -7,6 +7,7 @@ Changelog * Removed support for Python 3.4 * Added support for `short_description` for field labels in modeladmin's `InspectView` (Wesley van Lee) * Rearranged SCSS folder structure to the client folder and split them approximately according to ITCSS. (Naomi Morduch Toubman, Jonny Scholes, Janneke Janssen, Hugo van den Berg) + * Fix: ModelAdmin no longer fails when filtering over a foreign key relation (Jason Dilworth, Matt Westcott) 2.5 (xx.xx.xxxx) - IN DEVELOPMENT diff --git a/CONTRIBUTORS.rst b/CONTRIBUTORS.rst index f06d246a88..50ed893f20 100644 --- a/CONTRIBUTORS.rst +++ b/CONTRIBUTORS.rst @@ -363,6 +363,7 @@ Contributors * Katie Locke * Cassidy Brooke * dthompson86 +* Jason Dilworth Translators =========== diff --git a/docs/releases/2.6.rst b/docs/releases/2.6.rst index 9270bd130b..6d96289221 100644 --- a/docs/releases/2.6.rst +++ b/docs/releases/2.6.rst @@ -21,7 +21,7 @@ Other features Bug fixes ~~~~~~~~~ - * ... + * ModelAdmin no longer fails when filtering over a foreign key relation (Jason Dilworth, Matt Westcott) Upgrade considerations diff --git a/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py b/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py index 219802d8bb..5be372d538 100644 --- a/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py +++ b/wagtail/contrib/modeladmin/tests/test_page_modeladmin.py @@ -364,3 +364,16 @@ class TestHeaderBreadcrumbs(TestCase, WagtailTestUtils): position_of_header = content_str.index('<header') # intentionally not closing tag position_of_breadcrumbs = content_str.index('<ul class="breadcrumb">') self.assertLess(position_of_header, position_of_breadcrumbs) + + +class TestSearch(TestCase, WagtailTestUtils): + fixtures = ['test_specific.json'] + + def setUp(self): + self.login() + + def test_lookup_allowed_on_parentalkey(self): + try: + self.client.get('/admin/tests/eventpage/?related_links__link_page__id__exact=1') + except AttributeError: + self.fail("Lookup on parentalkey raised AttributeError unexpectedly") diff --git a/wagtail/contrib/modeladmin/views.py b/wagtail/contrib/modeladmin/views.py index f61beb0cff..87e8da7305 100644 --- a/wagtail/contrib/modeladmin/views.py +++ b/wagtail/contrib/modeladmin/views.py @@ -3,8 +3,7 @@ from collections import OrderedDict from functools import reduce from django import forms -from django.contrib.admin import FieldListFilter, widgets -from django.contrib.admin.exceptions import DisallowedModelAdminLookup +from django.contrib.admin import FieldListFilter from django.contrib.admin.options import IncorrectLookupParameters from django.contrib.admin.utils import ( get_fields_from_path, label_for_field, lookup_needs_distinct, prepare_lookup_value, quote, unquote) @@ -12,9 +11,8 @@ from django.contrib.auth.decorators import login_required from django.core.exceptions import ImproperlyConfigured, PermissionDenied, SuspiciousOperation from django.core.paginator import InvalidPage, Paginator from django.db import models -from django.db.models.constants import LOOKUP_SEP from django.db.models.fields import FieldDoesNotExist -from django.db.models.fields.related import ForeignObjectRel, ManyToManyField +from django.db.models.fields.related import ManyToManyField from django.shortcuts import get_object_or_404, redirect from django.template.defaultfilters import filesizeformat from django.utils.decorators import method_decorator @@ -290,54 +288,6 @@ class IndexView(WMABaseView): return queryset, use_distinct - def lookup_allowed(self, lookup, value): - # Check FKey lookups that are allowed, so that popups produced by - # ForeignKeyRawIdWidget, on the basis of ForeignKey.limit_choices_to, - # are allowed to work. - for l in self.model._meta.related_fkey_lookups: - for k, v in widgets.url_params_from_lookup_dict(l).items(): - if k == lookup and v == value: - return True - - parts = lookup.split(LOOKUP_SEP) - - # Last term in lookup is a query term (__exact, __startswith etc) - # This term can be ignored. - if len(parts) > 1 and parts[-1] in QUERY_TERMS: - parts.pop() - - # Special case -- foo__id__exact and foo__id queries are implied - # if foo has been specifically included in the lookup list; so - # drop __id if it is the last part. However, first we need to find - # the pk attribute name. - rel_name = None - for part in parts[:-1]: - try: - field = self.model._meta.get_field(part) - except FieldDoesNotExist: - # Lookups on non-existent fields are ok, since they're ignored - # later. - return True - if hasattr(field, 'remote_field'): - if field.remote_field is None: - # This property or relation doesn't exist, but it's allowed - # since it's ignored in ChangeList.get_filters(). - return True - model = field.remote_field.model - rel_name = field.remote_field.get_related_field().name - elif isinstance(field, ForeignObjectRel): - model = field.model - rel_name = model._meta.pk.name - else: - rel_name = None - if rel_name and len(parts) > 1 and parts[-1] == rel_name: - parts.pop() - - if len(parts) == 1: - return True - clean_lookup = LOOKUP_SEP.join(parts) - return clean_lookup in self.list_filter - def get_filters_params(self, params=None): """ Returns all params except IGNORED_PARAMS @@ -356,11 +306,6 @@ class IndexView(WMABaseView): lookup_params = self.get_filters_params() use_distinct = False - for key, value in lookup_params.items(): - if not self.lookup_allowed(key, value): - raise DisallowedModelAdminLookup( - "Filtering by %s not allowed" % key) - filter_specs = [] if self.list_filter: for list_filter in self.list_filter: