Django 中的Form表单认证

一、Form表单
 
1.1 Form的几个功能
  1. 验证用户数据(显示错误信息)

  2. 初始化页面显示内容

  3. HTML Form提交保留上次提交数据

  4. 生成HTML标签

 

1.2 创建表单类Form

1. 创建的类必须继承类:forms.Form

2. 字段名必须与前端表单中的名称一致(完全一样)

3. Field类是所有其他类的基类

#!/usr/bin/env python
# -*- coding:utf-8 -*-
import re

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import ValidationError

def mobile_validate(value):
    pattern_mobile= '^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$'
    if not re.match(pattern_mobile, str(value)):

        raise ValidationError('手机号码格式错误')

class UserForm(forms.Form):

    user = fields.CharField(
        min_length=4,
        max_length=12,
        error_messages={
            "required": "用户名不能为空",
            "min_length": "长度必须大于4",
            "max_length": "长度必须小于12"
        }
    )
    email = fields.EmailField(
        error_messages={
            "required": "邮箱不能为空",
            "invalid": "格式不合法"
        }
    )
    wechat = fields.CharField(
        error_messages={
            "required": "微信号还是填上吧!"
        }
    )
    phone_number = fields.IntegerField(
        # validators= ['^1[3-8]{2}\d{8}$',],
        validators= [mobile_validate,],
        error_messages= {
            "required": "手机号不能为空",
            "invalid": "手机号格式有误"
        }
    )
    group = fields.ChoiceField(
        choices=((1,"普通用户"), (2, "员工用户"), (3, "黑名单")),
        error_messages={
            "required": "用户类型必选",
            "invalid": "只能为选择框中的内容"
        }
    )
    partment = fields.ChoiceField(
        choices=(
            (0,"人力资源"),
            (1,"运营维护"),
            (2,"销售部"),
            (3,"开发部"),
            (4,"项目部"),
            (5,"后勤管理"),
        ),
        error_messages = {
            "required": "所属部门必选",
            "invalid": "必须为提供的选项中的值"
        }
    )

 

1.3 视图函数处理
  1. HTML Form提交保留上次提交数据 及“GET”方式提交生成form内的标签
    实现方式:在"GET"方法内生成一个Form对象 obj = my_form.UserForm() 并传入前端

  2. 验证用户数据
    实现方式:在"POST"方法中创建一个Form对象并把POT提交的数据传入
    obj = my_form.UserForm(request.POST)
    if obj.is_valid():
        data = obj.cleaned_data
        #在这儿去数据库创建数据
        # models.User.objects.create(**data)
    else:
        errors = obj.errors.as_data()

def adduser(request):
    """使用Form表单验证,新增用户是否合法"""
    users = models.User.objects.all()
    if request.method == "GET":
        obj = my_form.UserForm()  #这儿就能保证上次的错误信息还给保留
        response = render(request, 'cmdb/usermanage.html',{
            "obj": obj,  
            "users": users,
        })
    elif request.method == "POST":
        obj = my_form.UserForm(request.POST)
        if obj.is_valid():
            data = obj.cleaned_data
            #在这儿去数据库创建数据
            # models.User.objects.create(**data)
        else:
            errors = obj.errors.as_data()
        response = render(request, 'cmdb/usermanage.html', {
            "users": users,
            "obj":obj,
        })
    return response

 

1.4 Form验证时几个方法代表的含义
  • obj = UserForm(request.POST) #生成一个将要验证的对象

1. obj.is_valid() #开始验证, 所有数据验证过了返回True 有一个错误就返回False

2. obj.cleaned_data #所有正确的数据都在这里面
obj.clearned_data.as_json() #json 格式展示数据
obj.cleaned_data.as_data

3. obj.errors #包含了所有验证错误的方法

 

1.5 前端生成html标签
  • obj = my_form.UserForm() #已将标签打包

  • response = render(request, 'url',{"obj": obj, "users": users,}) #将数据传入前端

  1. obj.user 会自动生成 <input type="text" name="user"/>标签,同理其他
    在此我使用的表格形式
