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[-\w]+)/(?P[-\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)