Django form组件

1、form组件概述

在HTML页面中利用form表单向后端提交数据时,都会写一些获取用户输入的标签并且用form标签把它们包起来。

与此同时我们在好多场景下都需要对用户的输入做校验,比如校验用户是否输入,输入的长度和格式等正不正确。
如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。

Django form组件就实现了上面所述的功能。

总结一下,其实form组件的主要功能如下:
    生成页面可用的HTML标签;
    对用户提交的数据进行校验;
    保留上次输入内容;


注册功能要实现的功能:
渲染前端标签获取用户输入        >> 渲染标签
获取用户输入传递到后端校验      >> 校验数据
校验未通过展示错误信息          >> 展示信息


校验数据前端后端都可以做,但是前端可以不做,后端必须得做;一般是前端校验+后端校验;


2、form组件在校验数据中的使用

views.py 需要先写一个类,有点像ORM:
# 先导包
from django import forms

class MyForm(forms.Form):
    name = forms.CharField(max_length=6)
    password = forms.CharField(max_length=8, min_length=3)
    email = forms.EmailField()


验证:

可以在pycharm的python console中校验,相当于一个tests.py:

Django form组件

# 校验步骤:

# 实例化form对象,并传入值
form_obj = MyForm({'name':'jason'})
            
# 查看数据校验是否合法
form_obj.is_valid()   # 只有当所有的字段都校验通过才会返回True
            
# 查看校验错误的信息
form_obj.errors   # 这个里面放的是所有校验未通过的字段及错误提示
"""
{
'name': ['Ensure this value has at most 6 characters (it has 7).'], 
'password': ['Ensure this value has at least 3 characters (it has 2).'], 
'email': ['Enter a valid email address.']
}
"""

# 查看校验通过的数据
form_obj.cleaned_data   # 符合校验规则数据都会被放到该对象中


注意:

form组件校验数据的规则从上往下依次取值校验,无论值的正确与否,都要进行校验:
*校验通过的放到cleaned_data
*校验失败的放到errors

注意:
    form中所有的字段默认都是必须传值的(required=True)
    校验数据的时候可以多传(多传的数据不会做任何的校验>>>不会影响form校验规则)


3、form组件在渲染标签中的使用

form组件可以帮你渲染获取用户输入的标签,不会帮你渲染提交按钮,须手动添加。

第一种渲染方式:

views.py

from django import forms
class MyForm(forms.Form):
    name = forms.CharField(max_length=6)
    password = forms.CharField(max_length=8, min_length=3)
    email = forms.EmailField()


def reg(request):
    # 生成一个空对象
    form_obj = MyForm()
    return render(request, 'reg.html', locals())


reg.html

<body>
<h1>第一种渲染方式</h1>
{{ form_obj.as_p }}    //以p标签的形式显示出来
{{ form_obj.as_ul }}   //以li标签的形式显示出来
</body>


// 此方式封装性高,导致可扩展性差,建议用于本地测试

Django form组件


第二种渲染方式:

views.py和第一种相同;


reg.html

<body>
<h1>第二种渲染方式</h1>
<form action="">
    <p>{{ form_obj.name.label }}: {{ form_obj.name }}</p>  //lable不配置的话,默认用类中字段的首字母大写(如:Name)
    <p>{{ form_obj.password.label }}: {{ form_obj.password }}</p>
    <p>{{ form_obj.email.label }}: {{ form_obj.email }}</p>
    <input type="submit">
</form>
</body>


// 此方式可以实现功能,但代码冗余


lable也可以自己配:

# views.py

class MyForm(forms.Form):
    name = forms.CharField(max_length=6, label='用户名')  # 这里就是配置了,前端调的时候就会用配的这个
    password = forms.CharField(max_length=8, min_length=3)
    email = forms.EmailField()

Django form组件


第三种渲染方式(推荐):

reg.html

<body>
<h1>第三张渲染方式</h1>
<form action="" method="post">
    {% for foo in form_obj %}
        <p>{{ foo.label }}: {{ foo }}</p>
    {% endfor %}
    <input type="submit">
</form>
</body>


4、form综合使用

models.py

from django.db import models

# Create your models here.
class User(models.Model):
    name = models.CharField(max_length=32)
    password = models.CharField(max_length=32)
    email = models.EmailField()


views.py

from django.shortcuts import render, HttpResponse
from django import forms
from app01 import models


class MyForm(forms.Form):
    # error_messages中可以写各种错误对应的提示信息
    name = forms.CharField(max_length=6, label='用户名', error_messages={
        'max_length': '用户名最长为6位',
        'required': '用户名不能为空'
    })
    password = forms.CharField(max_length=8, min_length=3, error_messages={
        'max_length': '密码最长为8位',
        'required': '密码不能为空',
        'min_length': '密码最少为3位'
    })

    email = forms.EmailField(error_messages={
        'invalid': '邮箱格式不正确',
        'required': '邮箱不能为空'
    })


def reg(request):
    # 生成一个空对象
    form_obj = MyForm()
    if request.method == 'POST':
        print(request.POST)
        form_obj = MyForm(request.POST)
        if form_obj.is_valid():
            print(form_obj.cleaned_data)
            models.User.objects.create(**form_obj.cleaned_data)
    return render(request, 'reg.html', locals())


