2011-10-07 105 views
8

我有一个简单的Django模型,如:过滤Django管理由空/不为空

class Person(models.Model): 
    referrer = models.ForeignKey('self', null=True) 
    ... 

在这个模型中的的ModelAdmin,我怎么会允许它通过引用是否为空过滤?默认情况下,将引用链接添加到list_filter会导致显示一个下拉列表,其中每个人记录列出个人记录,可能有成百上千个记录,有效地防止加载页面。即使加载,我仍然无法过滤我想要的标准。

即我将如何修改此以便下拉列表仅列出“全部”,“空”或“非空”选项?

我见过一些posts声称使用自定义的FilterSpec子类来完成类似的事情,但没有一个解释如何使用它们。我见过的少数几个似乎适用于所有模型中的所有领域,我不想要这些领域。此外,还有 FilterSpec的文档,这让我感到紧张,因为我不想投资很多自定义代码,这些代码绑定到可能在下一个版本中消失的临时内部类。

回答

1

我结束了使用the top solution here,以及this snippet的混合物。

但是,我不得不稍微调整片段,放下字段类型限制并添加最近在1.3中添加的新field_path。

from django.contrib.admin.filterspecs import FilterSpec 
from django.db import models 
from django.utils.safestring import mark_safe 
from django.utils.translation import ugettext as _ 

class NullFilterSpec(FilterSpec): 
    #fields = (models.CharField, models.IntegerField, models.FileField) 

    @classmethod 
    def test(cls, field): 
     #return field.null and isinstance(field, cls.fields) and not field._choices 
     return field.null and not field._choices 
    #test = classmethod(test) 

    def __init__(self, f, request, params, model, model_admin, field_path=None): 
     super(NullFilterSpec, self).__init__(f, request, params, model, model_admin, field_path) 
     self.lookup_kwarg = '%s__isnull' % f.name 
     self.lookup_val = request.GET.get(self.lookup_kwarg, None) 

    def choices(self, cl): 
     # bool(v) must be False for IS NOT NULL and True for IS NULL, but can only be a string 
     for k, v in ((_('All'), None), (_('Has value'), ''), (_('Omitted'), '1')): 
      yield { 
       'selected' : self.lookup_val == v, 
       'query_string' : cl.get_query_string({self.lookup_kwarg : v}), 
       'display' : k 
      } 

# Here, we insert the new FilterSpec at the first position, to be sure 
# it gets picked up before any other 
FilterSpec.filter_specs.insert(0, 
    # If the field has a `profilecountry_filter` attribute set to True 
    # the this FilterSpec will be used 
    (lambda f: getattr(f, 'isnull_filter', False), NullFilterSpec) 
) 
1

已经有一张票在这里弹跳了4年(https://code.djangoproject.com/ticket/5833)。它错过了1.3里程碑,但已经达到了新的功能状态,据推测已经发现它是进入主干道的方式。如果你不介意从行李箱里跑掉,现在就可以使用它。不过,这个补丁应该是1.3兼容的,所以你可以通过补丁来修补当前的安装。

13

由于Django的1.4带来了一些变化滤波器,我以为我救一个人我只花了修改从Cerin的接受的答案代码使用Django 1.4 RC1的工作时间。

我有一个模型,其TimeField(空= True)名为“开始”,我想筛选为null和非空值,所以它是非常相同的问题OP。
所以,这里对我来说是什么工作?

定义(实际上包括在内),这些在admin.py:

from django.contrib.admin.filters import SimpleListFilter 

class NullFilterSpec(SimpleListFilter): 
    title = u'' 

    parameter_name = u'' 

    def lookups(self, request, model_admin): 
     return (
      ('1', _('Has value'),), 
      ('0', _('None'),), 
     ) 

    def queryset(self, request, queryset): 
     kwargs = { 
     '%s'%self.parameter_name : None, 
     } 
     if self.value() == '0': 
      return queryset.filter(**kwargs) 
     if self.value() == '1': 
      return queryset.exclude(**kwargs) 
     return queryset 



class StartNullFilterSpec(NullFilterSpec): 
    title = u'Started' 
    parameter_name = u'started' 

不仅仅是使用他们的ModelAdmin:

class SomeModelAdmin(admin.ModelAdmin): 
    list_filter = (StartNullFilterSpec,) 
+3

在1.4有''BooleanFieldListFilter''这将默认执行此操作。 ''list_filter =(('myfield',BooleanFieldListFilter),'other_field','other_field2')''。在非布尔字段中,它可以达到与null/not null相同的效果。 –

+1

@KyleMacFarlane虽然 – Kos

+1

似乎不适用于DateTime字段使用1.6它看起来不适用于ForeignKeys。 –

7

我有一个简单的frnhr的答案版本,其实际上过滤__isnull条件。 (Django 1。4+):

from django.contrib.admin import SimpleListFilter 

class NullListFilter(SimpleListFilter): 
    def lookups(self, request, model_admin): 
     return (
      ('1', 'Null',), 
      ('0', '!= Null',), 
     ) 

    def queryset(self, request, queryset): 
     if self.value() in ('0', '1'): 
      kwargs = { '{0}__isnull'.format(self.parameter_name) : self.value() == '1' } 
      return queryset.filter(**kwargs) 
     return queryset 

然后也:

class StartNullListFilter(NullListFilter): 
    title = u'Started' 
    parameter_name = u'started' 

最后:

class SomeModelAdmin(admin.ModelAdmin): 
    list_filter = (StartNullListFilter,) 

我个人不喜欢垃圾我的admin.py有几十个班,所以我来了具有这样的帮手功能:

def null_filter(field, title_=None): 
    class NullListFieldFilter(NullListFilter): 
     parameter_name = field 
     title = title_ or parameter_name 
    return NullListFieldFilter 

,我可以在以后应用在:

class OtherModelAdmin(admin.ModelAdmin): 
    list_filter = (null_filter('somefield'), null_filter('ugly_field', _('Beautiful Name')),) 
2

有一个简单的方法:

class RefererFilter(admin.SimpleListFilter): 
    title = 'has referer' 
    # Parameter for the filter that will be used in the URL query. 
    parameter_name = 'referer__isnull' 

    def lookups(self, request, model_admin): 
     return (
      ('False', 'has referer'), 
      ('True', 'has no referer'), 
     ) 

    def queryset(self, request, queryset): 
     if self.value() == 'False': 
      return queryset.filter(referer__isnull=False) 
     if self.value() == 'True': 
      return queryset.filter(referer__isnull=True) 

然后,只需使用他们的ModelAdmin:

class PersonAdmin(admin.ModelAdmin): 
    list_filter = (RefererFilter,)