+44
-4
lines changedFilter options
+44
-4
lines changed Original file line number Diff line number Diff line change
@@ -10,7 +10,9 @@
10
10
from django.views.decorators.csrf import csrf_protect
11
11
from django.core.exceptions import PermissionDenied, ValidationError
12
12
from django.db import models, transaction
13
-
from django.db.models.fields import BLANK_CHOICE_DASH
13
+
from django.db.models.related import RelatedObject
14
+
from django.db.models.fields import BLANK_CHOICE_DASH, FieldDoesNotExist
15
+
from django.db.models.sql.constants import LOOKUP_SEP, QUERY_TERMS
14
16
from django.http import Http404, HttpResponse, HttpResponseRedirect
15
17
from django.shortcuts import get_object_or_404, render_to_response
16
18
from django.utils.decorators import method_decorator
@@ -183,6 +185,30 @@ def _declared_fieldsets(self):
183
185
def get_readonly_fields(self, request, obj=None):
184
186
return self.readonly_fields
185
187
188
+
def lookup_allowed(self, lookup):
189
+
parts = lookup.split(LOOKUP_SEP)
190
+
191
+
# Last term in lookup is a query term (__exact, __startswith etc)
192
+
# This term can be ignored.
193
+
if len(parts) > 1 and parts[-1] in QUERY_TERMS:
194
+
parts.pop()
195
+
196
+
# Special case -- foo__id__exact and foo__id queries are implied
197
+
# if foo has been specificially included in the lookup list; so
198
+
# drop __id if it is the last part.
199
+
if len(parts) > 1 and parts[-1] == self.model._meta.pk.name:
200
+
parts.pop()
201
+
202
+
try:
203
+
self.model._meta.get_field_by_name(parts[0])
204
+
except FieldDoesNotExist:
205
+
# Lookups on non-existants fields are ok, since they're ignored
206
+
# later.
207
+
return True
208
+
else:
209
+
clean_lookup = LOOKUP_SEP.join(parts)
210
+
return clean_lookup in self.list_filter or clean_lookup == self.date_hierarchy
211
+
186
212
class ModelAdmin(BaseModelAdmin):
187
213
"Encapsulates all admin options and functionality for a given model."
188
214
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
1
1
from django.contrib.admin.filterspecs import FilterSpec
2
2
from django.contrib.admin.options import IncorrectLookupParameters
3
3
from django.contrib.admin.util import quote
4
+
from django.core.exceptions import SuspiciousOperation
4
5
from django.core.paginator import Paginator, InvalidPage
5
6
from django.db import models
6
7
from django.db.models.query import QuerySet
@@ -187,13 +188,18 @@ def get_query_set(self):
187
188
else:
188
189
lookup_params[key] = True
189
190
191
+
if not self.model_admin.lookup_allowed(key):
192
+
raise SuspiciousOperation(
193
+
"Filtering by %s not allowed" % key
194
+
)
195
+
190
196
# Apply lookup parameters from the query string.
191
197
try:
192
198
qs = qs.filter(**lookup_params)
193
199
# Naked except! Because we don't have any other way of validating "params".
194
200
# They might be invalid if the keyword arguments are incorrect, or if the
195
201
# values are not in the correct type, so we might get FieldError, ValueError,
196
-
# ValicationError, or ? from a custom field that raises yet something else
202
+
# ValicationError, or ? from a custom field that raises yet something else
197
203
# when handed impossible data.
198
204
except:
199
205
raise IncorrectLookupParameters
Original file line number Diff line number Diff line change
@@ -92,7 +92,7 @@ class ChapterInline(admin.TabularInline):
92
92
93
93
class ArticleAdmin(admin.ModelAdmin):
94
94
list_display = ('content', 'date', callable_year, 'model_year', 'modeladmin_year')
95
-
list_filter = ('date',)
95
+
list_filter = ('date', 'section')
96
96
97
97
def changelist_view(self, request):
98
98
"Test that extra_context works"
@@ -584,6 +584,9 @@ class Album(models.Model):
584
584
owner = models.ForeignKey(User)
585
585
title = models.CharField(max_length=30)
586
586
587
+
class AlbumAdmin(admin.ModelAdmin):
588
+
list_filter = ['title']
589
+
587
590
admin.site.register(Article, ArticleAdmin)
588
591
admin.site.register(CustomArticle, CustomArticleAdmin)
589
592
admin.site.register(Section, save_as=True, inlines=[ArticleInline])
@@ -630,4 +633,4 @@ class Album(models.Model):
630
633
admin.site.register(ChapterXtra1)
631
634
admin.site.register(Pizza, PizzaAdmin)
632
635
admin.site.register(Topping)
633
-
admin.site.register(Album)
636
+
admin.site.register(Album, AlbumAdmin)
Original file line number Diff line number Diff line change
@@ -4,6 +4,7 @@
4
4
import datetime
5
5
6
6
from django.conf import settings
7
+
from django.core.exceptions import SuspiciousOperation
7
8
from django.core.files import temp as tempfile
8
9
# Register auth models with the admin.
9
10
from django.contrib.auth import REDIRECT_FIELD_NAME, admin
@@ -300,6 +301,10 @@ def testI18NLanguageNonEnglishFallback(self):
300
301
self.assertContains(response, 'Choisir une heure')
301
302
deactivate()
302
303
304
+
def test_disallowed_filtering(self):
305
+
self.assertRaises(SuspiciousOperation,
306
+
self.client.get, "/test_admin/admin/admin_views/album/?owner__email__startswith=fuzzy"
307
+
)
303
308
304
309
class SaveAsTests(TestCase):
305
310
fixtures = ['admin-views-users.xml','admin-views-person.xml']
You can’t perform that action at this time.
RetroSearch is an open source project built by @garambo | Open a GitHub Issue
Search and Browse the WWW like it's 1997 | Search results from DuckDuckGo
HTML:
3.2
| Encoding:
UTF-8
| Version:
0.7.4