Unfortunately, it is not possible currently to use foreign keys in list filter of the admin website. list_filter=['city__country'] doesn't work.
This filter spec tries to workaround this problem.
It is also possible to have 2 filters for a foreign-key field but it requires to add a dummy field to the model. Set the fk_filterspec dictionnary on this dummy field and add 'fk':'real-field' to the dict.
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 78 79 80 81 82 83 84 | #-*- coding: utf-8 -*-
#!/usr/bin/env python
from django.db import models
from django.contrib.admin.filterspecs import FilterSpec, ChoicesFilterSpec
from django.utils.encoding import smart_unicode
from django.utils.translation import ugettext as _
class FkFilterSpec(ChoicesFilterSpec):
def __init__(self, f, request, params, model, model_admin):
super(FkFilterSpec, self).__init__(f, request, params, model, model_admin)
# ******* Extract parameters ********
the_args = f.fk_filterspec.copy()
#The field of the related table
fk_field = the_args['fk_field']
#The name in the related table to use as label in the choices
label = the_args.pop('label', '')
#a title: by default the lookup arg
self.filter_title = the_args.pop('title', '')
#the foreign key field. By default the field the filter is assigned
fk = the_args.pop('fk', f.name)
# ******* Build the filter definition ********
self.lookup_kwarg = '{0}__{1}'.format(fk, fk_field)
self.lookup_val = request.GET.get(self.lookup_kwarg, None)
self.lookup_labels = {}
#get the list of values
values_list = model.objects.values_list(self.lookup_kwarg, flat=True)
#get the
if label:
label_field = '{0}__{1}__{2}'.format(fk, fk_field, label)
else:
label_field = '{0}__{1}'.format(fk, fk_field)
labels = model.objects.values_list(label_field, flat=True)
for (v, l) in zip(values_list, labels):
self.lookup_labels[v] = l
self.lookup_choices = self.lookup_labels.keys()
def choices(self, cl):
yield {'selected': self.lookup_val is None,
'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
'display': _('All')}
for val in self.lookup_choices:
yield {'selected': smart_unicode(val) == self.lookup_val,
'query_string': cl.get_query_string({self.lookup_kwarg: val}),
'display': smart_unicode(self.lookup_labels[val])}
def title(self):
if self.filter_title:
return self.filter_title
else:
return super(FkFilterSpec, self).title()
@classmethod
def register_filterspec(cls):
"""register the filter. To be called in the models.py"""
FilterSpec.filter_specs.insert(0,
(lambda f: len(getattr(f, 'fk_filterspec', [])), cls)
)
### In the models.py
from filterspecs import FkFilterSpec
FkFilterSpec.register_filterspec()
class Country(models.Model):
name = models.CharField(max_length=100)
class City(models.Model):
name = models.CharField(max_length=100)
country = models.ForeignKey(Country)
class Company(models.Model):
name = models.CharField(max_length=100)
city = models.ForeignKey(City)
city.fk_filterspec = {'fk_field':'country',
'label':'name',
'title':'Country'}
|
More like this
- Template tag - list punctuation for a list of items by shapiromatron 10 months, 2 weeks ago
- JSONRequestMiddleware adds a .json() method to your HttpRequests by cdcarter 10 months, 3 weeks ago
- Serializer factory with Django Rest Framework by julio 1 year, 5 months ago
- Image compression before saving the new model / work with JPG, PNG by Schleidens 1 year, 6 months ago
- Help text hyperlinks by sa2812 1 year, 7 months ago
Comments
I had to change the
__init__()
method to make it work with Django 1.3It was giving errors because an unexpected
field_path
keyword argument.#
@gmandx
Thanks for your help! I had the same problem and this solved it.
#
Please login first before commenting.