我遇到了类似的问题并提出了以下解决方案(主要基于this 答案,但我能够避免使用任何javascript):
表单包含隐藏字段以存储 requirement 字段的计数;默认情况下,表单有一个这样的字段,但按下按钮"add_requirement" 会增加TestView.post() 中的计数。如果需要,__init__ 表单会添加具有适当索引的新字段,save() 它会遍历所有需求索引以从各个字段收集值。
TestView.post() 对表单的两个按钮的工作方式不同:"add_requirement" 只是增加字段数并再次呈现表单并添加字段;默认"submit" 按钮保存有效表单并重定向到success_url 或重新显示无效表单。
forms.py
class SimpleForm(forms.Form):
requirements_count = forms.CharField(widget=forms.HiddenInput(), initial=1)
stable_field = forms.CharField(label='Stable field', required=False)
other_stable_field = forms.CharField(label='Other field', required=False)
requirements_1 = forms.CharField(label='Requirements', required=False)
def __init__(self, *args, **kwargs):
super(SimpleForm, self).__init__(*args, **kwargs)
if self.is_bound:
requirements_count = int(self.data.get('requirements_count', 1))
else:
requirements_count = int(self.initial.get('requirements_count', 1))
if requirements_count > 1:
for index in range(2, requirements_count + 1):
self.fields.update(
{'requirements_' + str(index):
forms.CharField(label='Requirements', required=False)}
)
def save(self, *args, **kwargs):
form = self.cleaned_data
requirements_count = int(form.get('requirements_count', 1))
requirements_list = []
for index in range(1, requirements_count + 1):
requirements = form.get('requirements_' + str(index), '')
if requirements:
requirements_list.append(requirements)
views.py
class TestView(FormView):
template_name = 'testtemplate.html'
form_class = SimpleForm
form = None
success_url = reverse_lazy('home')
def post(self, request, *args, **kwargs):
request_POST = request.POST
requirements_count = int(request_POST.get('requirements_count', 1))
if 'add_requirement' in request_POST:
new_initial = get_initial(request_POST)
new_initial['requirements_count'] = requirements_count + 1
self.form = SimpleForm(initial=new_initial)
context = self.get_context_data(form=self.form)
response = render(request, self.template_name, context)
else:
self.form = SimpleForm(data=request_POST)
context = self.get_context_data(form=self.form)
if self.form.is_valid():
response = self.form_valid(self.form)
else:
response = render(request, self.template_name, context)
return response
def form_valid(self, form):
form.save()
return super().form_valid(self.form)
# helper function
def get_initial(previous_data):
new_initial = {}
for key, value in previous_data.items():
if value != '' and key != 'csrfmiddlewaretoken':
new_initial.update({key: value})
return new_initial
testtemplate.html
<form action="" method="post">
{% csrf_token %}
<table border="1">
{{ form.as_table }}
</table>
<input type="submit">
<input type="submit" name="add_requirement" value="Add another requirement">
{{ form.non_field_errors }}
</form>
我绝不是 Django 专家,它可能不是最好的解决方案,但它对我有用并且相对简单。