我将在我的数据库中保存有关比赛的数据。我希望能够通过某些标准搜索比赛 - 尤其是比赛类型。
比赛类型保存在元组中。一个稍微缩短的例子:
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)
我不希望搜索表单中需要这些字段,因此表单定义如下:
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False)
我希望ChoiceField中的select小部件显示一个空标签,但我没有得到一个。任何有关这方面的帮助将非常感激:)
答案 0 :(得分:36)
我找到了一种解决方案,可以按照我想要的方式运行而不违反DRY原则。不是很干净,但我认为这是必须的。
根据the documentation选择,不必是元组:
最后,请注意选择可以是任何选择 可迭代对象 - 不一定是 列表或元组。这可以让你构建 动态选择。但如果你找到了 自己黑客入选 动态,你可能会更好 使用适当的数据库表 ForeignKey的。选择是为了 静态数据变化不大, 如果有的话。
所以我现在要解决的问题是:
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)
该模型保持原样。
答案 1 :(得分:27)
我尝试了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)
答案 2 :(得分: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, ('','---------' ) )
答案 3 :(得分:7)
根据文件:
要使用2元组的可迭代(例如,列表或元组)作为此字段的选项,或使用返回此类可迭代的可调用对象。 (https://docs.djangoproject.com/en/dev/ref/forms/fields/)
所以,你可以很简单:
sample_field = forms.ChoiceField(choices=(('', '---'),) + Model.YOUR_CHOICES)
答案 4 :(得分:6)
只需对Evgeniy's answer进行少量更改,即检查是否尚未添加空白替代。
如果没有检查(至少在运行内置运行服务器时),每次重新加载页面都会添加一个额外的空标签。
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, ('','---------' ) )
答案 5 :(得分:4)
尝试将blank=True
添加到模型字段(假设这是您想要的行为),然后将表单更改为ModelForm并删除字段定义。请注意,验证或保存模型时,不需要为其设置blank=True
的任何字段。同样,这可能不是你想要的,但是如果它允许Django自动处理一些事情。
否则只需将COMPETITION_TYPE_CHOICES
更改为:
COMPETITION_TYPE_CHOICES = (
('', '---------'),
('1', 'Olympic Games'),
('2', 'ISU Championships'),
('3', 'Grand Prix Series'),
)
答案 6 :(得分:0)
如果您已经拥有模型类,为什么不使用ModelForm?
最佳解决方案:
<强> 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
答案 7 :(得分:0)
聚会晚一点。
完全不修改选择,而仅使用小部件处理呢?
from django.db.models import BLANK_CHOICE_DASH
class EmptySelect(Select):
empty_value = BLANK_CHOICE_DASH[0]
empty_label = BLANK_CHOICE_DASH[1]
@property
def choices(self):
yield (self.empty_value, self.empty_label,)
for choice in self._choices:
yield choice
@choices.setter
def choices(self, val):
self._choices = val
然后称呼它:
class CompetitionSearchForm(forms.Form):
name = forms.CharField(required=False)
type = forms.ChoiceField(choices=COMPETITION_TYPE_CHOICES,required=False, widget=EmptySelect)
这就是你最终得到的:
print(CompetitionSearchForm().as_p())
<p>
<label for="id_name">Name:</label>
<input id="id_name" name="name" type="text" />
</p>
<p>
<label for="id_type">Type:</label>
<select id="id_type" name="type">
<option value="" selected="selected">------</option>
<option value="1">Olympic Games</option>
<option value="2">ISU Championships</option>
<option value="3">Grand Prix Series</option>
</select>
</p>