在 Web 开发中,经常需要在同一个页面中显示多个模型表单,并使用一个按钮提交所有表单。例如,在一个电子商务网站中,用户可能需要填写个人信息、收货地址和支付信息,然后点击一个按钮提交订单。
然而,Django 默认的表单处理方式是每个表单对应一个提交按钮。如果要在同一个页面中显示多个模型表单,我们需要使用一些特殊的方法。
2、解决方案
1. 使用 Formset
Formset 是 Django 提供的一种用于处理多个表单的工具。它可以将多个表单放在一个页面中显示,并使用一个按钮提交所有表单。
2. 使用 inline formsets
Inline formsets 是 Formset 的一种特殊形式,它可以将多个表单嵌套在另一个表单中。这对于处理一对多关系的模型非常有用。
3. 使用 JavaScript
也可以使用 JavaScript 动态创建和删除表单。这种方法比较灵活,但需要更多的代码。
4. 使用第三方库
也有许多第三方库可以帮助我们在 Django 中处理多个表单。这些库通常提供了更友好的 API 和更丰富的功能。
3、代码例子
1. 使用 Formset
from django.forms import formset_factory
class AForm(ModelForm):
class Meta:
model = model_a
class BForm(ModelForm):
class Meta:
model = model_b
class CForm(ModelForm):
class Meta:
model = model_c
BFormSet = formset_factory(BForm, extra=3)
CFormSet = formset_factory(CForm, extra=3)
def my_view(request):
if request.method == 'POST':
a_form = AForm(request.POST)
b_formset = BFormSet(request.POST)
c_formset = CFormSet(request.POST)
if a_form.is_valid() and b_formset.is_valid() and c_formset.is_valid():
a_form.save()
for b_form in b_formset:
b_form.instance.forign_key_to_a = a_form.instance
b_form.save()
for c_form in c_formset:
c_form.instance.forign_key_to_b = b_form.instance
c_form.save()
return HttpResponseRedirect('/success/')
else:
a_form = AForm()
b_formset = BFormSet()
c_formset = CFormSet()
context = {
'a_form': a_form,
'b_formset': b_formset,
'c_formset': c_formset,
}
return render(request, 'my_template.html', context)
2. 使用 inline formsets
from django.contrib.admin.widgets import InlineModelAdminFormSet
class BInlineFormSet(InlineModelAdminFormSet):
model = model_b
class CInlineFormSet(InlineModelAdminFormSet):
model = model_c
class AForm(ModelForm):
class Meta:
model = model_a
inline_formsets = {
'b_formset': BInlineFormSet,
'c_formset': CInlineFormSet,
}
def my_view(request):
if request.method == 'POST':
a_form = AForm(request.POST)
if a_form.is_valid():
a_form.save()
# Save the inline formsets
a_form.save_related()
return HttpResponseRedirect('/success/')
else:
a_form = AForm()
context = {
'a_form': a_form,
}
return render(request, 'my_template.html', context)
3. 使用 JavaScript
<script type="text/javascript">
$(document).ready(function() {
var b_formset = $('#b_formset');
var c_formset = $('#c_formset');
// Add a new B form
$('#add_b_form').click(function() {
var form = b_formset.find('.form-row:last').clone();
form.find('input').val('');
b_formset.append(form);
});
// Add a new C form
$('#add_c_form').click(function() {
var form = c_formset.find('.form-row:last').clone();
form.find('input').val('');
c_formset.append(form);
});
// Submit the forms
$('#submit_button').click(function() {
var a_form = $('#a_form');
var b_forms = b_formset.find('.form-row');
var c_forms = c_formset.find('.form-row');
// Validate the forms
if (a_form.valid() && b_forms.valid() && c_forms.valid()) {
// Submit the forms
a_form.submit();
b_forms.submit();
c_forms.submit();
}
});
});
</script>
4. 使用第三方库
# Django MultiFormView: https://github.com/wagtail/django-multiformview
class MyFormView(MultiFormView):
form_classes = {
'a_form': AForm,
'b_formset': BFormSet,
'c_formset': CFormSet,
}
def get_success_url(self):
return reverse('success')
def forms_valid(self, forms):
# Save the forms
a_form = forms['a_form']
b_formset = forms['b_formset']
c_formset = forms['c_formset']
a_form.save()
for b_form in b_formset:
b_form.instance.forign_key_to_a = a_form.instance
b_form.save()
for c_form in c_formset:
c_form.instance.forign_key_to_b = b_form.instance
c_form.save()
return super().forms_valid(forms)