Ticket #8528: nullfilter_9084.diff

File nullfilter_9084.diff, 3.5 KB (added by bthomas, 7 years ago)

Add an "Is null" filter for foreign keys and value fields

  • contrib/admin/filterspecs.py

     
    5959        else:
    6060            self.lookup_title = f.verbose_name
    6161        self.lookup_kwarg = '%s__%s__exact' % (f.name, f.rel.to._meta.pk.name)
     62        self.lookup_null_kwarg = '%s__isnull' % (f.name)
    6263        self.lookup_val = request.GET.get(self.lookup_kwarg, None)
     64        self.lookup_null = request.GET.get(self.lookup_null_kwarg, None)
    6365        self.lookup_choices = f.rel.to._default_manager.all()
    6466
    6567    def has_output(self):
     
    6971        return self.lookup_title
    7072
    7173    def choices(self, cl):
    72         yield {'selected': self.lookup_val is None,
    73                'query_string': cl.get_query_string({}, [self.lookup_kwarg]),
     74        yield {'selected': self.lookup_val is None and not self.lookup_null,
     75               'query_string': cl.get_query_string({}, [self.lookup_kwarg, self.lookup_null_kwarg]),
    7476               'display': _('All')}
    7577        for val in self.lookup_choices:
    7678            pk_val = getattr(val, self.field.rel.to._meta.pk.attname)
    7779            yield {'selected': self.lookup_val == smart_unicode(pk_val),
    78                    'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}),
     80                   'query_string': cl.get_query_string({self.lookup_kwarg: pk_val}, [self.lookup_null_kwarg]),
    7981                   'display': val}
     82        if self.field.null:
     83            yield {'selected': self.lookup_null,
     84                   'query_string': cl.get_query_string({self.lookup_null_kwarg: 'True'}, [self.lookup_kwarg]),
     85                   'display': 'Is null'}
    8086
    8187FilterSpec.register(lambda f: bool(f.rel), RelatedFilterSpec)
    8288
     
    162168    def __init__(self, f, request, params, model, model_admin):
    163169        super(AllValuesFilterSpec, self).__init__(f, request, params, model, model_admin)
    164170        self.lookup_val = request.GET.get(f.name, None)
     171        self.lookup_null = request.GET.get(f.name + '__isnull', None)
    165172        self.lookup_choices = model_admin.queryset(request).distinct().order_by(f.name).values(f.name)
    166173
    167174    def title(self):
    168175        return self.field.verbose_name
    169176
    170177    def choices(self, cl):
    171         yield {'selected': self.lookup_val is None,
    172                'query_string': cl.get_query_string({}, [self.field.name]),
     178        yield {'selected': self.lookup_val is None and not self.lookup_null,
     179               'query_string': cl.get_query_string({}, [self.field.name, self.field.name + '__isnull']),
    173180               'display': _('All')}
    174181        for val in self.lookup_choices:
    175             val = smart_unicode(val[self.field.name])
    176             yield {'selected': self.lookup_val == val,
    177                    'query_string': cl.get_query_string({self.field.name: val}),
    178                    'display': val}
     182            if val[self.field.name] is None:
     183                yield {'selected': self.lookup_null,
     184                       'query_string': cl.get_query_string({self.field.name + '__isnull': 'True'}, [self.field.name]),
     185                       'display': 'Is null'}
     186            else:
     187                val = smart_unicode(val[self.field.name])
     188                yield {'selected': self.lookup_val == val,
     189                       'query_string': cl.get_query_string({self.field.name: val}, [self.field.name + '__isnull']),
     190                       'display': val}
    179191FilterSpec.register(lambda f: True, AllValuesFilterSpec)
Back to Top