Navigation

  • index
  • next |
  • previous |
  • django-filter 0.6.0 documentation »

Advanced search¶

Goal¶

The goal of my fork was to create an easy way to add filters in ModelAdmin, simply setting an attribute that I named ‘advanced_search_fields’. In the following, ‘advanced_search_fields’ refers to a filter that allows to filter the fields independently and is clearly implemented with a FilterSet form.

In my current implementation, the presence of attribute advanced_search_fields on ModelAdmin generates a button that will display the form filter when clicked. As in most other django ModelAdmin attributes there’s also a function named get_advanced_search_fields (same signature as get_search_fields) that you can use to customize the advanced_search field at runtime. This method takes precedence over the attribute.

Below you can find the features I added to django-filters:

short way to declare lookup_type¶

I realized that in many circumstancies I needed to create a FilterSet class just to set the lookup_type for each field, so I modified it in a way that accept the lookup_type to be added to the field_name:

class CertificateAdmin(DjangoFiltersModelAdmin):
    model = Certificates
    advanced_search_fields = (
            ('start_date__gte', 'start_date__range', 'user'),
            ('status__in', 'description__icontains',),
            )

status__in¶

in case the field has choices, I fill the widget with them. In case the lookup_type is ‘in’ I set a MultipleChoices

boolean¶

Boolean fields has a default that is ‘——’

date range¶

When the lookp type is ‘range’ I use the DateRangeFilter. This definetely reflects a personal choice.

Implementation¶

My working implementation to get advance_search in admin pages is split in different places:

change_list.html:
 

added 2 templatetags:

  • one to add a button “advanced search” if needed
  • one to add the form with advanced search input filters
  • some javascript to serialize the form (just filled in fields)
ModelAdmin:

added/customized several methods:

  • lookup_allowed: must let any field present in ‘advanced_search_fields’ to

    be used

  • search_filterset_class: property that return a FilterSet based on the

    declared fields. To allow for greater flexibility, it’s possible to set it or to create get_filterset_class method instead.

  • get_changelist: a personalized changelist is used (see below)

  • queryset: if an advanced_search is requested, the new queryset produced

    by FilterSet (search_filterset.qs) is returned

ChangeList:

currently I customized the ‘get_filters’ method, to clean self.params from filters already used.

templatetags:
  • jsearch_form: adds “Advanced Search” button
  • advanced_search_form: renders the html form
advanced_search.js:
 
  • manages visibility of advanced_search form
  • creates a serialization of just the filled in fields

Admin integration¶

Integrating this into the admin is quite simple. You just need to:

  • declare django-filter early in INSTALLED_APPS. So doing change_list.html will be used instead of django.contrib.auth’s one

  • declare in TEMPLATE_LOADER ‘django_filters.admin.Loader’ that implements the template syntax:

    admin:admin/change_list.html

    so that we don’t need to overwrite the whole template

  • derive your ModelAdmin class from django_filters.admin.AdvancedSearchModelAdmin

  • make your change_list extend django_filters:admin/change_list.html

  • declare one of:

    • get_advanced_search_fields
    • advanced_search_fields
    • get_filterset_class

Customization¶

In the following lines I want to show how easy it can be to customize the filterset automatically build from the advanced_search_fields attribute.

autocomplete in advanced_search¶

Let’s add an autocomplettion to the form automatically generated. Let’s substitue:

advanced_search_fields = (
  ('organization__name__icontains',),
)

and let us add the widget from autocomplete_light:

class MyTicketAdmin(TicketAdmin):

  advanced_search_fields = (
    ('organization',),
  )
  def get_filterset_class(self, request):
    TkFilterset = super(MyTicketAdmin, self).get_filterset_class(request)
       class TkFilters(TkFilterset):
         def __init__(self, *args, **kw):
         super(TkFilters, self).__init__(*args, **kw)

         widget_with_autocompl = autocomplete_light.ChoiceWidget('OrganizationAutocomplete')
         self.form.fields['organization'].widget = widget_with_autocompl

     return TkFilters

range that implements Tomorrow¶

Let’s implement a filter that offers option Tomorrow:

class RangeWithTomorrow(dj_filters.DateRangeFilter):
    options = dj_filters.DateRangeFilter.options.copy()
    options[0] = (_('Tomorrow'), lambda qs, name: qs.filter(**{
            '%s__year' % name: now().year,
            '%s__month' % name: now().month,
            '%s__day' % name: now().day +1,
        }))

And now let’s add it to the filterset:

class CogemaPlanAdmin(PlanAdmin):
    actions = [create_agenda]
    def get_filterset_class(self, request):
        PlanFilterset = super(CogemaPlanAdmin, self).get_filterset_class(request)
        class CogemaPlanFilters(PlanFilterset):
            date_begin__range = RangeWithTomorrow(name='date_begin', lookup_type='range', label='Start')
        return CogemaPlanFilters

Table Of Contents

  • Advanced search
    • Goal
      • short way to declare lookup_type
      • status__in
      • boolean
      • date range
    • Implementation
    • Admin integration
    • Customization
      • autocomplete in advanced_search
      • range that implements Tomorrow

Previous topic

Widget Reference

Next topic

Running the django-filter tests

This Page

  • Show Source

Quick search

Enter search terms or a module, class or function name.

Navigation

  • index
  • next |
  • previous |
  • django-filter 0.6.0 documentation »
© Copyright 2013, Alex Gaynor and others.. Created using Sphinx 1.2.2.