<form action="/cmdb/add-user/" method="POST">
{% csrf_token %}
<tr option="add">
    <td>{{ obj.user }}<span class="error_msg">{{ obj.errors.user.0 }}</span></td>
    <td>{{ obj.email }}<span class="error_msg">{{ obj.errors.email.0 }}</span></td>
    <td>{{ obj.wechat }}<span class="error_msg">{{ obj.errors.wechat.0 }}</span></td>
    <td>{{ obj.phone_number }}<span class="error_msg">{{ obj.errors.phone_number.0 }}</span></td>
    <td>{{ obj.group }}<span class="error_msg">{{ obj.errors.group.0 }}</span></td>
    <td>{{ obj.partment }}<span class="error_msg">{{ obj.errors.partment.0 }}</span></td>
    <td>默认当前时间</td>
    <td style="width: 80px">
        <input type="submit" value="新增用户"/>
    </td
</tr>

实际效果

 

二、Form中的参数

创建Form类时,主要涉及到 【字段】 和 【插件】,字段用于对用户请求数据的验证,插件用于自动生成HTML;

  1. 内置字段如下:
Field
    required=True,               是否允许为空
    widget=None,                 HTML插件
    label=None,                  用于生成Label标签或显示内容
    initial=None,                初始值
    help_text='',                帮助信息(在标签旁边显示)
    error_messages=None,         错误信息 {'required': '不能为空', 'invalid': '格式错误'}
    show_hidden_initial=False,   是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
    validators=[],               自定义验证规则
    localize=False,              是否支持本地化
    disabled=False,              是否可以编辑
    label_suffix=None            Label内容后缀
 
 
CharField(Field)
    max_length=None,             最大长度
    min_length=None,             最小长度
    strip=True                   是否移除用户输入空白
 
IntegerField(Field)
    max_value=None,              最大值
    min_value=None,              最小值
 
FloatField(IntegerField)
    ...
 
DecimalField(IntegerField)
    max_value=None,              最大值
    min_value=None,              最小值
    max_digits=None,             总长度
    decimal_places=None,         小数位长度
 
BaseTemporalField(Field)
    input_formats=None          时间格式化   
 
DateField(BaseTemporalField)    格式:2015-09-01
TimeField(BaseTemporalField)    格式:11:12
DateTimeField(BaseTemporalField)格式:2015-09-01 11:12
 
DurationField(Field)            时间间隔:%d %H:%M:%S.%f
    ...
 
RegexField(CharField)
    regex,                      自定制正则表达式
    max_length=None,            最大长度
    min_length=None,            最小长度
    error_message=None,         忽略,错误信息使用 error_messages={'invalid': '...'}
 
EmailField(CharField)      
    ...
 
FileField(Field)
    allow_empty_file=False     是否允许空文件
 
ImageField(FileField)      
    ...
    注:需要PIL模块,pip3 install Pillow
    以上两个字典使用时,需要注意两点:
        - form表单中 enctype="multipart/form-data"
        - view函数中 obj = MyForm(request.POST, request.FILES)
 
URLField(Field)
    ...
 
 
BooleanField(Field)  
    ...
 
NullBooleanField(BooleanField)
    ...
 
ChoiceField(Field)
    ...
    choices=(),                选项,如:choices = ((0,'上海'),(1,'北京'),)
    required=True,             是否必填
    widget=None,               插件,默认select插件
    label=None,                Label内容
    initial=None,              初始值
    help_text='',              帮助提示
 
 
ModelChoiceField(ChoiceField)
    ...                        django.forms.models.ModelChoiceField
    queryset,                  # 查询数据库中的数据
    empty_label="---------",   # 默认空显示内容
    to_field_name=None,        # HTML中value的值对应的字段
    limit_choices_to=None      # ModelForm中对queryset二次筛选
     
ModelMultipleChoiceField(ModelChoiceField)
    ...                        django.forms.models.ModelMultipleChoiceField
 
 
     
TypedChoiceField(ChoiceField)
    coerce = lambda val: val   对选中的值进行一次转换
    empty_value= ''            空值的默认值
 
MultipleChoiceField(ChoiceField)
    ...
 
TypedMultipleChoiceField(MultipleChoiceField)
    coerce = lambda val: val   对选中的每一个值进行一次转换
    empty_value= ''            空值的默认值
 
ComboField(Field)
    fields=()                  使用多个验证,如下:即验证最大长度20,又验证邮箱格式
                               fields.ComboField(fields=[fields.CharField(max_length=20), fields.EmailField(),])
 
MultiValueField(Field)
    PS: 抽象类,子类中可以实现聚合多个字典去匹配一个值,要配合MultiWidget使用
 
