Cer*_*rin 11 python django django-admin django-admin-filters
我有一个简单的Django模型,如:
class Person(models.Model):
referrer = models.ForeignKey('self', null=True)
...
Run Code Online (Sandbox Code Playgroud)
在这个模型的ModelAdmin中,我如何通过referrer是否为null来过滤它?默认情况下,将referrer添加到list_filter会导致显示一个下拉列表,其中列出了可能数十万的每个人的记录,从而有效地阻止了页面的加载.即使它加载,我仍然无法按照我想要的标准进行过滤.
即如何修改此选项,以便下拉列表仅列出"全部","空"或"非空"选项?
我已经看过一些声称使用自定义FilterSpec子类完成类似操作的帖子,但它们都没有解释如何使用它们.我见过的少数似乎适用于所有型号的所有领域,我不想要.此外,FilterSpec 没有文档,这让我感到紧张,因为我不想投入大量自定义代码,这些代码与一些可能在下一版本中消失的瞬态内部类相关联.
frn*_*nhr 13
由于Django 1.4对过滤器进行了一些更改,我认为我节省了一些时间,因为我只是修改了Cerin接受的使用Django 1.4 rc1的答案的代码.
我有一个名为"已启动"的TimeField(null = True)的模型,我想过滤掉null和非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'
Run Code Online (Sandbox Code Playgroud)
而不仅仅是在ModelAdmin中使用它们:
class SomeModelAdmin(admin.ModelAdmin):
list_filter = (StartNullFilterSpec, )
Run Code Online (Sandbox Code Playgroud)
Cal*_*tta 12
在 Django 3.1 之后,您可以使用EmptyFieldListFilter:
class MyAdmin(admin.ModelAdmin):
list_filter = (
("model_field", admin.EmptyFieldListFilter),
)
Run Code Online (Sandbox Code Playgroud)
我有一个简单版本的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
Run Code Online (Sandbox Code Playgroud)
然后还:
class StartNullListFilter(NullListFilter):
title = u'Started'
parameter_name = u'started'
Run Code Online (Sandbox Code Playgroud)
最后:
class SomeModelAdmin(admin.ModelAdmin):
list_filter = (StartNullListFilter, )
Run Code Online (Sandbox Code Playgroud)
我个人不喜欢把我的垃圾admin.py分成几十个类,所以我想出了这样一个帮助函数:
def null_filter(field, title_=None):
class NullListFieldFilter(NullListFilter):
parameter_name = field
title = title_ or parameter_name
return NullListFieldFilter
Run Code Online (Sandbox Code Playgroud)
我可以在以后申请:
class OtherModelAdmin(admin.ModelAdmin):
list_filter = (null_filter('somefield'), null_filter('ugly_field', _('Beautiful Name')), )
Run Code Online (Sandbox Code Playgroud)
小智 5
有一个简单的方法:
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)
Run Code Online (Sandbox Code Playgroud)
然后在 ModelAdmin 中使用它们:
class PersonAdmin(admin.ModelAdmin):
list_filter = (RefererFilter,)
Run Code Online (Sandbox Code Playgroud)
然而,我不得不稍微调整一下代码片段,删除字段类型限制并添加新的 field_path(最近在 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)
)
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
8507 次 |
| 最近记录: |