Login

FilterSpec for ForeignKeys to auth.User with HTML input tag for ModelAdmin.list_filter

Author:
loic
Posted:
May 7, 2011
Language:
Python
Version:
1.3
Score:
2 (after 2 ratings)

I often need to filter my change_list by author but my User table is usually pretty crowded and adding the User FK to list_filter would end up with hundreds of user links in the sidebar. This snippets replace those hundreds of links by a simple HTML <input>.

 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
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# admin_list.py
from django.contrib.admin.templatetags.admin_list import *


@register.simple_tag
def admin_list_filter(cl, spec):
"""
Django stock admin_list_filter is an inclusion_tag, we want to run spec.output instead.
"""
    return spec.output(cl)


# filterspecs.py
from django.contrib.admin.filterspecs import *
from django.utils.translation import ugettext as _

class UserFieldFilterSpec(RelatedFilterSpec):
    def __init__(self, f, request, *args, **kwargs):
        super(UserFieldFilterSpec, self).__init__(f, request, *args, **kwargs)
        self.lookup_kwarg = '%s__username__exact' % self.field_path
        self.lookup_val = request.GET.get(self.lookup_kwarg, None)

    def output(self, cl):
        t = []
        if self.has_output():
            t.append(_(u'<h3>By %s:</h3>\n<ul>\n') % escape(self.title()))
            t.append("""\
                <script type="text/javascript">
                    django.jQuery(function($) {
                        $('input.filter-user-fk')
                            .change(function() {
                                var $next = $(this).next()
                                var val = $(this).val()
                                $next.attr('href', val ? $next.attr('data-querystring').replace('%25s', val) : '#')
                            })
                    })
                </script>
            """)
            for choice in self.choices(cl):
                if choice['type'] == 'input':
                    t.append(u'<li%s><input class="filter-user-fk" type="text" value="%s"><a data-querystring="%s" href="#">&gt;</a></li>\n' % \
                        ((choice['selected'] and ' class="selected"' or ''),
                         choice['display'],
                         iri_to_uri(choice['query_string'])))
                else:
                    t.append(u'<li%s><a href="%s">%s</a></li>\n' % \
                        ((choice['selected'] and ' class="selected"' or ''),
                         iri_to_uri(choice['query_string']),
                         choice['display']))
            t.append('</ul>\n\n')
        return mark_safe("".join(t))

    def choices(self, cl):
        from django.contrib.admin.views.main import EMPTY_CHANGELIST_VALUE
        yield {
            'selected': self.lookup_val is None and not self.lookup_val_isnull,
            'query_string': cl.get_query_string({}, [self.lookup_kwarg, self.lookup_kwarg_isnull]),
            'type': 'link',
            'display': _('All')
        }
        yield {
            'selected': bool(self.lookup_val),
            'query_string': cl.get_query_string({self.lookup_kwarg: '%s'}, [self.lookup_kwarg_isnull]),
            'type': 'input',
            'display': self.lookup_val or ''
        }
        if isinstance(self.field, models.related.RelatedObject) \
           and self.field.field.null or hasattr(self.field, 'rel') \
           and self.field.null:
            yield {
                'selected': bool(self.lookup_val_isnull),
                'query_string': cl.get_query_string({self.lookup_kwarg_isnull: 'True'}, [self.lookup_kwarg]),
                'type': 'link',
                'display': EMPTY_CHANGELIST_VALUE
            }
from django.contrib.auth.models import User
FilterSpec.filter_specs.insert(0, (lambda f: isinstance(f, models.ForeignKey) and f.rel.to == User, UserFieldFilterSpec))

More like this

  1. Template tag - list punctuation for a list of items by shapiromatron 9 months, 3 weeks ago
  2. JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months ago
  3. Serializer factory with Django Rest Framework by julio 1 year, 4 months ago
  4. Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 5 months ago
  5. Help text hyperlinks by sa2812 1 year, 6 months ago

Comments

jazzuell (on July 3, 2011):

I think that this is a good idea, because Django doesn't support multiple search fields and my filter field is toooo long. Thank you for your work. Can you please show us something more universal and maybe not with RelatedFilterSpec but with AllValuesFilterSpec. Im trying use it in my own admin, but you didn't shown us your models.py so it is difficuilt to change code for my needs. It should be easy to do it, but I am just a newbie. Thank you.

#

zaan (on August 28, 2011):

I just can't make it work. Could you write a short instruction, where should be placed particular parts of that code?

#

Please login first before commenting.