[Django]-Filtering by custom date range in Django admin

29👍

Note: I wrote this answer in 2009, when the required functionality was not available in Django as a public API. For Django 1.4+, see the other answers.

This functionality isn’t provided as far as I’m aware, but you can build it yourself.

Firstly, you can filter items using date__gte and date__lte as GET arguments in the url.

For example

/admin/myapp/bar/?date__gte=2009-5-1&date__lt=2009-8-1

will display all bar objects with dates in May, June or July 2009.

Then if you override the admin/change_list.html template file, you can add widgets for start and end dates, which navigate to the required url.


Hat tip to Daniel’s answer to another SO question, which taught me about using queryset filter parameters as GET arguments.

54👍

In django 1.4, you can user list_filter. try:

from django.contrib.admin import DateFieldListFilter
class PersonAdmin(ModelAdmin):
    list_filter = (
        ('date_field_name', DateFieldListFilter),
    )

This will give some built-in ranges, but it will work if you put the date range in url, like:

?date__gte=2009-5-1&date__lt=2009-8-1

If you need a date picker (like jquery), then you need to extend DateFieldListFilter. I sent a patch to django-admin-filtrate, so, check there soon.

👤bsm

34👍

12👍

It’s now possible to easily implement Custom Admin filters using standard Django APIs. The docs day that in the list_filter, you can now add:

a class inheriting from django.contrib.admin.SimpleListFilter, which you need to provide the title and parameter_name attributes to and override the lookups and queryset methods

And they go ahead to demo (scroll to the second bullet). I’ve used this myself to add filters whose underlying relation to the objects isn’t via model attributes, but results of methods on them, something which the traditional filters don’t offer.

👤JWL

6👍

I ended up implementing it something like this, admin.py:

 class FooAdmin(MyModelAdmin):

     def changelist_view(self, request, extra_context=None):

         extra_context = extra_context or {}
         try:
             extra_context['trade_date_gte'] = request.GET['date__gte']
         except:
             pass

         try:
             extra_context['trade_date_lte'] = request.GET['date__lte']
         except:
             pass

     return super(FileNoteAdmin, self).changelist_view(request, extra_context)  

change_list.html:

{% extends "admin/admin/change_list.html" %}
{% load i18n admin_static admin_list %}
{% load url from future %}
{% load admin_urls %}


{% block filters %}

{% if cl.has_filters %}
  <div id="changelist-filter">
    <h2>{% trans 'Filter' %} </h2>

<h3>By trade date</h3>

<link href="/media/css/ui-lightness/jquery-ui-1.8.19.custom.css" rel="stylesheet" type="text/css"/>
<script src="/media/js/jquery/jquery-min.js"></script>
<script src="/media/js/jquery/jquery-ui-1.8.19.custom.min.js"></script>

<script>

    $(function() {
        $( "#trade_date_gte" ).datepicker({ dateFormat: 'yy-mm-dd'{% if trade_date_gte %}, defaultDate: '{{ trade_date_gte }}'{% endif %} }); 
        $( "#trade_date_lte" ).datepicker({ dateFormat: 'yy-mm-dd'{% if trade_date_lte %}, defaultDate: '{{ trade_date_lte }}'{% endif %} });
    });

function applyDateFilters() {

    qs = location.search;

    if (qs.charAt(0) == '?') qs = qs.substring(1);

    var qsComponents = qs.split(/[&;]/g);

    new_qs = [];
    for (var index = 0; index < qsComponents.length; index ++){

        var keyValuePair = qsComponents[index].split('=');
        var key          = keyValuePair[0];
        var value        = keyValuePair[1];

        if(key == 'trade_date__gte' || key == 'trade_date__lte' || key == '') {
            continue;
        } else {
            new_qs[index] = key + '=' + value;
        }
    }

    if($( "#trade_date_gte" ).val() != '') {
        new_qs[new_qs.length] = 'trade_date__gte=' + $( "#trade_date_gte" ).val();
    }
    if($( "#trade_date_lte" ).val() != '') {
        new_qs[new_qs.length] = 'trade_date__lte=' + $( "#trade_date_lte" ).val();
    }

    window.location = '?' + new_qs.join("&");
}
</script>

<p>
From: <br /><input type="text" id="trade_date_gte" value="{{ trade_date_gte|default:'' }}" size="10"><br />
To: <br /><input type="text" id="trade_date_lte" value="{{ trade_date_lte|default:'' }}" size="10">
</p>

<ul>
    <li><a href="#" onclick="javascript:applyDateFilters();">Apply date filters</a></li>
</ul>

    {% for spec in cl.filter_specs %}{% admin_list_filter cl spec %}{% endfor %}
  </div>
{% endif %}
{% endblock %}

The date column being filtered is trade_date.

5👍

The DateRangeFilter() class found at https://github.com/runekaagaard/django-admin-filtrate does just that 🙂

Leave a comment