from django.contrib.admin.filterspecs import FilterSpec from django.contrib.admin.filterspecs import RelatedFilterSpec class FKFilterSpec(RelatedFilterSpec): def __init__(self, f, request, params, model, model_admin): filter_by_key = f.name+'_fk_filter_by' filter_by_val = getattr(model_admin, filter_by_key, None) if filter_by_val != None: self.fk_filter_on = True # we call FilterSpec constructor, not RelatedFilterSpec # constructor; RelatedFilterSpec constructor will try to # get all the pk values on the related models, which we # won't need. FilterSpec.__init__(self, f, request, params, model, model_admin) filter_name_key = f.name+'_fk_filter_name' filter_name_val = getattr(model_admin, filter_name_key, None) if filter_name_val == None: self.lookup_title = f.verbose_name else: self.lookup_title = f.verbose_name+' '+filter_name_val self.lookup_kwarg = f.name+'__'+filter_by_val+'__exact' self.lookup_val = request.GET.get(self.lookup_kwarg, None) values_list = f.rel.to.objects.values_list(filter_by_val, flat=True).distinct() self.lookup_choices = list(values_list) else: RelatedFilterSpec.__init__(self, f, request, params, model, model_admin) self.fk_filter_on = False filter_related_key = f.name+'_fk_filter_related_only' filter_related_val = getattr(model_admin, filter_related_key, False) filter_nf_key = f.name+'_fk_filter_name_field' filter_nf_val = getattr(model_admin, filter_nf_key, 'pk') if filter_related_val: values_list = model_admin.queryset(request).distinct().values_list(f.name+'__pk',f.name+'__'+filter_nf_val).order_by(f.name+'__'+filter_nf_val).distinct() self.lookup_choices = list(values_list) def choices(self, cl): yield {'selected': self.lookup_val is None, 'query_string': cl.get_query_string({}, [self.lookup_kwarg]), 'display': _('All')} if self.fk_filter_on: 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': val} else: for pk_val,val in self.lookup_choices: yield {'selected': self.lookup_val == smart_unicode(pk_val), 'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}), 'display': val} FilterSpec.filter_specs.insert(0, (lambda f: bool(f.rel), FKFilterSpec))