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