2011-10-07 107 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,)