Login

Generic object_detail view with multiple named URL filters

Author:
cotton
Posted:
December 14, 2011
Language:
Python
Version:
1.3
Tags:
filter urlconf generic-views queryset urlpatterns
Score:
0 (after 0 ratings)

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

  1. Generic object_detail view filterable by multiple url values by jlorich 4 years, 2 months ago
  2. Decorating URL includes by cotton 3 years, 11 months ago
  3. HTTPS redirections middleware with updated URL template tag by xlq 2 years, 9 months ago
  4. Simple random file CAPTCHA by jeverling 3 years, 4 months ago
  5. Custom change_list filter based on SimpleListFilter shows only referenced (related, used) values by darklow 2 years, 6 months ago

Comments

bluerat (on February 20, 2012):

Thanks, very useful :-)

#

Please login first before commenting.