如何解决动态将字段添加为表单
| 我的表格中有3个字段。 我有一个提交按钮和一个“添加其他字段”按钮。 我知道我可以在表单类中使用__init__
方法添加字段。
我是Python和Django的新手,并且遇到了一个新手问题;我的问题是:
当我单击“添加其他字段”按钮时,添加其他字段的过程是什么?
是否需要再次呈现表单?
如何以及何时调用__init__
,甚至必须调用它?
如何将参数传递给__init__
?
解决方法
您的表单必须基于从POST传递给它的一些变量来构造(或盲目检查属性)。每次重新加载视图时(无论是否加载)都会构造表单本身,因此HTML需要包含有关构造正确数量的字段以进行验证的字段数量的信息。
我将以3的工作方式来研究这个问题:存在一个隐藏字段,其中包含活动表单的数量,每个表单名称前都带有表单索引。
实际上,您可以将一个字段
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>
,我曾经不得不动态创建带有动态字段的表单。我用这个技巧做到了:
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)
那行得通。
,没有javascript和字段类型的方法不在js中描述:
蟒蛇
def __init__(self,**kwargs):
super(Form,**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 %}
,该答案基于@Yuji \'Tomita \'Tomita的改进和更改。
尽管@Yuji \'Tomita \'Tomita的答案很好,并且很好地说明了构建“以django格式添加额外字段”功能所遵循的方向,但我发现其中的某些部分存在一些问题代码。
在这里,我根据@Yuji \'Tomita \'Tomita的最初建议提供工作代码:
视图(在view.py文件中)
视图中并没有真正改变:
def myview(request):
if request.method == \'POST\':
form = MyForm(request.POST,extra=request.POST.get(\'total_input_fields\'))
if form.is_valid():
print \"valid!\"
else:
form = MyForm()
return render(request,{ \'form\': form })
表格(在form.py文件中)
class MyForm(forms.Form):
empty_layer_name = forms.CharField(max_length=255,required=True,label=\"Name of new Layer\")
total_input_fields = forms.CharField(widget=forms.HiddenInput())
def __init__(self,**kwargs):
extra_fields = kwargs.pop(\'extra\',0)
# check if extra_fields exist. If they don\'t exist assign 0 to them
if not extra_fields:
extra_fields = 0
super(MyForm,**kwargs)
self.fields[\'total_input_fields\'].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()
模板HTML
<form id=\"empty-layer-uploader\" method=\"post\" enctype=\"multipart/form-data\" action=\"{% url \"layer_create\" %}\">
<div id=\"form_empty_layer\">
<input type=\"hidden\" name=\"csrfmiddlewaretoken\" value=\"{{ csrf_token }}\">
{{ form.errors }}
{{ form.non_field_errors }}
{% if errormsgs %}
{% for value in errormsgs %}
</p> {{ value }} </p>
{% endfor %}
{% endif %}
{% for error in form_empty_layer.non_field_errors %}
{{ error }} </br>
{% endfor %}
</br>
{% for field in form_empty_layer.visible_fields %}
{{ field }} </br>
{% endfor %}
</div>
</br>
<button type=\"button\" id=\"add-another\">add another</button> </br> </br>
<button type=\"submit\" id=\"empty-layer-button\" name=\"emptylayerbtn\">Upload</button>
</br></br>
// used in order to save the number of added fields (this number will pass to forms.py through the view)
<input type=\"text\" name=\"total_input_fields\"/>
</form>
模板jQuery
// check how many times elements with this name attribute exist: extra_field_*
form_count = $(\'input[name*=\"extra_field_*\"]\').length;
// when the button \'add another\' is clicked then create a new input element
$(document.body).on(\"click\",\"#add-another\",function(e) {
new_attribute = $(\'<input type=\"text\"/>\');
// add a name attribute with a corresponding number (form_count)
new_attribute.attr(\'name\',\'extra_field_\' + form_count);
// append the new element in your html
$(\"#form_empty_layer\").append(new_attribute);
// increment the form_count variable
form_count ++;
// save the form_count to another input element (you can set this to invisible. This is what you will pass to the form in order to create the django form fields
$(\"[name=total_input_fields]\").val(form_count);
})
,Yuji \'Tomita \'Tomita \的解决方案是您能找到的最好的解决方案,但是假设您有一个多步骤表单,并且使用django-formtools应用程序,则将需要解决一些问题。谢谢Yuji \'Tomita \'Tomita,您对我有很大帮助:)
表格
class LicmodelForm1(forms.Form):
othercolumsvalue = forms.IntegerField(min_value=0,initial=0)
class LicmodelForm2(forms.Form):
def __init__(self,**kwargs):
extra_fields = kwargs.pop(\'extra\',0)
super(LicmodelForm2,**kwargs)
for index in range(int(extra_fields)):
# generate extra fields in the number specified via extra_fields
self.fields[\'othercolums_{index}\'.format(index=index)] = \\
forms.CharField()
self.fields[\'othercolums_{index}_nullable\'.format(index=index)] = \\
forms.BooleanField(required=False)
对于多步骤表单,您将不需要多余的字段,在此代码中,我们在第一步中使用othercolumsvalue字段。
views.py
class MyFormTool(SessionWizardView):
def get_template_names(self):
return [TEMPLATES[self.steps.current]]
def get_context_data(self,form,**kwargs):
context = super(MyFormTool,self).get_context_data(form=form,**kwargs)
data_step1 = self.get_cleaned_data_for_step(\'step1\')
if self.steps.current == \'step2\':
#prepare tableparts for the needLists
needList_counter = 0
for i in self.wellKnownColums:
if data_step1[i] is True:
needList_counter = needList_counter + 1
pass
#prepare tableparts for othercolums
othercolums_count = []
for i in range(0,data_step1[\'othercolumsvalue\']):
othercolums_count.append(str(i))
context.update({\'step1\': data_step1})
context.update({\'othercolums_count\': othercolums_count})
return context
def get_form(self,step=None,data=None,files=None):
form = super(MyFormTool,self).get_form(step,data,files)
if step is None:
step = self.steps.current
if step == \'step2\':
data = self.get_cleaned_data_for_step(\'step1\')
if data[\'othercolumsvalue\'] is not 0:
form = LicmodelForm2(self.request.POST,extra=data[\'othercolumsvalue\'])
return form
def done(self,form_list,**kwargs):
print(\'done\')
return render(self.request,\'formtools_done.html\',{
\'form_data\' : [form.cleaned_data for form in form_list],})
通过覆盖get_form()和get_context_data()函数,您可以在呈现表单之前覆盖它。模板文件也不再需要JavaScript:
{% if step1.othercolumsvalue > 0 %}
<tr>
<th>Checkbox</th>
<th>Columname</th>
</tr>
{% for i in othercolums_count %}
<tr>
<td><center><input type=\"checkbox\" name=\"othercolums_{{ i }}_nullable\" id=\"id_othercolums_{{ i }}_nullable\" /></center></td>
<td><center><input type=\"text\" name=\"othercolums_{{ i }}\" required id=\"id_othercolums_{{ i }}\" /></center></td>
</tr>
{% endfor %}
{% endif %}
由于名称相同,也从formtools重新验证了动态创建的step2中的字段。但是要到达那里,您将必须解决for-each模板循环,如下所示:
从get_context_data()函数
othercolums_count = []
for i in range(0,data_step1[\'othercolumsvalue\']):
othercolums_count.append(str(i))
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。