Django基础(11): 表单集合Formset的高级用法详解

Formset(表单集)是多个表单的集合。Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据,比如一个页面上添加多个用户信息。今天小编我就介绍下Django Formset的基础知识,Formset的分类以及如何使用Formset。为什么要使用Django Formset我们先来下看下Django中不使用Formset情况下是如何在同...
摘要由CSDN通过智能技术生成

Formset(表单集)是多个表单的集合。Formset在Web开发中应用很普遍,它可以让用户在同一个页面上提交多张表单,一键添加多个数据,比如一个页面上添加多个用户信息。今天小编我就介绍下Django Formset的基础知识,Formset的分类以及如何使用Formset。

 

为什么要使用Django Formset

我们先来下看下Django中不使用Formset情况下是如何在同一页面上一键提交2张或多张表单的。我们在模板中给每个表单取不同的名字,如form1和form2(如下面代码所示)。注: form1和form2分别对应forms.py里的Form1()和Form2()。

<form >
    {
  { form1.as_p }}
    {
  { form2.as_p }}
</form>

用户点击提交后,我们就可以在视图里了对用户提交的数据分别处理。

if request.method == 'POST':
        form1 = Form1( request.POST,prefix="form1")
        form2 = Form2( request.POST,prefix="form2")
        
        if form1.is_valid() or form2.is_valid(): 
            pass
else:
        form1 = Form1(prefix="form1")
        form2 = Form2(prefix="form2")

这段代码看似并不复杂,然而当表单数量很多或不确定时,这个代码会非常冗长。我们希望能控制表单的数量,这是我们就可以用Formset了。

 

Formset的分类

Django针对不同的formset提供了3种方法: formset_factory, modelformset_factory和inlineformset_factory。我们接下来分别看下如何使用它们。

 

如何使用formset_factory

对于继承forms.Form的自定义表单,我们可以使用formset_factory。我们可以通过设置extra和max_num属性来确定我们想要展示的表单数量。注意: max_num优先级高于extra。比如下例中,我们想要显示3个空表单(extra=3),但最后只会显示2个空表单,因为max_num=2。

 

from django import forms


class BookForm(forms.Form):
    name = forms.CharField(max_length=100)
    title = forms.CharField()
    pub_date = forms.DateField(required=False)


# forms.py - build a formset of books

from django.forms import formset_factory
from .forms import BookForm

# extra: 想要显示空表单的数量
# max_num: 表单显示最大数量,可选,默认1000

BookFormSet = formset_factory(BookForm, extra=3, max_num=2)

 

在视图文件views.py里,我们可以像使用form一样使用formset。

# views.py - formsets example.
from .forms import BookFormSet
from django.shortcuts import render

def manage_books(request):
    if request.method == 'POST':
        formset = BookFormSet(request.POST, request.FILES)
        if formset.is_valid():
            # do something with the formset.cleaned_data
            pass
    else:
        formset = BookFormSet()
    return render(request, 'manage_books.html', {'formset': formset})

模板里可以这样使用formset。

 

<form action=”.” method=”POST”>
{
  { formset }}
</form>

 

也可以这样使用。

<form method="post">
    {
  { formset.management_form }}
    <table>
        {% for form in formset %}
        {
  { form }}
        {% endfor %}
    </table>
</form>

 

如何使用modelformset_factory

Formset也可以直接由模型model创建,这时你需要使用modelformset_factory。你可以指定需要显示的字段和表单数量。

from django.forms import modelformset_factory
from myapp.models import Author

AuthorFormSet = modelformset_factory(
    Author, fields=('name', 'title'), extra = 3)

 

当然上面方法我并不推荐,因为对单个表单添加验证方法非常不方便。我更喜欢的方式先创建自定义的ModelForm,添加单个表单验证,然后再利用modelformset_factory创建formset。

class AuthorForm(forms.ModelForm):
    class Meta:
        model = Author
        fields = ('name', 'title')

    def clean_name(self):
        # custom validation for the name field
        ...

由ModelForm创建formset:

AuthorFormSet = modelformset_factory(Author, form=AuthorForm)

在模板和视图里使用formset的方法与前面的例子是一样的。

 

如何使用inlineformset_factory

试想我们有如下recipe模型,Recipe与Ingredient是单对多的关系。一般的formset只允许我们一次性提交多个Recipe或多个Ingredient。但如果我们希望同一个页面上添加一个菜谱(Recipe)和多个原料(Ingredient),这时我们就需要用使用inlineformset了。

from django.db import models


class Recipe(models.Model):
    title = models.CharField(max_length=255)
    description = models.TextField()


class Ingredient(models.Model):
    recipe = models.ForeignKey(Recipe, on_delete=models.CASCADE, related_name='ingredient')
    name = models.CharField(max_length=255)

 

利用inlineformset_factory创建formset的方法如下所示。该方法的第一个参数和第二个参数都是模型,其中第一个参数必需是ForeignKey。

# forms.py
from django.forms import ModelForm
from django.forms import inlineformset_factory

from .models import Recipe, Ingredient, Instruction


class RecipeForm(ModelForm):
    class Meta:
        model = Recipe
        fields = ("title", "description",)


IngredientFormSet = inlineformset_factory(Recipe, Ingredient, fields=('name',),
                                          extra=3, can_delete=False, max_num=5)

views.py中使用formset创建和更新recipe的代码如下。在对IngredientFormSet进行实例化的时候,必需指定recipe的实例。

def recipe_update(request, pk):
    recipe = get_object_or_404(Recipe, pk=pk)
    if request.method == "POST":
        form = RecipeForm(request.POST, instance=recipe)

        if form.is_valid():
            recipe = form.save()
            ingredient_formset = IngredientFormSet(request.POST, instance=recipe)

            if ingredient_formset.is_valid():
                ingredient_formset.save()

        return redirect('/recipe/')
    else:
        form = RecipeForm(instance=recipe)
        ingredient_formset = IngredientFormSet(instance=recipe)

    return render(request, 'recipe/recipe_update.html', {'form': form,
                                                         'ingredient_formset': ingredient_formset,
                                                      })

def recipe_add(request):
    if request.method =&#
  • 6
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值