如何使ChoiceField
的标签行为像ModelChoiceField
?有没有办法设置empty_label
,或者至少显示一个空白字段?
Forms.py:
thing = forms.ModelChoiceField(queryset=Thing.objects.all(), empty_label='Label')
color = forms.ChoiceField(choices=COLORS)
year = forms.ChoiceField(choices=YEAR_CHOICES)
我尝试过这里建议的解决方案:
Stack Overflow Q - 设置CHOICES = [('','All')] + CHOICES
导致内部服务器错误。
Stack Overflow Q2 - 在我的选择中定义('', '---------'),
后,仍默认为列表中的第一项,而不是('', '---------'),
选项。
Gist - 尝试使用此处定义的EmptyChoiceField
,但使用Django 1.4无效。
但这些都不适合我......你会如何解决这个问题?谢谢你的想法!
答案 0 :(得分:36)
请参阅ChoiceField上的Django 1.11文档。 ChoiceField的'empty_value'被定义为空字符串'',因此您的元组列表应包含一个''映射到您想要为空值显示的值的键。
### forms.py
from django.forms import Form, ChoiceField
CHOICE_LIST = [
('', '----'), # replace the value '----' with whatever you want, it won't matter
(1, 'Rock'),
(2, 'Hard Place')
]
class SomeForm (Form):
some_choice = ChoiceField(choices=CHOICE_LIST, required=False)
注意,如果您希望使用'required = False'将表单字段设为可选,则可以避免表单错误
此外,如果你已经有一个没有empty_value的CHOICE_LIST,你可以插入一个,使其首先显示在表单下拉菜单中:
CHOICE_LIST.insert(0, ('', '----'))
答案 1 :(得分:13)
以下是我使用的解决方案:
from myapp.models import COLORS
COLORS_EMPTY = [('','---------')] + COLORS
class ColorBrowseForm(forms.Form):
color = forms.ChoiceField(choices=COLORS_EMPTY, required=False, widget=forms.Select(attrs={'onchange': 'this.form.submit();'}))
答案 2 :(得分:3)
你可以尝试这个(假设你的选择是元组):
blank_choice = (('', '---------'),)
...
color = forms.ChoiceField(choices=blank_choice + COLORS)
year = forms.ChoiceField(choices=blank_choice + YEAR_CHOICES)
此外,我无法从您的代码中判断这是表单还是ModelForm,但它是后者,无需在此处重新定义表单字段(您可以直接在其中包含选项= COLORS和choices = YEAR_CHOICES)模范领域。
希望这会有所帮助。
答案 3 :(得分:2)
我知道你已经接受了答案,但我只是想发布这个以防万一有人遇到我遇到的问题,即接受的解决方案不适用于ValueListQuerySet。您链接到的EmptyChoiceField对我来说非常合适(虽然我使用的是django 1.7)。
class EmptyChoiceField(forms.ChoiceField):
def __init__(self, choices=(), empty_label=None, required=True, widget=None, label=None, initial=None, help_text=None, *args, **kwargs):
# prepend an empty label if it exists (and field is not required!)
if not required and empty_label is not None:
choices = tuple([(u'', empty_label)] + list(choices))
super(EmptyChoiceField, self).__init__(choices=choices, required=required, widget=widget, label=label, initial=initial, help_text=help_text, *args, **kwargs)
class FilterForm(forms.ModelForm):
#place your other fields here
state = EmptyChoiceField(choices=People.objects.all().values_list("state", "state").distinct(), required=False, empty_label="Show All")
答案 4 :(得分:1)
由于模型中的整数字段,必须使用0代替u''。 (对于带有基数为10的int(),错误是无效的文字:')
if not required and empty_label is not None:
choices = tuple([(0, empty_label)] + list(choices))
答案 5 :(得分:1)
聚会晚一点。
完全不修改选择,而仅使用小部件处理呢?
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 SomeForm(forms.Form):
# thing = forms.ModelChoiceField(queryset=Thing.objects.all(), empty_label='Label')
color = forms.ChoiceField(choices=COLORS, widget=EmptySelect)
year = forms.ChoiceField(choices=YEAR_CHOICES, widget=EmptySelect)
自然地,EmptySelect
将被放置在某种common/widgets.py
代码内,然后在需要时只要引用它即可。
答案 6 :(得分:0)
这是不一样的形式,但是我是通过EmptyChoiceField方法启发的以下方式实现的:
from django import forms
from ..models import Operator
def parent_operators():
choices = Operator.objects.get_parent_operators().values_list('pk', 'name')
choices = tuple([(u'', 'Is main Operator')] + list(choices))
return choices
class OperatorForm(forms.ModelForm):
class Meta:
model = Operator
# fields = '__all__'
fields = ('name', 'abbr', 'parent', 'om_customer_id', 'om_customer_name', 'email', 'status')
def __init__(self, *args, **kwargs):
super(OperatorForm, self).__init__(*args, **kwargs)
self.fields['name'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
self.fields['abbr'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
self.fields['parent'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
self.fields['parent'].choices = parent_operators()
self.fields['parent'].required = False
self.fields['om_customer_id'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
self.fields['om_customer_name'].widget.attrs.update({'class': 'form-control m-input form-control-sm'})
self.fields['email'].widget.attrs.update({'class': 'form-control m-input form-control-sm', 'type': 'email'})enter code here
答案 7 :(得分:0)
实现此目的的另一种方法是将选择小部件与其余小部件分开定义,并更改保存内容的方法。
forms.py
class CardAddForm(forms.ModelForm):
category = forms.ModelChoiceField(empty_label='Choose category',
queryset=Categories.objects.all(),
widget=forms.Select(attrs={'class':'select-css'}))
class Meta:
**other model field**
并且在 views.py 中,您应该使用 obj.create(**form.cleaned_data)
代替 form.save()