📅  最后修改于: 2023-12-03 15:28:58.913000             🧑  作者: Mango
在Django中,内联表单集允许我们在同一页面上展示多个表单。 使用内联表单集,用户可以在一次提交中更新或创建多个相关对象。 在本文中,我们将了解如何使用Django内联表单集,并在删除时验证内联表单集。
内联表单集是管理多个相关模型时一个非常方便的方法。 通常,父模型与多个子模型相关联,例如用户拥有多个帖子或相册。 内联表单集允许我们在一张表单中展示父模型和相关联的子模型的表单。 这样,用户可以在同一页面上创建或编辑多个对象。
在Django中,内联表单集通过formsets实现。formset是一个表单的集合,每个表单都与一个对象相关联。 在内联表单集中,formset将所有子表单作为一个组在主表单中展示。
创建内联表单集的过程很简单,我们只需要定义父模型的表单(通常是ModelForm)和相关联的子模型的表单的集合(通常是inlineformset_factory),然后将它们渲染出来即可。
下面是定义内联表单集的基本示例:
from django.forms import inlineformset_factory
from .models import Parent, Child
ChildFormSet = inlineformset_factory(Parent, Child, fields=('name', 'age'))
parent = Parent.objects.get(pk=1)
formset = ChildFormSet(instance=parent)
上面的代码中,ChildFormSet是一个动态创建的表单集类,用于关联Parent和Child模型。fields参数定义了子表单中包含哪些字段。 在实例化表单集时,我们将父对象传递给它,然后它将自动为该父对象创建一个表单集。
现在,我们可以在视图中呈现这些表单:
from django.shortcuts import render
def my_view(request):
parent = Parent.objects.get(pk=1)
formset = ChildFormSet(instance=parent)
return render(request, 'my_template.html', {'formset': formset})
最后,我们需要为表单设置相应的模板。 下面是一个基本的模板示例:
<form method="POST">
{% csrf_token %}
{{ form.as_p }}
{% for form in formset %}
{{ form.as_p }}
{% endfor %}
<button type="submit">Save</button>
</form>
在渲染HTML应用程序时,Django将处理表单的应答和验证并保存模型实例。 内联表单集与常规表单工作原理相同,只是在提交页面时需要注意。
默认情况下,内联表单集允许在提交表单时添加和编辑相关模型实例。 如果要从表单集中删除,我们可以在每个子表单中添加一个复选框。
为了删除子模型类的实例,我们需要在表单集定义中使用can_delete选项:
ChildFormSet = inlineformset_factory(Parent, Child, fields=('name', 'age'), can_delete=True)
现在,我们可以在子表单中为每个实例添加一个复选框,这将允许用户选择要删除的实例:
{% for form in formset %}
{{ form.as_p }}
{% if form.instance.pk %}
<label for="{{ form.DELETE.id_for_label }}">Delete</label>
{{ form.DELETE }}
{% endif %}
{% endfor %}
在上面的代码中,我们检查每个表单实例是否有一个主键(即该实例是否已保存)。 如果是,则显示一个复选框Delete来允许用户将该实例从表单集中删除。
现在,我们可以保存表单并删除子对象。 但是,为了在提交表单之前执行自定义验证,我们需要用自定义表单集重载表单集中的delete方法。删除的验证由can_delete提供的印记函数完成。
下面是示例代码:
from django.forms.models import BaseInlineFormSet
class ChildFormSet(BaseInlineFormSet):
def clean(self):
super().clean()
for form in self.forms:
# check if there's a child instance attached to the form
if hasattr(form, 'cleaned_data'):
if form.cleaned_data.get('DELETE', False):
# if the form is about to be deleted anyway, no further validation is required
return
name = form.cleaned_data.get('name')
age = form.cleaned_data.get('age')
# additional validation
if name.startswith('bad word'):
raise forms.ValidationError(f"Child's name starts with bad word")
if age < 0:
raise forms.ValidationError(f"Child's age can't be negative")
上面的代码中,我们定义了一个自定义表单集,它继承了BaseInlineFormSet。 clean方法用于验证每个表单中列出的子模型对象。
如果复选框被选中,那么我们不需要执行验证,并且将跳过验证。 如果没有删除,我们将对每个子表单中的name和age字段执行验证。
在上面的示例中,我们在名称中查找了“bad word”,并且如果子表单中的age字段小于零,则会引发ValidationError。
现在,在提交父表单并在引发任何验证错误前,内联表单集中的所有表单都会执行自定义验证。
内联表单集是一个强大的工具,使我们能够轻松管理多个相关对象。 在这篇文章中,我们学习了如何创建和验证内联表单集,特别是删除子对象的验证。
希望这篇文章对您有所帮助!