SplitDateTimeField(MultiValueField)
    input_date_formats=None,   格式列表:['%Y--%m--%d', '%m%d/%Y', '%m/%d/%y']
    input_time_formats=None    格式列表:['%H:%M:%S', '%H:%M:%S.%f', '%H:%M']
 
FilePathField(ChoiceField)     文件选项,目录下文件显示在页面中
    path,                      文件夹路径
    match=None,                正则匹配
    recursive=False,           递归下面的文件夹
    allow_files=True,          允许文件
    allow_folders=False,       允许文件夹
    required=True,
    widget=None,
    label=None,
    initial=None,
    help_text=''
 
GenericIPAddressField
    protocol='both',           both,ipv4,ipv6支持的IP格式
    unpack_ipv4=False          解析ipv4地址,如果是::ffff:192.0.2.1时候,可解析为192.0.2.1, PS:protocol必须为both才能启用
 
SlugField(CharField)           数字,字母,下划线,减号(连字符)
    ...
 
UUIDField(CharField)           uuid类型
2.2 插件方法
  • from django.forms import widgets #使用插件将CharField 中的内容生成文本域 textarea 标签
    textarea = fields.CharField(
        error_messages={"required": "文本域不能为空"}
        widget = widgets.Textarea
    )
TextInput(Input)
NumberInput(TextInput)
EmailInput(TextInput)
URLInput(TextInput)
PasswordInput(TextInput)
HiddenInput(TextInput)
Textarea(Widget)
DateInput(DateTimeBaseInput)
DateTimeInput(DateTimeBaseInput)
TimeInput(DateTimeBaseInput)
CheckboxInput
Select
NullBooleanSelect
SelectMultiple
RadioSelect
CheckboxSelectMultiple
FileInput
ClearableFileInput
MultipleHiddenInput
SplitDateTimeWidget
SplitHiddenDateTimeWidget
SelectDateWidget
常用插件
单radio,值为字符串
user = fields.CharField(
    initial=2,
    widget=widgets.RadioSelect(choices=((1,'上海'),(2,'北京'),))
)

单radio,值为字符串
user = fields.ChoiceField(
    choices=((1, '上海'), (2, '北京'),),
    initial=2,
    widget=widgets.RadioSelect
)

单select,值为字符串
user = fields.CharField(
    initial=2,
    widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))
)

单select,值为字符串
user = fields.ChoiceField(
    choices=((1, '上海'), (2, '北京'),),
    initial=2,
    widget=widgets.Select
)

多选select,值为列表
user = fields.MultipleChoiceField(
    choices=((1,'上海'),(2,'北京'),),
    initial=[1,],
    widget=widgets.SelectMultiple
)

单checkbox
user = fields.CharField(
    widget=widgets.CheckboxInput()
)


多选checkbox,值为列表
user = fields.MultipleChoiceField(
    initial=[2, ],
    choices=((1, '上海'), (2, '北京'),),
    widget=widgets.CheckboxSelectMultiple

 

三、定义自己的验证规则

1. 第一种方式自定义函数
将自定义的函数加入 validators = [] 参数中

from django.forms import ValidationError

def mobile_validate(value):
    pattern_mobile= '^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$'
    if not re.match(pattern_mobile, str(value)):

        raise ValidationError('手机号码格式错误')

#Form类中
class UserForm(forms.Form):

    phone_number = fields.IntegerField(
        validators= [mobile_validate,],     #将自定义的函数加入validators参数中
        error_messages= {
            "required": "手机号不能为空",
            "invalid": "手机号格式有误"
        }
    )

#或
phone_number = forms.CharField(validators=[mobile_validate, ],

                          error_messages={'required': '手机不能为空'},

                            widget=forms.TextInput(attrs={'class': "phone",

                                                          'placeholder': '+86 13356475897'}))

2. 第二种方式自定义函数
将自定义的函数加入 validators = [] 参数中

from django.core.validators import RegexValidator
 
class UserForm(Form):

    phone_number = fields.IntegerField(
        validators=[RegexValidator('^1\d{10}$', '手机号非法'), RegexValidator('^133[0-9]{8}$', '只能为联通号')],
    )
posted @ 2018-09-17 00:14  G1733  阅读(419)  评论(0编辑  收藏  举报