Django add additional range filter

#StandWithUkraine
Today, 25th June 2022, Ukraine is still bravely fighting for democratic values, human rights and peace in whole world. Russians ruthlessly kill all civilians in Ukraine including childs and destroy their cities. We are uniting against Putinโ€™s invasion and violence, in support of the people in Ukraine. You can help by donating to Ukrainian's army.

Copy change_list.html template from here

https://github.com/django/django/blob/master/django/contrib/admin/templates/admin/change_list.html to your templates (name it for example custom_change_list.html).

Add next to block result_list

{% block result_list %}
        <div style="float: right">{{ range_form }} <button type="button" class="button" onclick="apply_range()">Apply</button></div>

...

Also you can append <script> section to {% block content %} that will put dates into date GET param:

<script>
      function apply_range() {
        var fy = document.getElementById('id_from_date_year').value;
        var fm = document.getElementById('id_from_date_month').value;
        var fd = document.getElementById('id_from_date_day').value;
        var ty = document.getElementById('id_to_date_year').value;
        var tm = document.getElementById('id_to_date_month').value;
        var td = document.getElementById('id_to_date_day').value;
        window.location.href = '/admin/someurl/?date__gte='+fy+'-'+fm+'-'+fd+'&date__lt=+ty+'-'+tm+'-'+td+';
      }
</script>

This param will be mapped into iternal queryset for your model, so models will be filtered by field named date.

Add next to admin.py:

class RangeForm(forms.Form):
    yrs = [(datetime.datetime.now().year - i) for i in range(6)]

    from_date = forms.DateField(widget=SelectDateWidget(years=yrs))
    to_date = forms.DateField(widget=SelectDateWidget(years=yrs))

class Ma(admin.ModelAdmin):
    change_list_template = 'custom_change_list.html'

    def changelist_view(self, request, extra_context=None):
        extra_context = extra_context or {}

        if 'date__gte' in request.GET:
            from_date = request.GET['date__gte'].split('t')
            to_date = request.GET['date__lt'].split('t')
            initial = {
                'from_date':  datetime.datetime.strptime(from_date, '%Y-%m-%d').date(),
                'to_date': datetime.datetime.strptime(to_date, '%Y-%m-%d').date()
            }
        else:
            initial = {
                'from_date': (datetime.datetime.now() - timedelta(days=365*5)).date(),
                'to_date': datetime.datetime.now().date()}
        extra_context['range_form'] = RangeForm(initial=initial)
        return super(Ma, self).changelist_view(request, extra_context=extra_context)

Using non-model fields

If your model has no date field and you want to use it for some other case (aggregations, etc) then you should add date get param to admin.views.main.IGNORED_PARAMS.

In admin.py add:

from django.contrib.admin.views import main as views_main
views_main.IGNORED_PARAMS += ('date',)  
#django
0
Ivan Borshchov profile picture
May 05, 2017
by Ivan Borshchov
Did it help you?
Yes !
No

Best related