django forms组件

django forms组件

一、forms组件的作用

  ① 手写获取用户输入的前端页面代码——渲染页面

  ② 后端获取用户数据并做合法性校验——校验数据

  ③ 将检验之后的结果渲染到前端页面——展示信息

它可以做到html页面用户输入、然后提交发送到后端进行校验、再将检验之后的结果发送到前端展示的一个完整流程。

 

 

二、如何使用forms组件校验数据

  首先,先自定义一个MyRegForm类。forms组件的使用方法和创建表模型的使用方法比较相似

后端views.py代码:

from django import forms  # 导入forms组件


class MyRegForm(forms.Form):
    username = forms.CharField(max_length=8, min_length=3)  # username长度最多为8位,最少为3位
    password = forms.CharField(max_length=8, min_length=3)
    # email字段必须填写符合邮箱格式的数据
    email = forms.EmailField()

 

1、测试单个py文件的两种方法

  ① 前面已经介绍过了,在tests.py文件中写测试代码

  ② 使用django的工作台Django Console(下文中的测试过程用django工作台来进行测试)

 

2、forms组件校验数据方法

Django Console:

# 1.传入待校验的数据,用自己写的类传入字典格式的待校验的数据
from app01 import views
form_obj = views.MyRegForm({'username': 'tank', 'password': '12', 'email': '123456789'})

# 2.判断数据是否符合校验规则
form_obj.is_valid()  # 该方法只有在所有的数据全部符合校验规则时候才会返回True

# 3.获取校验之后通过的数据
form_obj.cleaned_data

# 4.获取校验失败及失败的数据
form_obj.errors

注意:forms组件默认所有的字段都必须传值,也就意味着传少了肯定是报错,而传多了没有关系,只校验里面的字段,多传的直接忽略

Django Console

form_obj = views.MyRegForm({'username': 'tank', 'password': '123456', 'email': '123456@qq.com'})
form_obj.is_valid()

form_obj = views.MyRegForm({'username': 'tank', 'password': '123456',})
form_obj.is_valid()

form_obj = views.MyRegForm({'username': 'tank', 'password': '123456', 'email': '123456@qq.com', 'age': 45646546})
form_obj.is_valid()

 

 

三、如何使用forms组件渲染页面

  在MyRegForm类的基础上写一个reg视图函数

后端views.py代码:

def reg(request):
    # 1 先生成一个空对象
    form_obj = MyRegForm()
    if request.method == 'POST':
        # 3 获取用户属性并交给forms组件进行校验
        form_obj = MyRegForm(request.POST)
    # 2 直接将该对象传给前端
    return render(request, 'reg.html', {'form_obj': form_obj})

 

1、forms组件渲染页面的第一种方式

  自动生成多个p标签,本地测试方便,封装程度太高了,不便于扩展

前端reg.html代码:

<h2>第一种渲染方式:自动生成多个p标签,本地测试方便,封装程度太高了,不便于扩展</h2>
{{ form_obj.as_p }}

 

2、forms组件渲染页面的第二种方式

  扩展性较高

前端reg.html代码:

<h2>第二种渲染方式:扩展性较高</h2>
<label for="{{ form_obj.username.id_for_label }}">
    {{ form_obj.username.label }}{{ form_obj.username }}
</label>
<label for="{{ form_obj.password.id_for_label }}">
    {{ form_obj.password.label }}{{ form_obj.password }}
</label>
<label for="{{ form_obj.email.id_for_label }}">
    {{ form_obj.email.label }}{{ form_obj.email }}
</label>

 

3、forms组件渲染页面的第三种方式

  for循环(推荐使用)

前端reg.html代码:

<h2>第三种方式:for循环  推荐使用</h2>
<form action="" method="post" novalidate>
    {% for foo in form_obj %}
        <p>
            {{ foo.label }}:{{ foo }}
            <span style="color: red">{{ foo.errors.0 }}</span>
        </p>
    {% endfor %}
    <input type="submit">
</form>

 

 

四、如何使用forms组件渲染错误信息

  数据校验一个前后端都得有,但是前端的校验安全性很差,可有可无,而后端的校验则必须非常全面

 

1、取消浏览器自动校验的功能

<form action="" method="post" novalidate></form>  // novalidate属性,使前端不对数据进行处理,直接传给后端。然后后端通过逻辑代码进行校验

 

2、演示:后端校验结果在前端渲染

