Python 按空/不为空筛选Django管理员
我有一个简单的Django模型,如:Python 按空/不为空筛选Django管理员,python,django,django-admin,django-admin-filters,Python,Django,Django Admin,Django Admin Filters,我有一个简单的Django模型,如: class Person(models.Model): referrer = models.ForeignKey('self', null=True) ... 在这个模型的ModelAdmin中,我如何允许通过referer是否为null来过滤它?默认情况下,将referer添加到list_filter会导致显示一个下拉列表,其中列出每一个个人记录,可能有几十万条,从而有效阻止页面加载。即使它加载了,我仍然无法按照我想要的标准进行筛选 i、
class Person(models.Model):
referrer = models.ForeignKey('self', null=True)
...
在这个模型的ModelAdmin中,我如何允许通过referer是否为null来过滤它?默认情况下,将referer添加到list_filter会导致显示一个下拉列表,其中列出每一个个人记录,可能有几十万条,从而有效阻止页面加载。即使它加载了,我仍然无法按照我想要的标准进行筛选
i、 e.如何修改此选项,使下拉列表仅列出“全部”、“空”或“非空”选项
我见过一些人声称使用自定义FilterSpec子类可以实现类似的功能,但没有人解释如何使用它们。我见过的少数几个似乎适用于所有模型中的所有字段,这是我不希望看到的。此外,FilterSpec没有文档,这让我很紧张,因为我不想投入大量定制代码,这些代码与一些可能在下一个版本中消失的临时内部类相关联。可能需要一个更好的解释片段。Django 1.4将随附一个。四年来,一直有一张票在这方面出现(https://code.djangoproject.com/ticket/5833). 它错过了1.3的里程碑,但已经达到了新的功能状态,大概已经找到了进入主干的途径。如果你不介意从后备箱里跑出来,你现在就可以用了。不过,该修补程序应该与1.3兼容,因此您可能只需修补当前安装的补丁即可 然而,我不得不稍微调整代码片段,去掉字段类型限制,并添加新的字段路径,最近在1.3中添加
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)
)
由于Django 1.4对过滤器进行了一些更改,我想我可以节省一些人的时间来修改Cerin接受的答案中的代码,以便使用Django 1.4 rc1 我有一个名为“started”的TimeField(null=True)模型,我想筛选空值和非空值,所以它的问题与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, )
class PersonAdmin(admin.ModelAdmin):
list_filter = (RefererFilter,)
我有一个frnhr答案的简单版本,它实际上根据
\uu isnull
条件进行过滤。
(Django 1.4+):
然后还:
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')), )
有一个简单的方法:
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 SomeModelAdmin(admin.ModelAdmin):
list_filter = (StartNullFilterSpec, )
class PersonAdmin(admin.ModelAdmin):
list_filter = (RefererFilter,)
在Django 3.1之后,您可以使用:
class MyAdmin(admin.ModelAdmin):
list_filter = (
("model_field", admin.EmptyFieldListFilter),
)
对于小于3.1的django版本,请复制下面的
EmptyFieldListFilter
代码
from django.contrib.admin import FieldListFilter
from django.contrib.admin.options import IncorrectLookupParameters
from django.core.exceptions import ImproperlyConfigured
from django.db import models
from django.utils.translation import gettext_lazy as _
class EmptyFieldListFilter(FieldListFilter):
def __init__(self, field, request, params, model, model_admin, field_path):
if not field.empty_strings_allowed and not field.null:
raise ImproperlyConfigured(
"The list filter '%s' cannot be used with field '%s' which "
"doesn't allow empty strings and nulls." % (
self.__class__.__name__,
field.name,
)
)
self.lookup_kwarg = '%s__isempty' % field_path
self.lookup_val = params.get(self.lookup_kwarg)
super().__init__(field, request, params, model, model_admin, field_path)
def queryset(self, request, queryset):
if self.lookup_kwarg not in self.used_parameters:
return queryset
if self.lookup_val not in ('0', '1'):
raise IncorrectLookupParameters
lookup_condition = models.Q()
if self.field.empty_strings_allowed:
lookup_condition |= models.Q(**{self.field_path: ''})
if self.field.null:
lookup_condition |= models.Q(**{'%s__isnull' % self.field_path: True})
if self.lookup_val == '1':
return queryset.filter(lookup_condition)
return queryset.exclude(lookup_condition)
def expected_parameters(self):
return [self.lookup_kwarg]
def choices(self, changelist):
for lookup, title in (
(None, _('All')),
('1', _('Empty')),
('0', _('Not empty')),
):
yield {
'selected': self.lookup_val == lookup,
'query_string': changelist.get_query_string({self.lookup_kwarg: lookup}),
'display': title,
}
您可以使用它将管理员中的空字段值筛选器定义为
import myfile
class MyAdmin(admin.ModelAdmin):
list_filter = (
("model_field", myfile.EmptyFieldListFilter),
)
在1.4中有一个
BooleanFieldListFilter
,默认情况下会这样做<代码>列表过滤器=(('myfield',BooleanFieldListFilter),'other\u field','other\u field2')。在非布尔字段中,它实现了与null/notnull相同的效果。@KyleMacFarlane似乎不适用于DateTime字段,尽管使用1.6它似乎也不适用于ForeignKey。或者,如果您使用的是Django较低版本,请创建一个文件(例如:admin_filter.py)并将EmptyFieldListFilter的代码添加到一个文件中,并将其导入到管理文件中,并使用类MyAdmin(admin.ModelAdmin):list_filter=((“model_字段”,admin_filter.EmptyFieldListFilter),)