This snippet is greatly inspired by @jlorich's useful #2436.
The main difference is that I wanted to choose the names of my URL params instead of being forced into naming them "value1", "value2", etc. When reversing the URL you have to remember that the kwargs aren't friendly. By using the same names in the filters
list, you don't have to change the way your otherwise write the URL pattern. Also it's clear throughout how you'll be filtering the QuerySet.
The other change I made was "erroring early". This avoids running the QuerySet all over again inside object_detail()
just to have it raise an exception we could have caught the first time.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | from django.http import Http404
from django.views.generic.list_detail import object_detail
from django.core.exceptions import MultipleObjectsReturned, ObjectDoesNotExist
def filtered_object_detail(request, queryset, filters=[], **kwargs):
"""
Generic object-detail view that can filter a QuerySet
on multiple named URL parameters
This generic view will filter a QuerySet on any number of
named URL parameters and will "error early". It expects a
single object from the QuerySet and will raise exceptions
without having to step into object_detail(), which will
ultimately run the QuerySet again and raise the same
exceptions.
Usage:
The named URL parameters must match the filter list.
url(r'^(?P<blog__slug>[-\w]+)/(?P<slug>[-\w]+)/$', filtered_object_detail, {
'queryset': BlogPost.objects.all(),
'filters': ['blog__slug', 'slug'],
},
name='blog-post'),
"""
args = {}
for item in filters:
if item in kwargs.keys():
args[item] = kwargs.pop(item)
else:
raise AttributeError("filtered_object_detail view must used all "\
"the given `filters` as named URL kwargs.")
queryset = queryset.filter(**args)
try:
object_id = queryset.get().id
except MultipleObjectsReturned:
raise MultipleObjectsReturned("filtered_object_detail view is "\
"designed to return a single object")
except ObjectDoesNotExist:
raise Http404("No %s found matching the query" \
% (queryset.model._meta.verbose_name))
return object_detail(request, queryset, object_id, **kwargs)
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
Thanks, very useful :-)
#
Please login first before commenting.