将“django-filter”与CHOICES字段一起使用 - 需要“Any”选项

时间:2009-09-21 16:23:59

标签: django django-filter

我正在使用非常酷的django-filter(来自:http://github.com/alex/django-filter) 并且要么似乎无法围绕文档,或者只是 需要一点提升。

当我在对象列表页面上显示过滤器表单时,对于FK字段I 获得包含“-----”的下拉列表,其结果为 “任何”类型的过滤器。但我有一些选择设置在那个领域 模型,我想得到相同的“任何”类型选项。 以下是models.py:

的相关示例部分
TICKET_STATUS_CHOICES = (
    ('new', 'New'),
    ('accepted', 'Accepted'),
    ('assigned', 'Assigned'),
    ('reopened', 'Reopened'),
    ('closed', 'Closed'),
)

class Ticket(models.Model):
    assigned_to = models.ForeignKey(User, null=True, blank=True)
    status = models.CharField(max_length=20,
choices=TICKET_STATUS_CHOICES, default='new')

import django_filters

class TicketFilter(django_filters.FilterSet):
    class Meta:
        model = Ticket
        fields = ['assigned_to', 'status']

当我显示过滤器表单时,“assigned_to'获得'任意'选项,如 以及列出可用用户。但是,'status'字段是 仅限于实际“_CHOICES”中列出的选项。

如何根据_CHOICES在字段中添加“any”选项?

6 个答案:

答案 0 :(得分:8)

正如简短但甜蜜的“用法”文档所述,

  

过滤器还会接受任何传递给它的任意关键字参数   django.forms.Field构造函数。

在我进一步观察之前,这并没有多大意义。在./django-filter/docs/ref/目录中,有filters.txt描述了过滤字段以及默认情况下它们与之交互的模型字段。 (我想我的语言就在这里,如果没有,请纠正我)。

因此,我们可以看到ChoiceFilter用于“有选择”的任何字段。

点击Django文档,这里重要的是表单字段,以及它们如何与模型交互。 (使用Django Forms)。所以我们找到了说明

的ChoiceField(http://docs.djangoproject.com/en/dev/ref/forms/fields/#choicefield
  

需要一个额外的必需参数:   ChoiceField.choices     2元组的可迭代(例如,列表或元组),用作此字段的选项。

所以你可以传递一个列表,而不仅仅是原始的Tuple选择集。

所以这可能不是pythonic或DRY,但这是我改变模型的方式:

class TicketFilter(django_filters.FilterSet):
    class Meta:
        model = Ticket
        fields = ['assigned_to', 'priority', 'status']

    def __init__(self, *args, **kwargs):
        super(TicketFilter, self).__init__(*args, **kwargs)
        self.filters['priority'].extra.update(
            {
                'choices': CHOICES_FOR_PRIORITY_FILTER
            })

除此之外,我定义了_CHOICES,我定义了这个新的(如上所述),并确保将原始选项附加到最后:

CHOICES_FOR_PRIORITY_FILTER = [
    ('', 'Any'),
]
CHOICES_FOR_PRIORITY_FILTER.extend(list(TICKET_PRIORITY_CHOICES))

我在这里使用list()因为原始Choices是在一个元组中设置的,所以我想把它变成一个列表。此外,如果您收到NoneType错误,请确保您没有尝试分配.extend()的“返回值”,因为没有。{我绊倒了这个,因为我忘记了它是一个list的方法,而不是一个返回新列表的函数。

如果你知道更简单,更干燥或“pythonic”的方法,请告诉我!

答案 1 :(得分:7)

DRY'er将使用已定义的'choices'参数作为ChoiceFilter。

所以你可以简单地将FILTER_CHOICES扩展为你的TICKET_STATUS_CHOICES以及带有空字符串的'any'选项:

FILTER_CHOICES = (
    ('new', 'New'),
    ('accepted', 'Accepted'),
    ('assigned', 'Assigned'),
    ('reopened', 'Reopened'),
    ('closed', 'Closed'),
    ('', 'Any'),
)

您的TicketFilter将是:

class TicketFilter(django_filters.FilterSet):

   status = django_filters.ChoiceFilter(choices=FILTER_CHOICES)

   class Meta:
      model = Ticket
      fields = ['assigned_to']

答案 2 :(得分:2)

基于匿名懦夫的工作,我做了以下事情:

import django_filters

from .models import Experiment

EMPTY_CHOICE = ('', '---------'), # Don't forget the trailing comma

class ExperimentFilter(django_filters.FilterSet):
    class Meta:
        model = Experiment
        fields = ['method__year',]

    def __init__(self, *args, **kwargs):
        super(ExperimentFilter, self).__init__(*args, **kwargs)
        self.filters['method__year'].extra['choices'] = EMPTY_CHOICE + \
            self.filters['method__year'].extra['choices']

答案 3 :(得分:1)

我结合了上面的所有方法,因为我不喜欢指定需要更新的所有字段,结果是这样的:

import django_filters

from django.db import models
from django_filters.filters import ChoiceFilter

EMPTY_CHOICE = ('', '---------')

class TicketFilter(django_filters.FilterSet):
    def __init__(self, *args, **kwargs):
        super(TicketFilter, self).__init__(*args, **kwargs)
        # add empty choice to all choice fields:
        choices = filter(
            lambda f: isinstance(self.filters[f], ChoiceFilter),
            self.filters)

        for field_name in choices:
            extended_choices = ((EMPTY_CHOICE,) +
                                self.filters[field_name].extra['choices'])
            self.filters[field_name].extra['choices'] = extended_choices

这项工作是做什么的。

答案 4 :(得分:1)

更短的是使用空标签:

class TicketFilter(FilterSet):

    status = ChoiceFilter(choices=Ticket.CHOICES, empty_label=ugettext_lazy(u'Any'))

    class Meta:
        model = Ticket
        fields = ('status', )

答案 5 :(得分:0)

您可以简单地使用null_labelnull_value,例如

    my_field = MultipleChoiceFilter(choices=MY_CHOICES, null_label='Any', null_value='')