SimpleListFIlter默认值

时间:2013-09-04 00:53:42

标签: django django-admin django-admin-filters

我的模型上有一个布尔字段,表示某人是否已取消其成员资格。我正在尝试创建一个自定义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版本,或者仍然是最好的答案。

鉴于另一个问题的答案年龄,我不确定应该如何进行。我认为没有办法合并这两者。

3 个答案:

答案 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而不是Falsequerystring,但是你会注意到正确的选择不会突出显示,因为元组中的第一个元素不匹配(您将字符串与布尔值进行比较)。我也尝试在元组字符串中创建第一个元素,但是我必须进行字符串比较或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]]