Django之forms组件

  一、校验数据功能

  我们在写注册页面时,之前只是提交了数据,然后就保存了数据,后端根本就没有对数据进行校验,比如价格写的不是纯数字也让保存,这肯定是不行的,在前端是可以校验的,但我们不能只依靠前端验证,万一前端不校验,那整个过程就没校验了,所以,不管前端有没有校验,我们后端都应该进行验证。

  现在注册页面要向我提交三个数据,用户名、密码、邮箱,当它提交过来后,首先我要对数据进行校验,根据数据的校验结果然后再决定保存还是给前端返回错误信息。

  views.py

from django import  forms
class UserInfo_form(forms.Form):
    name=forms.CharField(max_length=10,label=‘姓名‘)
    email = forms.CharField(max_length=20, label=‘邮箱‘)
    pwd=forms.CharField(max_length=20,label=‘密码‘)def register(request):
    if request.method==‘GET‘:
        form=UserInfo_form()
        return render(request,‘register.html‘,{‘form‘:form})
    form=UserInfo_form(request.POST)             #这是实例化一个forms类的一个实例化对象
    res={‘state‘:True,‘error‘:{}}
    name=request.POST.get(‘name‘)
    email=request.POST.get(‘email‘)
    pwd=request.POST.get(‘pwd‘)
    r_pwd=request.POST.get(‘r_pwd‘)
    if not form.is_valid():                  #is_valid,这就是对实例化对象进行校验。然后form.errors里面放的是错误信息,form.clean_data放的是没问题的信息
        res[‘error‘] = form.errors
        res[‘state‘] = False
    if pwd != r_pwd :
        res[‘error‘][‘r_pwd‘]=[‘密码不统一‘]
    if pwd==r_pwd and form.is_valid():
        User.objects.create_user(username=name,password=pwd,email=email)
    return JsonResponse(res)

  二、字段类型

  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,插件

# 单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,‘北京‘),),    #这是写死的情况    choices=Author.objects.all().value_list(‘pk‘,‘name‘)      
#     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,方法一

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator

class MyForm(Form):

    user = fields.ChoiceField(
        # choices=((1, ‘上海‘), (2, ‘北京‘),),
        initial=2,
        widget=widgets.Select
    )

    def __init__(self, *args, **kwargs):
        super(MyForm,self).__init__(*args, **kwargs)
        # self.fields[‘user‘].widget.choices = ((1, ‘上海‘), (2, ‘北京‘),)
        # 或
        self.fields[‘user‘].widget.choices = models.Classes.objects.all().value_list(‘id‘,‘caption‘)

  2,方法二

from django import forms
from django.forms import fields
from django.forms import widgets
from django.forms import models as form_model
from django.core.exceptions import ValidationError
from django.core.validators import RegexValidator

class FInfo(forms.Form):
    authors = form_model.ModelMultipleChoiceField(queryset=models.NNewType.objects.all())
    # authors = form_model.ModelChoiceField(queryset=models.NNewType.objects.all())

  三、渲染标签功能

  1,方式一

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
   <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
    <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
</head>
<body>
<h3>注册页面</h3>
<div class="container">
    <div class="row">
        <div class="col-md-6 col-lg-offset-3">

                <form action="" method="post">
                    {% csrf_token %}
                    <div>
                        <label for="">用户名</label>
                        {{ form.name }}
                    </div>
                    <div>
                        <label for="">密码</label>
                        {{ form.pwd }}
                    </div>
                    <div>
                        <label for="">确认密码</label>
                        {{ form.r_pwd }}
                    </div>
                    <div>
                        <label for=""> 邮箱</label>
                        {{ form.email }}
                    </div>

                    <input type="submit" class="btn btn-default pull-right">
                </form>
        </div>
    </div>
</div>

</body>
</html>

  2,方式二

<form action="" method="post">
                    {% csrf_token %}

                    {% for field in form %}
                        <div>
                            <label for="">{{ field.label }}</label>
                            {{ field }}
                        </div>
                    {% endfor %}
                    <input type="submit" class="btn btn-default pull-right">

</form>

  3,方式三

<form action="" method="post">
    {% csrf_token %}

    {{ form.as_p }}
    <input type="submit" class="btn btn-default pull-right">

</form>

  四、在前端页面局部刷新错误信息

  views.py

