我的模型上有一个布尔字段,表示某人是否已取消其成员资格。我正在尝试创建一个自定义SimpleListFilter,允许过滤此字段。
但是,我真的只想显示默认情况下未取消的人。默认情况下是否有选择“否”选项?到目前为止,这是我的过滤器:
class CanceledFilter(SimpleListFilter):
title = 'Canceled'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'canceled'
def lookups(self, request, model_admin):
return (
(True, 'Yes'),
(False, 'No'),
)
def queryset(self, request, queryset):
if self.value() is True or self.value() is None:
return queryset.filter(canceled=True)
if self.value() is False:
return queryset.filter(canceled=False)
编辑: 我本来应该更清楚一点。我特意尝试在Admin界面中执行此操作。当我在admin中将上面的过滤器添加为list_filter时。我在管理页面侧面有一个过滤器,有3个选项:全部,是和否。
我想要“否”选择,或者默认情况下不设置任何选项。相反,默认情况下始终设置“全部”选项。是否有一些hacky方法来设置默认的过滤器选择或类似的东西。
在Admin中查看成员时,我只想默认显示活动(未取消)。如果他们点击“全部”或“是”,那么我想显示已取消的。
更新: 请注意,这与问题Default filter in Django admin相同,但我这个问题现在已经有6年了。接受的答案标记为需要Django 1.4。我不确定这个答案是否仍适用于较新的Django版本,或者仍然是最好的答案。
鉴于另一个问题的答案年龄,我不确定应该如何进行。我认为没有办法合并这两者。
答案 0 :(得分:7)
不得不这样做并偶然发现你的问题。这是我在我的代码中修改它的方法(适用于你的例子):
class CanceledFilter(SimpleListFilter):
title = 'Canceled'
# Parameter for the filter that will be used in the URL query.
parameter_name = 'canceled'
def lookups(self, request, model_admin):
return (
(2, 'All'),
(1, 'Yes'),
(0, 'No'),
)
def queryset(self, request, queryset):
if self.value() is None:
self.used_parameters[self.parameter_name] = 0
else:
self.used_parameters[self.parameter_name] = int(self.value())
if self.value() == 2:
return queryset
return queryset.filter(cancelled=self.value())
需要一些解释。查询字符串只是URL的一部分,正是名称所暗示的:查询字符串。您的值以字符串形式出现,而不是布尔值或整数。因此,当您致电self.value()
时,会返回字符串。
如果检查单击是/否时获得的URL,则在不使用自定义列表过滤器时,您会看到它将其编码为1/0,而不是True / False。我采用了同样的方案。
为了完整性和我们未来的读者,我还为所有人添加了2。在没有验证的情况下,我认为之前是None
。但是在未选择任何内容时也会使用None
,默认为全部。除了,在我们的例子中,它需要默认为False
,所以我必须选择一个不同的值。如果您不需要All选项,只需删除queryset
方法中的最终if块,以及lookups
方法中的第一个元组。
有了这个,它是如何工作的?诀窍在于意识到self.value()
只会返回:
self.used_parameters.get(self.parameter_name, None)
可以是字符串,也可以是None
,具体取决于是否在字典中找到了密钥。所以这是中心思想:我们确保它包含整数而不是字符串,以便self.value()
可以在queryset.filter()
的调用中使用。 All的值的特殊处理,即2:在这种情况下,只返回queryset
而不是过滤的查询集。另一个特殊值是None
,这意味着字典中没有键parameter_name
。在这种情况下,我们创建一个值为0的值,以便False
成为默认值。
注意:你的逻辑错误;您希望默认情况下未取消,但您将None
视为与True
相同。我的版本更正了这一点。
ps:是的,你可以在'True'
方法中检查'False'
和True
而不是False
和querystring
,但是你会注意到正确的选择不会突出显示,因为元组中的第一个元素不匹配(您将字符串与布尔值进行比较)。我也尝试在元组字符串中创建第一个元素,但是我必须进行字符串比较或eval
以匹配'True'
到True
,这有点难看/不安全。所以最好坚持整数,就像在我的例子中一样。
答案 1 :(得分:0)
请参阅以下链接中的“添加额外经理方法”部分:
http://www.djangobook.com/en/2.0/chapter10.html
您可以向模型中添加其他models.Manager,仅返回尚未取消其成员资格的人员。附加模型的粗略实现.Manager看起来像这样:
class MemberManager(models.Manager):
def get_query_set(self):
return super(MemberManager, self).get_query_set().filter(membership=True)
class Customer(models.Model):
# fields in your model
membership = BooleanField() # here you can set to default=True or default=False for when they sign up inside the brackets
objects = models.Manager # default Manager
members = MemberManager() # Manager to filter for members only
只要您需要获取当前成员的列表,您就可以致电:
Customer.members.all()
答案 2 :(得分:0)
如果仍然有人对此解决方案感兴趣,我会使用另一种更为恕我直言的简洁方法。由于我对默认选项及其处理方式感到满意,因此我决定只想重命名默认显示标签。恕我直言,这更加干净,您无需任何“ hack”即可处理默认值。
class CompleteFilter(admin.SimpleListFilter):
'''
Model admin filter to filter orders for their completion state.
'''
title = _('completion')
parameter_name = 'complete'
def choices(self, changelist):
'''
Return the available choices, while setting a new default.
:return: Available choices
:rtype: list
'''
choices = list(super().choices(changelist))
choices[0]['display'] = _('Only complete')
return choices
def lookups(self, request, model_admin):
'''
Return the optionally available lookup items.
:param django.http.HttpRequest request: The Django request instance
:param django.contrib.admin.ModelAdmin model_admin: The model admin instance
:return: Optional lookup states
:rtype: tuple
'''
return (
('incomplete', _('Only incomplete')),
('all', _('All')),
)
def queryset(self, request, queryset):
'''
Filter the retreived queryset.
:param django.http.HttpRequest request: The Django request instance
:param django.db.models.query.QuerySet: The Django database query set
:return: The filtered queryset
:rtype: django.db.models.query.QuerySet
'''
value = self.value()
if value is None:
return queryset.filter(state__complete=True)
elif value == 'incomplete':
return queryset.filter(state__complete=False)
return queryset
在choices()
方法中,我只是将显示标签从All
重命名为Only complete
。因此,新的默认值(值None
现在已重命名)。
然后,我像往常一样在lookups()
方法中添加了所有其他查找。因为我仍然想要All
选择,所以我再次添加它。但是,如果不需要,您也可以跳过该部分。
基本上就是这样!但是,如果要再次在顶部显示All
选项,则可能需要在返回之前,在choices
方法中对choices()
列表进行重新排序。例如:
# Reorder choices so that our custom "All" choice is on top again.
return [choices[2], choices[0], choices[1]]