Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a filter form for a (class based) generic object list in Django?

Tags:

django

I'm using Django 1.3's class based generic view to display a list of images, but I want to add a filter that enables the user to narrow down the displayed results.

My current approach works, but feels quite hackish:

class ImageFilterForm(ModelForm):
    class Meta:
        model = Image

class ImageListView(ListView):
    model = Image

    def get_queryset(self):
        qs = Image.objects.select_related()  
        for item in self.request.GET:
            key, value = item, self.request.GET.getlist(item)
            # ... Filtering here ...
        return qs

    def get_context_data(self, **kwargs):
        context = super(ImageListView, self).get_context_data(**kwargs)
        context['filter_form'] = ImageFilterForm(self.request.GET)
        return context

Are there better means to add custom filtering to a generic view?

like image 791
cvk Avatar asked Aug 10 '11 13:08

cvk


1 Answers

I use the same approach, but generic, using a mixin:

class FilterMixin(object):

    def get_queryset_filters(self):
        filters = {}
        for item in self.allowed_filters:
            if item in self.request.GET:
                 filters[self.allowed_filters[item]] = self.request.GET[item]
        return filters

    def get_queryset(self):
        return super(FilterMixin, self).get_queryset()\
              .filter(**self.get_queryset_filters())


class ImageListView(FilterMixin, ListView):

    allowed_filters = {
        'name': 'name',
        'tag': 'tag__name',
    }

    # no need to override get_queryset

This allows to specify a list of accepted filters, and they don't need to correspond to the actual .filter() keywords. You can then expand it to support more complex filtering (split by comma when doing an __in or __range filter is an easy example)

like image 127
rewritten Avatar answered Oct 06 '22 01:10

rewritten