def register(request):
    if request.method==‘GET‘:
        form=UserInfo_form()
        return render(request,‘register.html‘,{‘form‘:form})
    form=UserInfo_form(request.POST)
    res={‘state‘:True,‘error‘:{}}
    name=request.POST.get(‘name‘)
    email=request.POST.get(‘email‘)
    pwd=request.POST.get(‘pwd‘)
    r_pwd=request.POST.get(‘r_pwd‘)
    if not form.is_valid():
        print(form)
        print(form.cleaned_data)
        print(form.errors)
        res[‘error‘] = form.errors
        res[‘state‘] = False
    if pwd != r_pwd :
        res[‘error‘][‘r_pwd‘]=[‘密码不统一‘]
    if pwd==r_pwd and form.is_valid():
        User.objects.create_user(username=name,password=pwd,email=email)
    return JsonResponse(res)

  register.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
    <link rel="stylesheet" href="/static/css/bootstrap.css">
    <script src="/static/jquery-3.3.1.js"></script>
    <script src="/static/js/bootstrap.js"></script>
    <style>
        .outer{
            margin-top: 200px;
        }
        .title{
            margin-bottom: 50px;
        }
    </style>
</head>
<body>
{% csrf_token %}
<div class="container outer">
    {% csrf_token %}
    <div class="row">
        <div class="col-md-6 col-md-offset-3">
            <div style="color: blue;font-size: 50px;text-align: center;font-family: 华文隶书" class="title">注册页面</div>
            {% for field in form %}
                <div class="form-group ">
                    <label for="id_{{ field.name }}">{{ field.label }}</label>
                    {{ field }}<span class="right_span" style="color: red"></span>
            </div>
            {% endfor %}
            <button class="register btn btn-info">注册</button>
        </div>
    </div>
