Custom filter on django admin
Tuesday, February 17, 2009 2:55:59 PM
A teammate got it work by doing a new FilterSpec and I had to use it in another model.
First of all, create the FilterSpec for your admin:
customfilterspec.py
# -*- coding: utf-8 -*-
from django.db import models
from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec, RelatedFilterSpec
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext as _
class CustomFilterSpec(FilterSpec):
"""
Na verdade este é um FilterSpec para passar Queryset diferente do default do campo, por exemplo, filtrado
"""
def __init__(self, f, request, params, model, model_admin):
super(CustomFilterSpec, self).__init__(f, request, params, model, model_admin)
self.lookup_val = request.GET.get(f.name, None)
if isinstance(f, models.ManyToManyField):
self.lookup_title = f.rel.to._meta.verbose_name
else:
self.lookup_title = f.verbose_name
# Queryset padrão
qs = f.rel.to._default_manager.all()
# Verifica se as opções do admin possuem um queryset para este campo
qs_dict = getattr(model_admin, 'custom_filter_spec', None)
if qs_dict and f.name in qs_dict:
qs = qs_dict[f.name]
self.lookup_choices = qs.all()
def title(self):
return self.lookup_title
def choices(self, cl):
yield {'selected': self.lookup_val is None,
'query_string': cl.get_query_string({}, [self.field.name]),
'display': All}
for inst in self.lookup_choices:
val = smart_unicode(inst.pk)
yield {'selected': self.lookup_val == val,
'query_string': cl.get_query_string({self.field.name: val}),
'display': smart_unicode(inst)}
# O ideal seria usar o método register, mas o filtro ficaria por último e não seria utilizável.
# Então é preciso registrá-lo como primeiro.
#FilterSpec.register(lambda f: bool(f.rel and hasattr(f, 'custom_filter_spec')), CustomFilterSpec)
FilterSpec.filter_specs.insert(0, (lambda f: bool(f.rel and hasattr(f, 'custom_filter_spec')), CustomFilterSpec))
Save the file and put it somewhere in your app to import later
It must be loaded at least once so the filter will be added to the list, I recommend put it in an admin.py file.
so, on top of your admin.py:
from utils.customfilterspec import CustomFilterSpec
Then you must prepare your model to assure that the field can use FilterSpec¹
So, in your model do:
class MyModel(models.Model): created_by = models.ForeignKey(User) ... created_by.custom_filter_spec = True
And finally, in your Admin class you must include this field as a list_filter and give a resultset to it:
class MyAdminOptions(ModelAdmin):
...
list_filter = ('created_by',)
custom_filter_spec = {'created_by': User.objects.filter(is_staff=True).order_by('username')}
So now, in my example, I can filter only by staff user in my admin page.
Hope it helps
obs:
1: This models stuff is set in CustomFilterSpec. I believe it could work without this annoying step, just by changing the filter class, but I did not try.








Unregistered user # Tuesday, March 16, 2010 11:17:12 AM
Unregistered user # Monday, June 14, 2010 12:19:16 PM
Unregistered user # Tuesday, November 16, 2010 6:06:28 PM
Unregistered user # Thursday, June 2, 2011 11:34:20 AM
Unregistered user # Sunday, October 9, 2011 9:31:19 AM
Unregistered user # Tuesday, November 1, 2011 2:40:54 AM