7

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

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

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

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

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

4

3 回答 3

8

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

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 选项,只需删除方法中的最后一个 if 块和queryset方法中的第一个元组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'and'False'而不是Trueand ,但是您会注意到正确的选择不会突出显示,因为您的元组中的第一个元素不匹配(然后您将字符串与布尔值进行比较)。我也尝试在元组字符串中创建第一个元素,但是我必须进行字符串比较或匹配到,这有点难看/不安全。所以最好坚持整数,就像我的例子一样。Falsequerystringeval'True'True

于 2014-11-28T17:47:55.717 回答
4

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

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()方法中,我只是将显示标签从 重命名AllOnly 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]]
于 2019-06-22T16:32:29.073 回答
-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()
于 2013-09-04T01:39:11.443 回答