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

我正在尝试做什么

我将在数据库中保存关于比赛的数据。 我希望能够通过特定的标准来search比赛 – 尤其是比赛types。

关于竞争types

比赛types保存在一个元组中。 稍微缩短的例子:

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

这些在模型中被使用(再次 – 这是模型的简化版本):

 class Competition(models.Model): name = models.CharField(max_length=256) type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES) 

search表单

我不希望这些字段在search表单中是必需的,所以表单是这样定义的:

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

问题

我想在ChoiceField中的select小部件显示一个空的标签,但我没有得到一个。 任何帮助,将不胜感激:)

我find了一种解决scheme,按照我想要的方式工作,而不违反DRY原则。 不是很干净,但它必须做我想。

根据文档select不一定是元组:

最后,请注意,select可以是任何可迭代对象 – 不一定是列表或元组。 这可以让你dynamic地构buildselect。 但是如果你发现自己的select是dynamic的,那么你最好使用一个带有ForeignKey的正确的数据库表。 select意味着静态数据不会有太大变化。

所以我现在要做的解决scheme是:

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

接着:

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

模型保持原样。

我尝试了Monika和Evgeniy的解决scheme,但没有成功,但Monika有一个好处,那就是select不需要是元组。 因此,最简单的(和DRYest)解决scheme就是简单地做Django已经在模型字段中做的事情。 简单地将空白select和元组转换成列表后,将它们加在一起:

 from django.db.models.fields import BLANK_CHOICE_DASH ... type = forms.ChoiceField(choices=BLANK_CHOICE_DASH + list(COMPETITION_TYPE_CHOICES), required=False) 

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

 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, ('','---------' ) ) 

对Evgeniy的答案只是一个小的改变,检查是否没有添加空白的替代品。

没有检查(至less在运行内置的runserver时),为每个页面重新加载一个额外的空标签。

 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, ('','---------' ) ) 

根据文件:

无论是2元组的迭代(例如,一个列表或元组)作为这个字段的select,还是一个返回这样一个可迭代的可调用对象。 ( https://docs.djangoproject.com/en/dev/ref/forms/fields/

所以,你可以简单的:

 sample_field = forms.ChoiceField(choices=(('', '---'),) + Model.YOUR_CHOICES) 

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

否则,只要将您的COMPETITION_TYPE_CHOICES改为:

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

如果你已经有模型类,为什么不使用ModelForm?

最佳解决scheme

forms.py

 class CompetitionSearchForm(ModelForm): class Meta: model = Competition 

models.py

 class Competition(models.Model): name = models.CharField(max_length=256) type = models.IntegerField(choices=COMPETITION_TYPE_CHOICES, default=COMPETITION_TYPE_CHOICES[0][0], blank=True) 

您可以将blank = False设置为从列表中删除empty_label