Django表单集:让第一个必填?
这些表单组的表现跟我想要的完全相反。
我的视图设置是这样的:
def post(request): # TODO: handle vehicle formset
VehicleFormSetFactory = formset_factory(VehicleForm, extra=1)
if request.POST:
vehicles_formset = VehicleFormSetFactory(request.POST)
else:
vehicles_formset = VehicleFormSetFactory()
我的模板看起来是这样的:
<div id="vehicle_forms">
{{ vehicles_formset.management_form }}
{% for form in vehicles_formset.forms %}
<h4>Vehicle {{forloop.counter}}</h4>
<table>
{% include "form.html" %}
</table>
{% endfor %}
</div>
这样一来,最开始只生成一个表单,正是我想要的。但是我希望这个表单是必填的!
当我用JavaScript动态添加空表单时,使用vehicles_formset.empty_form
,所有这些额外的表单都是必填的,这正是我不想要的。
根据文档:
这个表单组足够聪明,可以忽略那些没有被修改的额外表单。
这是第一个表单的表现(这不是我想要的),但额外表单的表现却是我想要的。
有没有什么属性可以改变,让至少有一个表单变成必填的?
4 个回答
10
嗯……这就让第一个表单变成了必填项。
class RequiredFormSet(BaseFormSet):
def clean(self):
if any(self.errors):
return
if not self.forms[0].has_changed():
raise forms.ValidationError('Please add at least one vehicle.')
唯一的问题是,如果没有表单,那么clean
这个方法似乎根本不会被调用,所以我不知道怎么检查有没有表单。其实……这种情况不应该发生(除了我的JavaScript有个bug,允许你删除所有的表单)。
29
Django 1.7 新增了一个功能:你可以通过 formset_factory 来指定这个行为。
VehicleFormSetFactory = formset_factory(VehicleForm, min_num=1, validate_min=True, extra=1)
76
找到了一个更好的解决方案:
class RequiredFormSet(BaseFormSet):
def __init__(self, *args, **kwargs):
super(RequiredFormSet, self).__init__(*args, **kwargs)
for form in self.forms:
form.empty_permitted = False
然后像这样创建你的表单集合:
MyFormSet = formset_factory(MyForm, formset=RequiredFormSet)
我真的不知道为什么一开始没有这个选项……不过,随便吧。花了我几个小时才搞明白。
这样做会让所有的表单都是必填的。如果你只想让第一个表单必填,可以把self.forms[0].empty_permitted
设置为False
。