后端views.py代码:

def reg(request):
    # 1 先生成一个空对象
    form_obj = MyRegForm()
    if request.method == 'POST':
        # 3 获取用户属性并交给forms组件进行校验
        form_obj = MyRegForm(request.POST)
        # 4 获取校验结果
        if form_obj.is_valid():
            return HttpResponse('数据正确')
        else:
            # 获取校验失败的字段和提示信息在后端显示
            print(form_obj.errors)
    # 2 直接将该对象传给前端
    return render(request, 'reg.html', {'form_obj': form_obj})

前端reg.html代码:

<h2>第三种方式:for循环  推荐使用</h2>
<form action="" method="post" novalidate>
    {% for foo in form_obj %}
        <p>
            {{ foo.label }}:{{ foo }}
            // 模板语法索引取错误信息,当向后端提交数据时,后端通过forms组件校验生成错误信息,前端再拿到错误信息,展示在前端界面,模板语法索引溢出不会报错
            <span style="color: red">{{ foo.errors.0 }}</span></p>
    {% endfor %}
    <input type="submit">
</form>

 

 

五、forms组件常用参数

1、label

  input的提示信息

label='用户名',  # 设置输入框提示

 

2、err_messages

  自定义报错的提示信息

error_messages={  # 设置输入不符合规范的字符之后的报错信息
       'max_length': '用户名最长8位',
       'min_length': '用户名最短3位',
       'required': '用户名不能为空',
    }

 

3、required

  设置字段是否允许为空

required=False,  # 设置False,可以提交空;默认为True,不能提交空

 

4、initial

  设置默认值

initial='tom',  # 添加输入框内的默认值

 

5、widget

  控制type类型以及属性

from django.forms import widgets  # 先导入方法


widget=forms.widgets.TextInput(attrs={'class': 'form-control'}),  # 输入框为明文文本,括号内是为输入框添加属性、样式等
widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'})  # 输入框为密文,括号内是为输入框添加属性、样式等

 

6、例子演示常用参数用法

后端views.py代码:

from django.shortcuts import render, HttpResponse, redirect
from django import forms
from django.forms import widgets
from django.core.validators import RegexValidator


class MyRegForm(forms.Form):
    username = forms.CharField(max_length=8, min_length=3,
                               label='账户',  # 设置输入框提示
                               # required=False,  # 默认为True,不能提交空,设置False,可以提交空
                               initial='tom',  # 添加输入框内的默认值
                               # 输入框为明文文本,attrs属性括号内是为输入框添加属性、样式等
                               widget=forms.widgets.TextInput(attrs={'class': 'form-control'}),
                               error_messages={  # 设置输入不符合规范的字符之后的报错信息
                                   'max_length': '用户名最长8位',
                                   'min_length': '用户名最短3位',
                                   'required': '用户名不能为空',
                               })
    password = forms.CharField(max_length=8, min_length=3, label='密码',
                               # 输入框为密文,attrs属性括号内是为输入框添加属性、样式等
                               widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}),
                               error_messages={  # 设置输入不符合规范的字符之后的报错信息
                                   'max_length': '密码最长8位',
                                   'min_length': '密码最短3位',
                                   'required': '密码不能为空',
                               })
    # email字段必须填写符合邮箱格式的数据
    email = forms.EmailField(label='邮箱',
                             initial='xxx@qq.com',  # 添加输入框内的默认值
                             widget=forms.widgets.TextInput(attrs={'class': 'form-control'}),
                             error_messages={  # 设置输入不符合规范的字符之后的报错信息
                                 'required': '邮箱必须填写',
                                 'invalid': '邮箱格式不正确'
                             })
    # 正则校验,校验手机号
    phone = forms.CharField(label='手机号码',
                            validators=[
                                RegexValidator(r'^[0-9]+$', '请输入数字'),
                                RegexValidator(r'^159[0-9]+$', '数字必须以159开头')
                                ],
                            initial='159xxxxxxxx',  # 添加输入框内的默认值
                            widget=forms.widgets.TextInput(attrs={'class': 'form-control'}),
                            error_messages={  # 设置输入不符合规范的字符之后的报错信息
                                'required': '电话号码必须填写',
                                'invalid': '电话号码格式不正确'
                            })

