Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Fixed #16716 -- Fixed two small regressions in the development versio…

…n introduced in r16144 where the changelist crashed with a 500 error instead of nicely operating a 302 redirection back to the changelist.

The two specific cases were:

* a lookup through a non-existing field and apparently spanning multiple relationships (e.g. "?nonexistant__whatever=xxxx").
* a proper list_filter's queryset failing with an exception. In Django 1.3 the queryset was only directly manipulated by the changelist, whereas in 1.4 the list_filters may manipulate the queryset themselves. The fix here implies catching potential failures from the list_filters too.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@16705 bcc190cf-cafb-0310-a4f2-bffc1f526a37
  • Loading branch information...
commit 93fbb77d9b5f4ab936c8f29b20a704d9b11be0c7 1 parent ce477f0
Julien Phalip authored August 28, 2011
43  django/contrib/admin/views/main.py
@@ -267,6 +267,7 @@ def get_lookup_params(self, use_distinct=False):
267 267
                 del lookup_params[key]
268 268
                 lookup_params[smart_str(key)] = value
269 269
 
  270
+            field = None
270 271
             if not use_distinct:
271 272
                 # Check if it's a relationship that might return more than one
272 273
                 # instance
@@ -291,7 +292,7 @@ def get_lookup_params(self, use_distinct=False):
291 292
                     value = True
292 293
                 lookup_params[key] = value
293 294
 
294  
-            if not self.model_admin.lookup_allowed(key, value):
  295
+            if field and not self.model_admin.lookup_allowed(key, value):
295 296
                 raise SuspiciousOperation("Filtering by %s not allowed" % key)
296 297
 
297 298
         return lookup_params, use_distinct
@@ -300,28 +301,30 @@ def get_query_set(self, request):
300 301
         lookup_params, use_distinct = self.get_lookup_params(use_distinct=False)
301 302
         self.filter_specs, self.has_filters = self.get_filters(request, use_distinct)
302 303
 
303  
-        # Let every list filter modify the qs and params to its liking
304  
-        qs = self.root_query_set
305  
-        for filter_spec in self.filter_specs:
306  
-            new_qs = filter_spec.queryset(request, qs)
307  
-            if new_qs is not None:
308  
-                qs = new_qs
309  
-                for param in filter_spec.used_params():
310  
-                    try:
311  
-                        del lookup_params[param]
312  
-                    except KeyError:
313  
-                        pass
314  
-
315  
-        # Apply the remaining lookup parameters from the query string (i.e.
316  
-        # those that haven't already been processed by the filters).
317 304
         try:
  305
+            # First, let every list filter modify the qs and params to its
  306
+            # liking.
  307
+            qs = self.root_query_set
  308
+            for filter_spec in self.filter_specs:
  309
+                new_qs = filter_spec.queryset(request, qs)
  310
+                if new_qs is not None:
  311
+                    qs = new_qs
  312
+                    for param in filter_spec.used_params():
  313
+                        try:
  314
+                            del lookup_params[param]
  315
+                        except KeyError:
  316
+                            pass
  317
+
  318
+            # Then, apply the remaining lookup parameters from the query string
  319
+            # (i.e. those that haven't already been processed by the filters).
318 320
             qs = qs.filter(**lookup_params)
319  
-        # Naked except! Because we don't have any other way of validating "params".
320  
-        # They might be invalid if the keyword arguments are incorrect, or if the
321  
-        # values are not in the correct type, so we might get FieldError, ValueError,
322  
-        # ValicationError, or ? from a custom field that raises yet something else
323  
-        # when handed impossible data.
324 321
         except Exception, e:
  322
+            # Naked except! Because we don't have any other way of validating
  323
+            # "lookup_params". They might be invalid if the keyword arguments
  324
+            # are incorrect, or if the values are not in the correct type, so
  325
+            # we might get FieldError, ValueError, ValicationError, or ? from a
  326
+            # custom field that raises yet something else when handed
  327
