Django-form组件

一.Django的Form组件主要的几大功能:
1.生成HTML标签
2.验证用户数据(显示错误信息)
3.HTML Form提交保留上次提交数据
4.初始化页面显示内容
二.Form组件使用方法
1.创建类
2.创建字段(为了验证包含正则表达式)
3.当用户提交数据验证用户输入:

    obj = Form(request.POST,request.FILES)   #提交数据封装在request.POST,上传文件封装在request.FILES
    if obj.is_valid():                       #is_valid做验证判断是否合法
        obj.cleaned_data                     #正确在cleaned_data
    else:
        obj.errors                           #错误在errors

4.clean_字段:clean_开头的字段名单字段(对当前username字段验证)  
5.clean()  _post_clean() :对整体错误验证
三.初识Form组件
1.利用Form的功能使用给数据库添加编辑数据[生成HTML标签,验证用户数据(显示数据信息)]
(1)创建数据表:django_formapp1models.py

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)

(2)主页面:django_form emplatesusers.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>主页面</title>
</head>
<body>
    <a href="/add_user/">添加</a>
    <ul>
        {% for row in user_list %}
            <li>{{ row.id }}-{{ row.username }}-{{ row.email }} <a href="/edit_user-{{ row.id }}/">编辑</a></li>
        {% endfor %}
    </ul>
</body>
</html>

