我正在使用非常酷的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”选项?
答案 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_label
和null_value
,例如
my_field = MultipleChoiceFilter(choices=MY_CHOICES, null_label='Any', null_value='')