def reg(request):
    # 1.先生成一个空对象
    form_obj = MyRegForm()
    if request.method == 'POST':
        # 3.获取用户属性并交给forms组件进行校验
        form_obj = MyRegForm(request.POST)
        # 4.获取校验结果
        if form_obj.is_valid():
            return HttpResponse('数据正确')
    # 2.直接将该对象传给前端
    return render(request, 'reg.html', {'form_obj': form_obj})
views.py

前端reg.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post" novalidate>
                <h2>注册页面</h2>
                {% for foo in form_obj %}
                    <p>
                        {{ foo.label }}:{{ foo }}
                        <span style="color: red">{{ foo.errors.0 }}</span>
                    </p>
                {% endfor %}
                <input type="submit">
            </form>
        </div>
    </div>
</div>
</body>
</html>
reg.html

 

 

七、钩子函数

  钩子函数,就是再加一层校验方式。看一个例子,体验全局钩子、局部钩子的作用:

后端views.py代码:

from django.shortcuts import render, HttpResponse, redirect
from django import forms
from django.forms import widgets


class DoublePassword(forms.Form):
    username = forms.CharField(max_length=8, min_length=3,
                               label='账户',  # 设置输入框提示
                               # required=False,  # 默认为True,不能提交空,设置False,可以提交空
                               initial='tom',  # 添加输入框内的默认值
                               # 输入框为明文文本,attrs属性括号内是为输入框添加属性、样式等
                               widget=forms.widgets.TextInput(attrs={'class': 'form-control'}),
                               error_messages={  # 设置输入不符合规范的字符之后的报错信息
                                   'max_length': '用户名最长8位',
                                   'min_length': '用户名最短3位',
                                   'required': '用户名不能为空',
                               })
    password = forms.CharField(max_length=8, min_length=3, label='密码',
                               # 输入框为密文,attrs属性括号内是为输入框添加属性、样式等
                               widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}),
                               error_messages={  # 设置输入不符合规范的字符之后的报错信息
                                   'max_length': '密码最长8位',
                                   'min_length': '密码最短3位',
                                   'required': '密码不能为空',
                               })

    confirm_password = forms.CharField(max_length=8, min_length=3, label='确认密码',
                                       # 输入框为密文,attrs属性括号内是为输入框添加属性、样式等
                                       widget=forms.widgets.PasswordInput(attrs={'class': 'form-control'}),
                                       error_messages={  # 设置输入不符合规范的字符之后的报错信息
                                           'max_length': '确认密码最长8位',
                                           'min_length': '确认密码最短3位',
                                           'required': '确认密码不能为空',
                                       })

    # 全局钩子
    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

    # 局部钩子
    def clean_username(self):
        username = self.cleaned_data.get('username')
        if 'aaa' in username:
            self.add_error('username', '账户中不能含有aaa')
        return username


def double_password(request):
    # 1.先生成一个空对象
    password_obj = DoublePassword()
    if request.method == 'POST':
        # 3.获取用户属性并交给forms组件进行校验
        password_obj = DoublePassword(request.POST)
        # 4.获取校验结果
        if password_obj.is_valid():
            return HttpResponse('数据正确')
    # 2.直接将该对象传给前端
    return render(request, 'double_password.html', {'password_obj': password_obj})
views.py

前端double_password.html代码:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.5.1/jquery.min.js"></script>
    <link rel="stylesheet" href="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/css/bootstrap.min.css">
    <script src="https://cdn.bootcdn.net/ajax/libs/twitter-bootstrap/3.4.1/js/bootstrap.min.js"></script>
</head>
<body>
<div class="container">
    <div class="row">
        <div class="col-md-8 col-md-offset-2">
            <form action="" method="post" novalidate>
                <h2>测试密码</h2>
                {% for password in password_obj %}
                    <p>
                        {{ password.label }}:{{ password }}
                        <span style="color: red">{{ password.errors.0 }}</span>
                    </p>
                {% endfor %}
                <input type="submit">
            </form>
        </div>
    </div>
</div>
</body>
</html>
double_password.html

 

1、全局钩子(针对多个字段)

  验证:校验密码和确认密码是否一致

 

2、局部函数(针对单个字段)

  验证:校验密码中不能含有aaa

PS:如果想要同时操作多个字段的数据,那么就用全局钩子

  如果想要操作单个字段的数据,那么就用局部钩子

posted @ 2020-12-12 23:33  chchcharlie、  阅读(106)  评论(0编辑  收藏  举报