使用元组时,ChoiceField不显示空标签

Mon*_*lik 41 python django django-forms

我想做什么

我将在我的数据库中保存有关比赛的数据.我希望能够通过某些标准搜索比赛 - 尤其是比赛类型.

关于比赛类型

比赛类型保存在元组中.稍微缩短的例子:

COMPETITION_TYPE_CHOICES = (
    (1, 'Olympic Games'),
    (2, 'ISU Championships'),
    (3, 'Grand Prix Series'),
)
Run Code Online (Sandbox Code Playgroud)

这些在模型中使用如此(再次 - 这是模型的缩短/简化版本):

class Competition(models.Model):
    name = models.CharField(max_length=256)
    type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES) 
Run Code Online (Sandbox Code Playgroud)

搜索表单

我不希望在搜索表单中需要字段,因此表单定义如下:

class CompetitionSearchForm(forms.Form):
    name = forms.CharField(required=False)
    type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
Run Code Online (Sandbox Code Playgroud)

问题

我希望ChoiceField中的select小部件显示一个空标签,但我没有得到一个.任何有关这方面的帮助将非常感谢:)

Mon*_*lik 36

我发现了一种解决方案,可以按照我想要的方式工作而不违反DRY原则.不是很干净,但我认为这是必须的.

根据文档选择,不必是元组:

最后,请注意,选择可以是任何可迭代对象 - 不一定是列表或元组.这使您可以动态构造选择.但是如果你发现你自己选择了动态的选择,你可能最好使用一个带有ForeignKey的正确数据库表.选择适用于静态数据,如果有的话,变化不大.

所以我现在要解决的解决方案是:

COMPETITION_TYPE_CHOICES = [
     (1, 'Olympic Games'),
     (2, 'ISU Championships'),
     (3, 'Grand Prix Series'),
]

COMP_TYPE_CHOICES_AND_EMPTY = [('','All')] + COMPETITION_TYPE_CHOICES
Run Code Online (Sandbox Code Playgroud)

然后:

class CompetitionSearchForm(forms.Form):
    name = forms.CharField(required=False)
    type = forms.ChoiceField(choices=COMP_TYPE_CHOICES_AND_EMPTY, required=False)
Run Code Online (Sandbox Code Playgroud)

该模型保持原样.


Sco*_*ott 29

我尝试了Monika和Evgeniy的解决方案都没有成功,但Monika有一个很好的观点,即选择不需要是元组.因此,最简单(和DRYest)的解决方案就是简单地完成Django在Model Field中的功能.只需在将它们转换为列表后将空白选项和元组一起添加:

from django.db.models.fields import BLANK_CHOICE_DASH

...

type = forms.ChoiceField(choices=BLANK_CHOICE_DASH + list(COMPETITION_TYPE_CHOICES), required=False)
Run Code Online (Sandbox Code Playgroud)


小智 9

更好的选择是在表单init方法中更新字段选择

COMPETITION_TYPE_CHOICES = (
    (1, 'Olympic Games'),
    (2, 'ISU Championships'),
    (3, 'Grand Prix Series'),
)


class CompetitionSearchForm(forms.Form):
    name = forms.CharField(required=False)
    type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)

    def __init__(self, *args, **kwargs):
        super(CompetitionSearchForm, self).__init__(*args, **kwargs)
        self.fields['type'].choices.insert(0, ('','---------' ) )
Run Code Online (Sandbox Code Playgroud)


小智 7

根据文件:

可以使用2元组的可迭代(例如,列表或元组)作为该字段的选择,或者是返回这样的可迭代的可调用的.(https://docs.djangoproject.com/en/dev/ref/forms/fields/)

所以,你可以简单:

sample_field = forms.ChoiceField(choices=(('', '---'),) + Model.YOUR_CHOICES)
Run Code Online (Sandbox Code Playgroud)


sig*_*dga 6

只是改变了Evgeniy的答案,检查是否还没有添加空白替代品.

如果没有检查(至少在运行内置运行服务器时),则会为每个页面重新加载添加一个额外的空标签.

COMPETITION_TYPE_CHOICES = (
    (1, 'Olympic Games'),
    (2, 'ISU Championships'),
    (3, 'Grand Prix Series'),
)

class CompetitionSearchForm(forms.Form):
    name = forms.CharField(required=False)
    type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)

    def __init__(self, *args, **kwargs):
        super(CompetitionSearchForm, self).__init__(*args, **kwargs)
        if not self.fields['type'].choices[0][0] == '':
            self.fields['type'].choices.insert(0, ('','---------' ) )
Run Code Online (Sandbox Code Playgroud)

  • +1用于检查现有空白.不确定这是因为自2010年以来情况发生了变化,但我不得不使用self.fields ['type'].widget.choices (2认同)

Joh*_*ebs 5

尝试添加blank=True到模型字段(假设这是您想要的行为),然后将表单更改为ModelForm并删除字段定义。请注意,blank=True验证或保存模型时不需要设置任何字段。同样,这可能不是您想要的,但如果是,它将允许Django自动处理一些事情。

否则,只需将您更改COMPETITION_TYPE_CHOICES为:

COMPETITION_TYPE_CHOICES = (
    ('', '---------'),
    ('1', 'Olympic Games'),
    ('2', 'ISU Championships'),
    ('3', 'Grand Prix Series'),
)
Run Code Online (Sandbox Code Playgroud)