在 Django 中显示三个模型表单并使用一个按钮提交

80 阅读2分钟

在 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)