33

Can Django admin site select entries by a custom date range, i.e. using two DateFields with AdminDateWidget? I know that there are date_hierarchy and list_filter properties, but they don't seem very useful when there are a lot of DB entries and you just need to filter items by exact date__gte and date__lte query.

6 Answers 6

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.

2
  • also works as a "rows since date" like ?date__gte=2009-5-1 Commented Jan 12, 2021 at 17:22
  • How to filter the newest, because right now I get the oldest on the top. Solution I had to add a minus like this -date. Commented Nov 19, 2021 at 6:36
34

You can use this up-to-date one: https://github.com/silentsokolov/django-admin-rangefilter.Below is a screenshot

1
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.

0
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.

1
  • indeed, very helpful, tx
    – ptim
    Commented Jul 15, 2017 at 8:21
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.

1
  • now I ended up using your filter (slightly customized) as well - there is still nothing out there in terms of django-admin-filtrate. Still lacks 1.4 support
    – kosta5
    Commented Feb 27, 2013 at 19:07
5

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

1
  • Not tested on 1.4 so probably not. I think there is a new admin filter api in 1.4 that would shake things up. Commented Mar 5, 2012 at 8:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.