动态向表单添加字段
我在表单里有三个字段。
我有一个提交按钮,还有一个“添加额外字段”的按钮。
我知道可以通过表单类里的 __init__
方法来添加字段。
我刚开始学Python和Django,现在遇到了一个初学者的问题;我的问题是:
当我点击“添加额外字段”按钮时,添加这个额外字段的过程是什么?
表单需要重新渲染吗?
我应该怎么调用 __init__
方法,或者我根本就不需要调用它吗?
我该如何给 __init__
传递参数?
5 个回答
这里有一种方法,不需要用到JavaScript,而且字段类型在JavaScript中没有描述:
PYTHON
def __init__(self, *args, **kwargs):
super(Form, self).__init__(*args, **kwargs)
##ajouts des champs pour chaque chien
for index in range(int(nb_dogs)):
self.fields.update({
'dog_%s_name' % index: forms.CharField(label=_('Name'), required=False, max_length=512),
})
def fields_dogs(self):
fields = []
for index in range(int(nb_dogs)):
fields.append({
'name': self['dog_%s_name' % index],
})
return fields
模板
{% for field_dog in f.fields_dogs %}
<thead>
<tr>
<th style="background-color: #fff; border-width: 0px;"></th>
<th>{% trans 'Dog' %} #{{forloop.counter}}</th>
<th>{% trans 'Name' %}</th>
</tr>
</thead>
<tbody>
<tr>
<td style="background-color: #fff; border-width: 0px;"></td>
<td style="background-color: #fff; border-width: 0px;"></td>
<td>{{field_dog.name.errors}}{{field_dog.name}}</td>
</tr>
<tr>
<td style="padding: 10px; border-width: 0px;"></td>
</tr>
</tbody>
{% endfor %}
我遇到过一个情况,需要动态创建表单,并且表单里的字段也是动态的。我是通过这个小技巧来实现的:
from django import forms
...
dyn_form = type('DynForm', # form name is irrelevant
(forms.BaseForm,),
{'base_fields': fields})
想了解更多信息,可以参考这个链接: 动态表单
除此之外,我还需要在表单创建后,动态地添加字段,也就是说要在表单类里注入字段。
dyn_form.base_fields['field1'] = forms.IntegerField(widget=forms.HiddenInput(), initial=field1_val)
dyn_form.base_fields['field2'] = forms.CharField(widget=forms.HiddenInput(), initial=field2_val)
这样做是成功的。
你的表单需要根据从POST请求中传递过来的变量来构建(或者直接检查属性)。每次视图重新加载时,表单都会被构建,无论有没有错误,所以HTML里需要包含关于有多少个字段的信息,以便正确地构建这些字段进行验证。
我会把这个问题看作是FormSet
的工作方式:有一个隐藏字段,里面包含当前活动表单的数量,每个表单的名字前面会加上表单的索引。
实际上,你可以创建一个只有一个字段的FormSet
。
https://docs.djangoproject.com/en/dev/topics/forms/formsets/#formsets
如果你不想使用FormSet
,你也可以自己实现这个功能。
这里有一个从头开始制作的例子——它应该能给你一些灵感。它也回答了你关于如何将参数传递给__init__
的问题:你只需将参数传递给对象的构造函数:MyForm('arg1', 'arg2', kwarg1='keyword arg')
表单
class MyForm(forms.Form):
original_field = forms.CharField()
extra_field_count = forms.CharField(widget=forms.HiddenInput())
def __init__(self, *args, **kwargs):
extra_fields = kwargs.pop('extra', 0)
super(MyForm, self).__init__(*args, **kwargs)
self.fields['extra_field_count'].initial = extra_fields
for index in range(int(extra_fields)):
# generate extra fields in the number specified via extra_fields
self.fields['extra_field_{index}'.format(index=index)] = \
forms.CharField()
视图
def myview(request):
if request.method == 'POST':
form = MyForm(request.POST, extra=request.POST.get('extra_field_count'))
if form.is_valid():
print "valid!"
else:
form = MyForm()
return render(request, "template", { 'form': form })
HTML
<form>
<div id="forms">
{{ form.as_p }}
</div>
<button id="add-another">add another</button>
<input type="submit" />
</form>
JS
<script>
let form_count = Number($("[name=extra_field_count]").val());
// get extra form count so we know what index to use for the next item.
$("#add-another").click(function() {
form_count ++;
let element = $('<input type="text"/>');
element.attr('name', 'extra_field_' + form_count);
$("#forms").append(element);
// build element and append it to our forms container
$("[name=extra_field_count]").val(form_count);
// increment form count so our view knows to populate
// that many fields for validation
})
</script>