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)