Login

Add special field lookups to the Admin list_filter display

Author:
whiteinge
Posted:
February 4, 2008
Language:
JavaScript
Version:
Not specified
Tags:
admin jquery
Score:
3 (after 3 ratings)

Ever wanted to add an atypical field lookup to the Django Admin list_filter filters, like __isnull or __in? This jQuery snippet allows you to do just that.

Since you can access those additional filters by directly typing them into in the Admin URL, the tricky part is to add those to the regular list_filter display. A lot of this code is spent checking on querystring matches which is ugly and error-prone -- if you see any problems or room for improvement, drop me a comment!

A suggestion of where to place this code is in templates/admin/yourapp/yourmodel/change_list.html. Mine kinda looks like this:

{% extends "admin/change_list.html" %}

{% block content %}
<script src="/static/js/jquery-1.2.2.min.js" type="text/javascript"></script>
<script type="text/javascript">
    // the JavaScript posted in this snippet
</script>
{{ block.super }}
{% endblock %}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
$(document).ready(function() {
    function customFilter(heading, filter, text) {
        var filtergroup = $('#changelist-filter h3:contains("'+ heading +'")').next('ul');
        qs = window.location.search;

        // if we're already filtering by a sibling (that isn't "All")
        if (filtergroup.children('li:first').siblings().is('.selected')) {
            // remove sibling querystring from custom filter querystring
            var filterBase = filter.substr(0, filter.indexOf('_'));
            var siblingQs = qs.substr(qs.indexOf(filterBase), qs.indexOf('&', qs.indexOf(filterBase)));
            if (!siblingQs) {
                siblingQs = qs.slice(qs.indexOf(filterBase), qs.length);
            }
            qs = qs.replace(siblingQs, '');
            qs = qs + '&' + filter;
        } else {
            // no current filters, make new
            if (!qs || qs == '?') {
                qs = '?' + filter;
            // already filtering by custom filter, ignore
            } else if (qs.match(filter)) {
                qs = qs;
            // current filters, append
            } else {
                qs = qs + '&' + filter;
            }
        }

        filtergroup.append('<li><a href="'+ qs +'">'+ text +'</a></li>');

        var currentfilter = filtergroup.children('li:last');
        if (window.location.search.match(filter)) {
            currentfilter.addClass('selected');
            currentfilter.siblings().each(function(){
                $(this).removeClass('selected');
                $(this).children('a').attr('href', function() {
                    return this.href.replace(filter, '');
                });
            });
        }
    }

    // Usage examples. Takes three arguments.
    // 1. the exact text above your list_display section
    // 2. the custom field lookup (careful with weird characters here)
    // 3. the text you want the new filter to show up as
    customFilter('By affiliation', 'school__in=A,B', 'School A or B');
    customFilter('By affiliation', 'school__isnull=True', 'No school');
});

More like this

  1. Unobtrusvie Foldable Admin Interface by whiteinge 7 years, 2 months ago
  2. Add extra form elements in your contib admin by sergejdergatsjev 6 years, 4 months ago
  3. admin: edit related object shortcut by christian 7 years, 6 months ago
  4. A dict template tag by Batiste 6 years, 11 months ago
  5. Confirm alert if the user navigates away without saving changes by mrazzari 5 years, 8 months ago

Comments

Dinnerdog (on January 13, 2010):

In your example you have set 'By affiliation' as the heading. How do you get this to appear above yout list_display section?

For example I want to use 'By LEA' but when I set this as the heading nothing appears in the filters. However if I set the heading to an already existing heading then my options appear.

Thanks

#

Please login first before commenting.