</div>
    <script>
        $(‘input‘).addClass(‘form-control‘);
        $(‘#id_pwd‘).attr(‘type‘,‘password‘).attr(‘placeholder‘,‘只能有数字、字母、下划线组成的,长度5到20‘);
        $(‘#id_r_pwd‘).attr(‘type‘,‘password‘);
        $(‘#id_name‘).attr(‘placeholder‘,‘长度在4到10,不能全为数字‘);
        $(‘#id_email‘).attr(‘placeholder‘,‘例[email protected]‘);
        {#$(‘#id_pwd‘).attr(‘placeholder‘,‘只能有数字、字母、下划线组成的,长度5到20‘);#}
        $(‘.register‘).click(function () {
            $(‘span‘).html(‘‘);
            $.ajax({
                url:‘‘,
                type:‘post‘,
                data:{csrfmiddlewaretoken:$(‘[name="csrfmiddlewaretoken"]‘).val(),
                name:$(‘[name="name"]‘).val(),pwd:$(‘[name="pwd"]‘).val(),r_pwd:$(‘[name="r_pwd"]‘).val(),email:$(‘[name="email"]‘).val()},
                success:function (res) {
                    state=res[‘state‘];
                    if (state){
                        location.href=‘/login/‘
                    }else {
                         $.each(res[‘error‘],function(key,val) {
                             console.log(key,val)
                            $(‘#id_‘+key).next().html(val[0])       #每个字段错误的信息都会放在一个列表里
                        })
                    }
                }
            })
        })
    </script>
</body>

  五、钩子

  1,局部钩子

  views.py

class UserInfo_form(forms.Form):
    name=forms.CharField(max_length=10,label=‘姓名‘)
    email = forms.CharField(max_length=20, label=‘邮箱‘)
    pwd=forms.CharField(max_length=20,label=‘密码‘)
    r_pwd=forms.CharField(max_length=20,label=‘确认密码‘)  下面的局部钩子,必须在上面的对应的过滤条件通过之后,才会走到对应的钩子,局部钩子只能对对应的字段进行操作
    def clean_name(self):                 #clean_字段名,固定写法
        val=self.cleaned_data.get(‘name‘)
        if val.isdigit():           #如果不符合要求,要抛错误
            raise ValidationError(‘不能全为数字‘)
        elif len(val)<4 or len(val)>10:
            raise ValidationError(‘长度只能在4到10之间‘)
        elif User.objects.filter(username=val):
            raise ValidationError(‘用户名已存在‘)
        else:                #如果正确的话,必须返回取进来的值,因为在进行钩子验证时,会把值给清空的。
            return val
    def clean_email(self):
        val=self.cleaned_data.get(‘email‘)
        if re.search(r‘^\[email protected]\w+.com$‘,val):
            return val
        else:
            raise ValidationError(‘邮箱格式不对‘)
    def clean_pwd(self):
        val=self.cleaned_data.get(‘pwd‘)
        if re.search(‘^[0-9a-zA-Z_]{5,20}$‘,val):
            return val
        elif len(val)<5 or len(val)>20:
            raise ValidationError(‘长度只能在5到20之间‘)
        else:
            raise ValidationError(‘密码只能有数字、下划线、字母组成‘)
    def clean_r_pwd(self):
        val = self.cleaned_data.get(‘r_pwd‘)
        if re.search(‘^[0-9a-zA-Z_]{5,20}$‘, val):
            return val
        elif len(val) < 5 or len(val) > 20:
            raise ValidationError(‘长度只能在5到20之间‘)
        else:
            raise ValidationError(‘密码只能有数字、下划线、字母组成‘)

  2,全局钩子

def clean(self):      #在这里能拿到所有字段的值。
        pwd=self.cleaned_data.get("pwd")
        r_pwd=self.cleaned_data.get("r_pwd")

        if pwd==r_pwd:
            return self.cleaned_data
        else:
            raise ValidationError(‘两次密码不一致!‘)

  六、自定义规则

  方式一:

from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.validators import RegexValidator

class MyForm(Form):
    user = fields.CharField(
        validators=[RegexValidator(r‘^[0-9]+$‘, ‘请输入数字‘), RegexValidator(r‘^159[0-9]+$‘, ‘数字必须以159开头‘)],
    )

  方式二:

import re
from django.forms import Form
from django.forms import widgets
from django.forms import fields
from django.core.exceptions import ValidationError

# 自定义验证规则
def mobile_validate(value):
    mobile_re = re.compile(r‘^(13[0-9]|15[012356789]|17[678]|18[0-9]|14[57])[0-9]{8}$‘)
    if not mobile_re.match(value):
        raise ValidationError(‘手机号码格式错误‘)

class PublishForm(Form):

    title = fields.CharField(max_length=20,
                            min_length=5,
                            error_messages={‘required‘: ‘标题不能为空‘,
                                            ‘min_length‘: ‘标题最少为5个字符‘,
                                            ‘max_length‘: ‘标题最多为20个字符‘},
                            widget=widgets.TextInput(attrs={‘class‘: "form-control",
                                                          ‘placeholder‘: ‘标题5-20个字符‘}))

    # 使用自定义验证规则
    phone = fields.CharField(validators=[mobile_validate, ],
                            error_messages={‘required‘: ‘手机不能为空‘},
                            widget=widgets.TextInput(attrs={‘class‘: "form-control",
                                                          ‘placeholder‘: u‘手机号码‘}))

    email = fields.EmailField(required=False,
                            error_messages={‘required‘: u‘邮箱不能为空‘,‘invalid‘: u‘邮箱格式错误‘},
                            widget=widgets.TextInput(attrs={‘class‘: "form-control", ‘placeholder‘: u‘邮箱‘}))

  方式三:

from django import forms
    from django.forms import fields
    from django.forms import widgets
    from django.core.exceptions import ValidationError
    from django.core.validators import RegexValidator

    class FInfo(forms.Form):
        username = fields.CharField(max_length=5,
                                    validators=[RegexValidator(r‘^[0-9]+$‘, ‘Enter a valid extension.‘, ‘invalid‘)], )
        email = fields.EmailField()

        def clean_username(self):
            """
            Form中字段中定义的格式匹配完之后,执行此方法进行验证
            :return:
            """
            value = self.cleaned_data[‘username‘]
            if "666" in value:
                raise ValidationError(‘666已经被玩烂了...‘, ‘invalid‘)
            return value

  方式四:同时生成多个标签进行验证

from django.forms import Form
from django.forms import widgets
from django.forms import fields

from django.core.validators import RegexValidator

############## 自定义字段 ##############
class PhoneField(fields.MultiValueField):
    def __init__(self, *args, **kwargs):
        # Define one message for all fields.
        error_messages = {
            ‘incomplete‘: ‘Enter a country calling code and a phone number.‘,
        }
        # Or define a different message for each field.
        f = (
            fields.CharField(
                error_messages={‘incomplete‘: ‘Enter a country calling code.‘},
                validators=[
                    RegexValidator(r‘^[0-9]+$‘, ‘Enter a valid country calling code.‘),
                ],
            ),
            fields.CharField(
                error_messages={‘incomplete‘: ‘Enter a phone number.‘},
                validators=[RegexValidator(r‘^[0-9]+$‘, ‘Enter a valid phone number.‘)],
            ),
            fields.CharField(
                validators=[RegexValidator(r‘^[0-9]+$‘, ‘Enter a valid extension.‘)],
                required=False,
            ),
        )
        super(PhoneField, self).__init__(error_messages=error_messages, fields=f, require_all_fields=False, *args,
                                         **kwargs)

    def compress(self, data_list):
        """
        当用户验证都通过后,该值返回给用户
        :param data_list:
        :return:
        """
        return data_list

############## 自定义插件 ##############
class SplitPhoneWidget(widgets.MultiWidget):
    def __init__(self):
        ws = (
            widgets.TextInput(),
            widgets.TextInput(),
            widgets.TextInput(),
        )
        super(SplitPhoneWidget, self).__init__(ws)

    def decompress(self, value):
        """
        处理初始值,当初始值initial不是列表时,调用该方法
        :param value:
        :return:
        """
        if value:
            return value.split(‘,‘)
        return [None, None, None]

原文地址:https://www.cnblogs.com/12345huangchun/p/10262247.html

时间: 2024-11-05 17:29:38

Django之forms组件的相关文章

Django - 基于forms组件和Ajax实现注册登录 - FileField字段 - Media配置

一.基于forms组件的注册页面设计 点击头像==点击input 头像预览: 修改  获取用户选中的文件对象:获取文件对象的路径:修改img标签的src属性,让src=文件对象路径. register.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> <link

Django之forms组件使用

注册功能 1.渲染前端标签获取用户输入 >>> 渲染标签 2.获取用户输入传递到后端校验 >>> 校验数据 3.校验未通过展示错误信息 >>> 展示信息 校验数据(前后端都可以校验) 校验前端后端都可以做,但是前端可以不做,后端必须得做!!! django form组件 1.渲染标签 2.校验数据 3.展示信息 校验数据 第一步需要在views中写一个form类 from django import forms class MyForm(forms.F

django(forms组件、cookies与session)

一.forms组件 1.功能 - 渲染页面 - 校验数据 - 展示信息 需要先写一个类,该类类似于models中的表类 from django import forms class MyRegForm(forms.Form): # 用户名最少3位最多8位 username = forms.CharField(max_length=8,min_length=3) password = forms.CharField(max_length=8,min_length=3) # email字段必须填写符

CSIC_716_20200113【Django入门---forms组件、session和cookie、登录认证装饰器】

forms组件 forms组件的功能:1.渲染前端页面,不用在前端手写forms表单了,不过只会渲染用户输入(输入.选择.下拉.文件)的标签,不渲染按钮以及form表单标签,.2.后端能进行非常规范的数据合法性校验3.展示校验之后的合法性信息. 使用方法:1.定义一个自定义forms类 form组件的前端渲染方式 效果差不多 哈哈哈哈 顶 原文地址:https://www.cnblogs.com/csic716/p/12189236.html

Django forms组件【对form舒心l了】

目录 Django forms组件 bound and unbound form instance forms渲染有关 隐藏一个字段,不渲染它 form 校验 form类 ModelForm 利用ModelForm关键就在于model's field mapping to form's field ModelForm.save() 详解 class Meta !!!重写覆盖默认的modelField字段(即自定义一些modelform属性) form有关多选择Field的使用 form's fi

Django组件—forms组件

forms组件: 校验字段功能: 针对一个实例:注册用户. 模型:models.py class UserInfo(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) email=models.EmailField() tel=models.CharField(max_length=32) 模板:register.html <!DOCTYPE html> <html

12.Django组件-forms组件

forms组件 校验字段功能 针对一个实例:注册用户讲解. 模型:models.py class UserInfo(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) email=models.EmailField() tel=models.CharField(max_length=32) 模板: register.html: <!DOCTYPE html> <ht

Django组件——forms组件

一,forms组件: 校验字段功能针对一个实例:注册用户讲解.模型:models.py class UserInfo(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) email=models.EmailField() tel=models.CharField(max_length=32) 模板: register.html: <!DOCTYPE html> <h

Django组件:forms组件

针对"注册用户"示例: 一.校验字段功能 1.模型:models.py class UserInfo(models.Model): name=models.CharField(max_length=32) pwd=models.CharField(max_length=32) email=models.EmailField() tel=models.CharField(max_length=32) 2.模板:register.html: <!DOCTYPE html> &l