from django.db import models
from django.contrib.admin.filterspecs import FilterSpec, RelatedFilterSpec
from django.contrib.admin.util import get_model_from_relation
from django.db.models import Count
from taggit.managers import TaggableManager
class TaggitFilterSpec(RelatedFilterSpec):
"""
A FilterSpec that can be used to filter by taggit tags in the admin.
To use, simply import this module (for example in `models.py`), and add the
name of your :class:`taggit.managers.TaggableManager` field in the
:attr:`list_filter` attribute of your :class:`django.contrib.ModelAdmin`
class.
"""
def __init__(self, f, request, params, model, model_admin,
field_path=None):
super(RelatedFilterSpec, self).__init__(
f, request, params, model, model_admin, field_path=field_path)
other_model = get_model_from_relation(f)
if isinstance(f, (models.ManyToManyField,
models.related.RelatedObject)):
# no direct field on this model, get name from other model
self.lookup_title = other_model._meta.verbose_name
else:
self.lookup_title = f.verbose_name # use field name
rel_name = other_model._meta.pk.name
self.lookup_kwarg = '%s__%s__exact' % (self.field_path, rel_name)
self.lookup_kwarg_isnull = '%s__isnull' % (self.field_path)
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
self.lookup_val_isnull = request.GET.get(
self.lookup_kwarg_isnull, None)
# Get tags and their count
through_opts = f.through._meta
count_field = ("%s_%s_items" % (through_opts.app_label,
through_opts.object_name)).lower()
queryset = getattr(f.model, f.name).all()
queryset = queryset.annotate(num_times=Count(count_field))
queryset = queryset.order_by("-num_times")
self.lookup_choices = [(t.pk, "%s (%s)" % (t.name, t.num_times))
for t in queryset]
# HACK: we insert the filter at the beginning of the list to avoid the manager
# to be associated with a RelatedFilterSpec
FilterSpec.filter_specs.insert(0, (lambda f: isinstance(f, TaggableManager),
TaggitFilterSpec))
Comments
Awesome, works very well and a very good idea, thanks!
#
Nice one, thanks.
#
Things seem to have changed since 1.3. Under 1.4.1 I'm getting a "No module named filterspecs" exception.
#
I adapted this snippet to Django 1.4.
Filter by taggit tags in the admin (Django 1.4)
I used the example in the ModelAdmin.list_filter documentation, and the snippet code is very simple.
#