(3)添加数据页面:django_form emplatesadd_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插入提交页面</title>
</head>
<body>
    <form action="/add_user/" method="post" novalidate enctype="multipart/form-data">
        {% csrf_token %}
        <p>{{ obj.username.label }} {{ obj.username }}{{ obj.errors.username.0 }}</p> {#obj.username是生成的HTML,obj.errors拿到错误信息.0拿到第一个#}
        <p>{{ obj.email.label }} {{ obj.email }}{{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

(4)编辑数据页面:django_form emplatesedit_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>编辑提交页面</title>
</head>
<body>
    <form action="/edit_user-{{ nid }}/" method="POST" novalidate>    {#提交后id在GET上提交过去,其它的在POST里提交过去了#}
        {% csrf_token %}
        <p>{{ obj.username }}{{ obj.errors.username.0 }}</p>          {#obj.username是生成的HTML,obj.errors.username拿到错误信息.0拿到第一个#}
        <p>{{ obj.email }}{{ obj.errors.email.0 }}</p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

(5)URL配置:django_formdjango_formurls.py

from django.conf.urls import url
from django.contrib import admin
from app1 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^users/', views.users),                 #主页
    url(r'^add_user/', views.add_user),           #添加
    url(r'^edit_user-(d+)/', views.edit_user),   #编辑
]

(6)from配置:django_formapp1forms.py

from django import forms as dforms       #form组件
from django.forms import fields

class UserForm(dforms.Form):              #创建UserForm生成对话框类继承dforms.Form
    username = fields.CharField(          #创建用户名生成input框(username名字跟创建数据库字段名一样)
        max_length=18,                    #最大18位
        min_length=6,                     #最小6位
        required=True,                    #是否必填
        label='用户名:',
        error_messages={'required': '用户名不能为空', 'max_length': '', 'min_length': '', 'invalid': '名字格式不对'} #错误提示
    )


    email = fields.EmailField(            #创建email生成input框
        label='邮箱:',
        required=True,
        min_length=8,
        error_messages={'required': '邮箱不能为空', 'min_length': '太短了', 'invalid': '邮箱格式不对'}
    )

(6)函数配置:django_formapp1views.py

from django.shortcuts import render
from django.shortcuts import redirect
from app1 import models

#主页
def users(request):
    user_list = models.UserInfo.objects.all()
    return render(request,'users.html',{'user_list':user_list})

#生成输入对话框和添加数据加验证
from app1.forms import UserForm
def add_user(request):
    if request.method == 'GET':                                  #以GET请求自动生成HTML
        obj = UserForm()                                         #创建obj对象(当前obj没有内容只是input对话框)
        return render(request,'add_user.html',{'obj':obj})       #传到前端
    else:
        obj = UserForm(request.POST,request.FILES)               #UserForm是一个一个的对应关系,对应关系里对应的一大堆正则表达式,验证用户发来的数据,用户发来的数据全在request.POST,用户提交的文件在request.FILES
        if obj.is_valid():                                       #用户发来的数据是否全部验证成功
            models.UserInfo.objects.create(**obj.cleaned_data)   #把提交来的数据添加到数据库(cleaned_data把数据都获取好)
            return redirect('/users/')                           #
        else:
            return render(request, 'add_user.html', {'obj': obj}) #返回错误信息给前端

#编辑数据
def edit_user(request,nid):
    if request.method == "GET":                                               #以GET请求自动生成HTML
        data = models.UserInfo.objects.filter(id=nid).first()                 #获取当前要编辑的对象
        obj = UserForm({'username':data.username,'email':data.email})         #UserForm是保留要编辑的username和email字段给前端显示
        return render(request,'edit_user.html',{'obj':obj,'nid':nid})
    else:                                                                     #接收修改的数据
        obj = UserForm(request.POST)                                          #UserForm是一个一个的对应关系,对应关系里对应的一大堆正则表达式,验证用户发来的数据,用户发来的数据全在request.POST
        if obj.is_valid():                                                    #用户发来的数据是否全部验证成功
            models.UserInfo.objects.filter(id=nid).update(**obj.cleaned_data) #更新要修改的数据库数据
            return redirect('/users/')
        else:
            return render(request,'edit_user.html',{'obj':obj,'nid':nid})

访问:http://127.0.0.1:8080/users/点击添加xixixi和xixi18@qq.com:        

+----+----------+-----------------+
| id | username | email           |
+----+----------+-----------------+
|  1 | xixixi   | xixi18@qq.com   |
+----+----------+-----------------+

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

2.Django常用的内置字段(用于对用户请求数据的验证),用于保存正则表达式
(1)URL:django_formdjango_formurls.py

from django.conf.urls import url
from django.contrib import admin
from app1 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^add_user/', views.add_user),           #添加
]

(2)forms配置:django_formapp1forms.py

from django import forms as dforms
from django.forms import fields

#创建UserForm生成对话框类继承dforms.Form)
class UserForm(dforms.Form):
    #CharField:字符串,一般都在创建时写入max_length参数
    username = fields.CharField(     #创建用户名生成input框
        max_length=18,               #最大18位
        min_length=6,                #最小6位
        required=True,               #是否必填
        label='用户名:',           #生成label标签或显示内容
        # initial='请输入用户名',     #设置默认值
        # show_hidden_initial=False,  #是否在当前插件后面再加一个隐藏的且具有默认值的插件(可用于检验两次输入是否一直)
        # disabled=True,              #不可编辑
        error_messages={'required': '用户名不能为空', 'max_length': '', 'min_length': '', 'invalid': '名字格式不对'}  # 错误提示
    )

    #EmailField:字符串,会检查是否是合法的email地址
    email = fields.EmailField(
        label='邮箱:',
        required=True,
        min_length=8,
        error_messages={'required': '邮箱不能为空', 'min_length': '太短了', 'invalid': '邮箱格式不对'}
    )

    #IntegerField:[-2147483648,2147483647]的取值范围对Django所支持的数据库都是安全的
    age = fields.IntegerField(
        label='年龄:',
        max_value=99,                         #最大值
        min_value=18,                         #最小值
        error_messages={
            'max_value': '太大了'
        }
    )

    #FileField提交文件选择框
    img = fields.FileField()

    #下拉框:TypedChoiceField
    city = fields.TypedChoiceField(
        coerce=lambda x: int(x),                           #把传的字符串转换成整型
        choices=[(1, '上海',), (2, '北京'), (3, '香港'), ],  #数据源
        initial=2                                          #默认值北京
    )

    #多选框:MultipleChoiceField
    bobby = fields.MultipleChoiceField(                   #多选框
        choices=[(1, '吃饭'), (2, '睡觉'), (3, '打豆豆')],   #数据源
        initial=[1, 3]                                     #默认值吃饭,打豆豆
    )

(4)函数:django_formapp1views.py

from django.shortcuts import render

#生成输入对话框和添加数据加验证
from app1.forms import UserForm
def add_user(request):
    if request.method == 'GET':                                  #以GET请求自动生成HTML
        obj = UserForm()                                         #创建obj对象(当前obj没有内容只是input对话框)
        return render(request,'add_user.html',{'obj':obj})       #传到前端
    else:
        obj = UserForm(request.POST,request.FILES)               #UserForm是一个一个的对应关系,对应关系里对应的一大堆正则表达式,验证用户发来的数据,用户发来的数据全在request.POST,用户提交的文件在request.FILES
        obj.is_valid()                                           #用户发来的数据是否全部验证成功
        print(obj.cleaned_data)                                  #{'age': 18, 'bobby': ['1', '3'], 'city': 2, 'email': '113194773@qq.com', 'img': <InMemoryUploadedFile: 笔记.txt (text/plain)>, 'username': '西西西西西西西西'}

return render(request, 'add_user.html', {'obj': obj})

(5)页面:django_form emplatesadd_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插入提交页面</title>
</head>
<body>
    <form action="/add_user/" method="post" novalidate enctype="multipart/form-data">
        {% csrf_token %}
        <p>{{ obj.username.label }} {{ obj.username }}{{ obj.errors.username.0 }}</p>  {#obj.username是生成的HTML,obj.errors拿到错误信息.0拿到第一个#}
        <p>{{ obj.age.label }} {{ obj.age }}{{ obj.errors.age.0 }}</p>                  {#age#}
        <p>{{ obj.email.label }} {{ obj.email }}{{ obj.errors.email.0 }}</p>            {#email#}
        <p>{{ obj.img.label }}{{ obj.img }}</p>                                         {#文件上传#}
        <p>{{ obj.city.label }}{{ obj.city }}</p>                                       {#下拉框#}
        <p>{{ obj.bobby.label }}{{ obj.bobby }}</p>                                     {#多选框#}
        <input type="submit" value="提交" />
    </form>
</body>
</html>

访问:http://127.0.0.1:8080/add_user显示

3.Django常用选择插件,用于生成HTML标签
(1)forms配置:django_formapp1forms.py

from django.conf.urls import url
from django.contrib import admin
from app1 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^add_user/', views.add_user),           #添加
]

(2)forms配置:django_formapp1forms.py

from django import forms as dforms
from django.forms import fields
from django.forms import widgets

class UserForm(dforms.Form):                                   #创建UserForm生成对话框类继承dforms.Form)
    #单radio(值为字符串)方式一:
    radio = fields.CharField(
        widget=widgets.Select(choices=[(1, '吃饭'), (2, '睡觉'), (3, '打豆豆')])     #widget定制生成的单选框对话框
    )

    #单radio(值为字符串)方式二:
    radio2 = fields.ChoiceField(
        choices=[(1, '吃饭'), (2, '睡觉'), (3, '打豆豆')]
    )

    #单select(值为字符串)方式一:
    select = fields.CharField(
        initial=2,
        widget=widgets.Select(choices=((1,'上海'),(2,'北京'),))                       #widget定制生成的Select对话框
    )

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

    #单checkbox
    check_box= fields.CharField(                               #单选框
        widget=widgets.CheckboxInput()
    )

    #多选checkbox2
    check_box2 = fields.MultipleChoiceField(                  #多选框方式1
        initial=[2, ],                                        #默认选北京
        choices=((1, '上海'), (2, '北京'),),                 #数据源
        widget=widgets.CheckboxSelectMultiple
    )

    #多选checkbox3值为列表
    check_box3 = fields.ChoiceField(                          #多选框方式2,值为列表
        choices=((1, '上海'), (2, '北京'), (3, '北京1'),),   #数据源
        initial=2,                                            #默认选北京
        widget=widgets.RadioSelect
    )

(3)函数:django_formapp1views.py

from django.shortcuts import render

#生成输入对话框和添加数据加验证
from app1.forms import UserForm
def add_user(request):
    if request.method == 'GET':                                  #以GET请求自动生成HTML
        obj = UserForm()                                         #创建obj对象(当前obj没有内容只是input对话框)
        return render(request,'add_user.html',{'obj':obj})       #传到前端
    else:
        obj = UserForm(request.POST,request.FILES)               #UserForm是一个一个的对应关系,对应关系里对应的一大堆正则表达式,验证用户发来的数据,用户发来的数据全在request.POST,用户提交的文件在request.FILES
        obj.is_valid()                                           #用户发来的数据是否全部验证成功
        print(obj.cleaned_data)                                  #{'check_box': 'False', 'check_box2': ['2'], 'select2': '2', 'check_box3': '2', 'radio2': '1', 'select': '2', 'radio': '1'}
        return render(request, 'add_user.html', {'obj': obj})

(4)页面:django_form emplatesadd_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>插入提交页面</title>
</head>
<body>
    <form action="/add_user/" method="post" novalidate enctype="multipart/form-data">
        {% csrf_token %}
        <p>{{ obj.radio.label }}{{ obj.radio }}</p>
        <p>{{ obj.radio2.label }}{{ obj.radio2 }}</p>
        <p>{{ obj.select.label }}{{ obj.select }}</p>
        <p>{{ obj.select2.label }}{{ obj.select2 }}</p>
        <p>{{ obj.check_box.label }}{{ obj.check_box }}</p>
        <p>{{ obj.check_box2.label }}{{ obj.check_box2 }}</p>
        <p>{{ obj.check_box3.label }}{{ obj.check_box3 }}</p>
        <input type="submit" value="提交" />
    </form>
</body>
</html>

访问:http://127.0.0.1:8080/add_user显示

五.自定义构造方法对于数据源进行实时更新
在使用选择标签时,需要注意choices的选项可以从数据库中获取,但是由于是静态字段 获取的值无法实时更新,那么需要自定义构造方法从而达到此目的。
1.对于下拉框或者数据源进行实时更新可以通过自定制的init实现
(1)数据库:django_formapp1models.py

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)

(2)django_formdjango_formurls.py

from django.conf.urls import url
from django.contrib import admin
from app1 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^add_user/', views.add_user),           #添加
]

(3)主页:django_form emplatesadd_user.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <h1>超市</h1>
    <p>价格:{{ obj.price }}</p>
    <p>水果:{{ obj.user_id }}</p>
</body>
</html>

(4)函数:django_formapp1views.py

from django.shortcuts import render
from django import forms
from django.forms import fields
from django.forms import widgets
from app1 import models

class user(forms.Form):
    price = fields.IntegerField()                                                 #price价格:静态字段
    user_id = fields.IntegerField(                                                #user_id多选框
        #widget=widgets.Select(choices=[(0,'香蕉'),(1,'苹果'),(2,'草莓'),])
        widget=widgets.Select()                                                   #
    )

    def __init__(self,*args,**kwargs):                                                                    #第二步:只要创建user对象后__init__初始化执行一遍
        super(user,self).__init__(*args,**kwargs)                                                         #第三步:拷贝所有的静态字段,赋值给self.fields
        self.fields['user_id'].widget.choices = models.UserInfo.objects.values_list('id', 'username')     #第四步:取到self.fields,里面有user_id,里面有插件widget,在里面有choices(数据库取出新的数据)

def add_user(request):
    obj = user()                                                                                           #第一步:当页面刷新创建user对象
    return render(request,'add_user.html',{'obj':obj})

访问:http://127.0.0.1:8080/add_user/



六.validators自定义验证规则
1.Form组件扩展:
1)简单扩展:利用Form组件自带的正则扩展获取错误信息
自定制方式一:

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(                                                                                      #CharField是字符串
        error_messages={'invalid': '...'},
        validators=[RegexValidator(r'^[0-9]+$', '请输入数字'), RegexValidator(r'^159[0-9]+$', '数字必须以159开头')],  #自定义两个正则表达式验证(RegexValidator传俩参数放到validators里,第一个参数是正则表达式,第二个参数是错误提示)
    )

自定义方式二:

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.RegexField(r'^[0-9]+$',error_messages={'invalid': '...'})  #只能写一个正则表达式验证

2)基于源码流程
a.clean开头的字段名单字段(对当前username字段验证) 
(1)数据库:django_formapp1models.py

from django.db import models

class UserInfo(models.Model):
    username = models.CharField(max_length=32)
    email = models.EmailField(max_length=32)

(2)django_formdjango_formurls.py

from django.conf.urls import url
from django.contrib import admin
from app1 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^ajax/', views.ajax),           #验证主页
]

(3)函数:django_formapp1views.py

from django.shortcuts import render
from django import forms
from django.forms import fields
from django.shortcuts import HttpResponse
from django.forms import widgets
from app1 import models
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError  # ValidationError返回错误信息模块

class AjaxForm(forms.Form):
    username = fields.CharField()                              #第一步:第一个字段进来先验证username正则表达式
    user_id = fields.IntegerField(                             #第三步:第二个字段进来验证user_id正则表达式
        widget=widgets.Select(choices=[(0, '东东'), (1, '南南'), (2, '北北'), ])
    )

    #自定义方法clean_字段名
    def clean_username(self):                                   #第二步:如果正则表达式通过执行自定义clean_username方法
        v = self.cleaned_data['username']                       #必须有返回值,返回值self.cleaned_data['username']赋值给v
        if models.UserInfo.objects.filter(username=v).count():  #去数据库比对(某一个字段错了,整体就错了,自己的详细错误信息要有)
            raise ValidationError('用户名已存在')              #如果出错:raise ValidationError('用户名已存在')
        return v                                                #如果没出错把正确的值返回给用户(v=self.cleaned_data)

    def clean_user_id(self):                                    #第四步:如果正则表达式通过执行自定义clean_user_id方法
        return self.cleaned_data['user_id']

def ajax(request):
    if request.method == 'GET':
        obj = AjaxForm()
        return render(request,'ajax.html',{'obj':obj})
    else:
        ret = {'status': '错误', 'message': None}  # 定义默认信息
        import json
        obj = AjaxForm(request.POST)  # 准备做验证
        if obj.is_valid():  # is_valid做验证判断是否合法
            ret['status'] = '西'  # 验证成功
            return HttpResponse(json.dumps(ret))  # 返回json数据到前端
        else:

            ret['message'] = obj.errors  # 失败把错误信息返回给前端
            # 错误信息显示在页面上
            return HttpResponse(json.dumps(ret))

(4)主页面:django_form emplatesajax.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" method="POST" action="/ajax/">
        {% csrf_token %}
        {{ obj.as_p }}
        <input type="button" value="Ajax提交" id="btn" />
    </form>
    <script src="/static/jquery-3.1.1.js"></script>
    <script>
        $(function () {
            $('#btn').click(function () {
                $.ajax({
                    url: '/ajax/',
                    type: 'POST',
                    data: $('#fm').serialize(),
                    dataType: 'JSON',
                    success:function (arg) {
                        if (arg.status == '西'){                             //arg包括后台处理的状态和错误信息
                            window.location.href = "http://www.baidu.com"
                        }
                        console.log(arg);
                    }
                })
            })
        })
    </script>
</body>
</html>

访问如果数据库有草莓不跳转:http://127.0.0.1:8080/ajax/

b.clean方法对整体错误验证
(1)django_formdjango_formurls.py

from django.conf.urls import url
from django.contrib import admin
from app1 import views
urlpatterns = [
    url(r'^admin/', admin.site.urls),
    url(r'^ajax/', views.ajax),           #验证主页
]

(2)函数:django_formapp1views.py

from django.shortcuts import render
from django.shortcuts import HttpResponse
from django import forms
from django.forms import fields
from django.forms import widgets
from django.core.exceptions import NON_FIELD_ERRORS, ValidationError  # ValidationError返回错误信息模块

class AjaxForm(forms.Form):
    username = fields.CharField()
    user_id = fields.IntegerField(
        widget=widgets.Select(choices=[(0, '东东'), (1, '南南'), (2, '北北'), ])
    )

    def clean(self):
        value_dict = self.cleaned_data                          #把用户名密码获取到做验证
        v1 = value_dict.get('username')                         #做验证
        v2 = value_dict.get('user_id')                          #做验证
        if v1 == 'root' and v2 == 1:                            #如果v1等于root,v2等于1(模拟从数据库获取)
            raise ValidationError('整体错误信息')
        return self.cleaned_data                                #

def ajax(request):
    if request.method == 'GET':
        obj = AjaxForm()
        return render(request,'ajax.html',{'obj':obj})
    else:
        ret = {'status':'错误','message':None}                      #定义默认信息
        import json
        obj = AjaxForm(request.POST)                                 #准备做验证
        if obj.is_valid():                                           #is_valid做验证判断是否合法
            ret['status'] = '西'                                     #验证成功
            return HttpResponse(json.dumps(ret))                     #返回json数据到前端
        else:

            ret['message'] = obj.errors                              #失败把错误信息返回给前端
            #错误信息显示在页面上
            return HttpResponse(json.dumps(ret))

(3)主页面:django_form emplatesajax.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
    <form id="fm" method="POST" action="/ajax/">
        {% csrf_token %}
        {{ obj.as_p }}
        <input type="button" value="Ajax提交" id="btn" />
    </form>
    <script src="/static/jquery-3.1.1.js"></script>
    <script>
        $(function () {
            $('#btn').click(function () {
                $.ajax({
                    url: '/ajax/',
                    type: 'POST',
                    data: $('#fm').serialize(),
                    dataType: 'JSON',
                    success:function (arg) {
                        if (arg.status == '西'){                             //arg包括后台处理的状态和错误信息
                            window.location.href = "http://www.baidu.com"
                        }
                        console.log(arg);
                    }
                })
            })
        })
    </script>
</body>
</html>

访问输入用户名root,id为1的南南无法跳转:http://127.0.0.1:8080/ajax/

原文地址:https://www.cnblogs.com/xixi18/p/10298455.html