# form组件提交数据如果数据不合法,页面上会保留之前用户输入的信息
# 在使用form组件对模型表进行数据校验的时候,只需要保证form类中的字段和ORM建表字段一致,那么在创建对象的时候你就可以直接**form_obj.cleaned_data


reg.html

<body>

<form action="" method="post" novalidate>  <!--novalidate:取消前端校验-->
    {% for foo in form_obj %}
        <p>{{ foo.label }}: {{ foo }}
            <span>{{ foo.errors.0}}</span>
        </p>
    {% endfor %}
    <input type="submit">
</form>
</body>


5、form钩子函数

局部钩子:可以对单个字段进行校验,在Fom类中定义 clean_字段名() 格式的方法

views.py

class MyForm(forms.Form):
    # error_messages中写各种错误对应的提示信息
    name = forms.CharField(max_length=6, label='用户名', error_messages={
        'max_length': '用户名最长为6位',
        'required': '用户名不能为空'
    })
    password = forms.CharField(max_length=8, min_length=3, error_messages={
        'max_length': '密码最长为8位',
        'required': '密码不能为空',
        'min_length': '密码最少为3位'
    })

    # 加一个确认密码字段 
    confirm_password = forms.CharField(max_length=8, min_length=3, error_messages={
        'max_length': '确认密码最长为8位',
        'required': '确认密码不能为空',
        'min_length': '确认密码最少为3位'
    })

    email = forms.EmailField(error_messages={
        'invalid': '邮箱格式不正确',
        'required': '邮箱不能为空'
    })

    # 局部钩子函数,校验username字段
    def clean_name(self):
        # 上面的校验完成后,才会走钩子函数,所以正确的数据都在cleaned_data中
        name = self.cleaned_data.get('name')
        if '666' in name:
            # 警示信息
            self.add_error('name', '光喊666是不行的;')
        return name  # return还是要加上的,兼容性考虑


全局钩子:对多个字段校验

# 比如加了一个确认密码的字段,现在要验证密码框和确认密码框中的数据一致,就可以用全局钩子函数了

# views.py
class MyForm(forms.Form):
    # error_messages中写各种错误对应的提示信息
    name = forms.CharField(max_length=6, label='用户名', error_messages={
        'max_length': '用户名最长为6位',
        'required': '用户名不能为空'
    })
    password = forms.CharField(max_length=8, min_length=3, error_messages={
        'max_length': '密码最长为8位',
        'required': '密码不能为空',
        'min_length': '密码最少为3位'
    })

    confirm_password = forms.CharField(max_length=8, min_length=3, error_messages={
        'max_length': '确认密码最长为8位',
        'required': '确认密码不能为空',
        'min_length': '确认密码最少为3位'
    })

    email = forms.EmailField(error_messages={
        'invalid': '邮箱格式不正确',
        'required': '邮箱不能为空'
    })

    # 局部钩子函数,校验username字段
    def clean_name(self):
        # 上面的校验完成后,才会走钩子函数,所以正确的数据都在cleaned_data中
        name = self.cleaned_data.get('name')
        if '666' in name:
            # 警示信息
            self.add_error('name', '光喊666是不行的;')
        return name  # return还是要加上的,兼容性考虑

    # 定义全局的钩子,用来校验密码和确认密码字段是否相同
    def clean(self):
        password = self.cleaned_data.get('password')
        confirm_password = self.cleaned_data.get('confirm_password')
        if not password == confirm_password:
            self.add_error('confirm_password', '两次密码不一致')
        return self.cleaned_data


6、设置标签样式

class MyForm(forms.Form):
    # error_messages中写各种错误对应的提示信息
    name = forms.CharField(max_length=6, label='用户名', error_messages={
        'max_length': '用户名最长为6位',
        'required': '用户名不能为空'
    })

    # widget=widgets.PasswordInput(attrs={'class': 'form-control c1'}) 设置输入框为密文形式,并设置class
    password = forms.CharField(max_length=8, min_length=3, error_messages={
        'max_length': '密码最长为8位',
        'required': '密码不能为空',
        'min_length': '密码最少为3位'
    }, widget=widgets.PasswordInput(attrs={'class': 'form-control c1'}))

    confirm_password = forms.CharField(max_length=8, min_length=3, error_messages={
        'max_length': '确认密码最长为8位',
        'required': '确认密码不能为空',
        'min_length': '确认密码最少为3位'
    }, widget=widgets.PasswordInput())

    email = forms.EmailField(error_messages={
        'invalid': '邮箱格式不正确',
        'required': '邮箱不能为空'
    })

    # RadioSelect
    gender = forms.ChoiceField(
        choices=((1, ""), (2, ""), (3, "保密"),),
        label="爱好",
        initial=3,  # 默认值
        widget=forms.widgets.RadioSelect()
    )

    # 单选的select
    hobby = forms.ChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=3,
        widget=forms.widgets.Select()
    )

    # 多选的select
    hobby1 = forms.MultipleChoiceField(
        choices=((1, "篮球"), (2, "足球"), (3, "双色球"),),
        label="爱好",
        initial=[1, 3],
        widget=forms.widgets.SelectMultiple()
    )

    # 单选checkbox
    keep = forms.ChoiceField(
        label="是否记住密码",
        initial="checked",
        widget=forms.widgets.CheckboxInput()
    )


Django form组件