+            # impossible data.
325 328
             raise IncorrectLookupParameters(e)
326 329
 
327 330
         # Use select_related() if one of the list_display options is a field
21  tests/regressiontests/admin_filters/tests.py
... ...
@@ -1,9 +1,9 @@
1 1
 import datetime
2 2
 
  3
+from django.contrib.admin.options import IncorrectLookupParameters
3 4
 from django.core.exceptions import ImproperlyConfigured
4 5
 from django.test import TestCase, RequestFactory
5 6
 from django.utils.encoding import force_unicode
6  
-
7 7
 from django.contrib.auth.admin import UserAdmin
8 8
 from django.contrib.auth.models import User
9 9
 from django.contrib.admin.views.main import ChangeList
@@ -50,6 +50,11 @@ class DecadeListFilterWithNoneReturningLookups(DecadeListFilterWithTitleAndParam
50 50
     def lookups(self, request, model_admin):
51 51
         pass
52 52
 
  53
+class DecadeListFilterWithFailingQueryset(DecadeListFilterWithTitleAndParameter):
  54
+
  55
+    def queryset(self, request, queryset):
  56
+        raise Exception
  57
+
53 58
 class DecadeListFilterWithQuerysetBasedLookups(DecadeListFilterWithTitleAndParameter):
54 59
 
55 60
     def lookups(self, request, model_admin):
@@ -84,6 +89,9 @@ class DecadeFilterBookAdminWithoutParameter(ModelAdmin):
84 89
 class DecadeFilterBookAdminWithNoneReturningLookups(ModelAdmin):
85 90
     list_filter = (DecadeListFilterWithNoneReturningLookups,)
86 91
 
  92
+class DecadeFilterBookAdminWithFailingQueryset(ModelAdmin):
  93
+    list_filter = (DecadeListFilterWithFailingQueryset,)
  94
+
87 95
 class DecadeFilterBookAdminWithQuerysetBasedLookups(ModelAdmin):
88 96
     list_filter = (DecadeListFilterWithQuerysetBasedLookups,)
89 97
 
@@ -509,6 +517,17 @@ def test_simplelistfilter_with_none_returning_lookups(self):
509 517
         filterspec = changelist.get_filters(request)[0]
510 518
         self.assertEqual(len(filterspec), 0)
511 519
 
  520
+    def test_filter_with_failing_queryset(self):
  521
+        """
  522
+        Ensure that a filter's failing queryset is interpreted as if incorrect
  523
+        lookup parameters were passed (therefore causing a 302 redirection to
  524
+        the changelist).
  525
+        Refs #16716, #16714.
  526
+        """
  527
+        modeladmin = DecadeFilterBookAdminWithFailingQueryset(Book, site)
  528
+        request = self.request_factory.get('/', {})
  529
+        self.assertRaises(IncorrectLookupParameters, self.get_changelist, request, Book, modeladmin)
  530
+
512 531
     def test_simplelistfilter_with_queryset_based_lookups(self):
513 532
         modeladmin = DecadeFilterBookAdminWithQuerysetBasedLookups(Book, site)
514 533
         request = self.request_factory.get('/', {})
5  tests/regressiontests/admin_views/tests.py
@@ -410,6 +410,11 @@ def testIncorrectLookupParameters(self):
410 410
         """Ensure incorrect lookup parameters are handled gracefully."""
411 411
         response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'notarealfield': '5'})
412 412
         self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
  413
+
  414
+        # Spanning relationships through an inexistant related object (Refs #16716)
  415
+        response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'notarealfield__whatever': '5'})
  416
+        self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
  417
+
413 418
         response = self.client.get('/test_admin/%s/admin_views/thing/' % self.urlbit, {'color__id__exact': 'StringNotInteger!'})
414 419
         self.assertRedirects(response, '/test_admin/%s/admin_views/thing/?e=1' % self.urlbit)
415 420
 

0 notes on commit 93fbb77

Please sign in to comment.
Something went wrong with that request. Please try again.