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)