按 Null/Is Not Null 过滤 Django Admin
问题描述
我有一个简单的 Django 模型,例如:
I have a simple Django model like:
class Person(models.Model):
referrer = models.ForeignKey('self', null=True)
...
在这个模型的 ModelAdmin 中,我如何允许它通过referrer 是否为空来过滤?默认情况下,向 list_filter 添加推荐人会导致显示一个下拉列表,其中列出了 每个 人的记录,可能有数十万条记录,从而有效地阻止了页面加载.即使加载,我仍然无法按我想要的条件进行过滤.
In this model's ModelAdmin, how would I allow it to be filtered by whether or not referrer is null? By default, adding referrer to list_filter causes a dropdown to be shown that lists every person record, which may be in the hundreds of thousands, effectively preventing the page from loading. Even if it loads, I still can't filter by the criteria I want.
即我将如何修改它以使下拉列表仅列出All"、Null"或Not Null"选项?
i.e. How would I modify this so that the dropdown only lists "All", "Null", or "Not Null" choices?
我看到一些 帖子 声称使用自定义 FilterSpec 子类完成类似的事情,但没有一个解释如何使用它们.我见过的少数似乎适用于所有模型中的所有领域,这是我不想要的.此外,FilterSpec 的文档零,这让我很紧张,因为我不想投资大量与某些可能在下一个版本中消失的临时内部类相关的自定义代码.p>
I've seen some posts that claim to accomplish something similar using custom FilterSpec subclasses, but none of them explain how to use them. The few I've seen appear to apply to all fields in all models, which I wouldn't want. Moreover, there's zero documentation for FilterSpec, which makes me nervous, because I don't want to invest in a lot of custom code tied to some transient internal class that might disappear by the next release.
解决方案
我最终使用了 这里的最佳解决方案,以及这个片段.
I ended up using a mixture of the top solution here, along with this snippet.
但是,我不得不稍微调整一下代码片段,删除字段类型限制并添加最近在 1.3 中添加的新 field_path.
However, I had to tweak the snippet slightly, dropping the field type restriction and adding the new field_path, recently added in 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)
)
相关文章