【问题标题】:SimpleListFIlter Default简单列表过滤器默认
【发布时间】:2013-09-07 08:45:33
【问题描述】:

我的模型上有一个布尔字段,表示某人是否取消了他们的会员资格。我正在尝试创建一个自定义 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)

编辑: 我应该更清楚一点。我专门尝试在管理界面中执行此操作。当我在管理员中将上述过滤器添加为 list_filter 时。我在管理页面的一侧有一个过滤器,有 3 个选项:全部、是和否。

我希望默认设置“否”选项或不设置任何选项。相反,默认情况下始终设置“全部”选项。是否有一些没有技巧的方法来设置默认过滤器选项或类似的东西。

当他们查看成员时,基本上在管理员中,我只想默认显示活动(未取消)。如果他们点击“全部”或“是”,那么我想显示已取消的。

更新: 请注意,这与问题Default filter in Django admin 相同,但我这个问题现在已经 6 岁了。接受的答案被标记为需要 Django 1.4。我不确定该答案是否仍适用于较新的 Django 版本,或者仍然是最佳答案。

考虑到另一个问题的答案年龄,我不确定我们应该如何进行。我认为没有任何方法可以将两者合并。

【问题讨论】:

  • 我添加了一个更新来解释重复的情况。问题是相同的,但另一个现在已经很老了。我不确定我们应该如何进行。
  • 对旧问题的最高投票答案(不是被接受的答案)仍然有效(Django 1.8) - 正如我在那里评论的那样。让我们把决定权交给版主。 ;)
  • 同意,让我们把它留给版主。关于这两个问题都有很好的信息,所以希望有一种方法可以合并它们或类似的东西。

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


【解决方案1】:

查看下面链接中名为“添加额外的管理器方法”的部分:

http://www.djangobook.com/en/2.0/chapter10.html

您可以向模型添加额外的 models.Manager 以仅返回尚未取消其会员资格的人员。附加 models.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()

【讨论】:

  • 我添加了一个编辑来更好地解释问题。我正在尝试在管理界面中执行此操作。我认为 SimpleListFilter 是实现此目的的方法,但设置默认过滤器值似乎是不可能的。
【解决方案2】:

不得不做同样的事情并偶然发现了您的问题。这就是我在代码中修复它的方式(适应您的示例):

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 的一部分,正如其名称所暗示的那样:查询 string。您的值以字符串形式出现,而不是布尔值或整数。所以当你调用self.value()时,它会返回一个字符串

如果您检查单击是/否时获得的 URL,当不使用自定义列表过滤器时,您会看到它将其编码为 1/0,而不是 True/False。我采用了相同的方案。

为了完整性和我们未来的读者,我还为所有人添加了 2。未经验证,我假设之前是None。但是None在什么都不选的时候也用,默认是All。除了,在我们的例子中它需要默认为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:是的,您可以在 querystring 方法中检查 'True''False' 而不是 TrueFalse,但是您会注意到正确的选择不会突出显示,因为第一个元组中的元素不匹配(然后您将字符串与布尔值进行比较)。我也尝试在元组字符串中创建第一个元素,但是我必须进行字符串比较或eval 以将'True'True 匹配,这有点丑陋/不安全。所以最好坚持使用整数,就像我的例子一样。

【讨论】:

    【解决方案3】:

    如果有人仍然对此解决方案感兴趣,我使用了一种不同的、恕我直言的更清洁的方法。由于我对默认选择和处理它很好,我决定我只想重命名默认显示标签。恕我直言,这更干净,您不需要任何“黑客”来处理默认值。

    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]]
    

    【讨论】:

    • 这是正确、干净的方法。不仅如此,它还是在 UI 端呈现正确内容的方法。
    猜你喜欢
    • 2012-05-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-10-15
    • 2012-05-03
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多