Django之Form组件

一、Form组件介绍

Form组件可以做的几件事情:

  1、用户请求数据验证

  2、自动生成错误信息    

  3、打包用户提交的正确信息

  4、如果其中有一个错误了,其他的正确,保留上次输入的内容

  5、自动创建input标签并可以设置样式

Form组件的基本用法

 1  2     字段
 3     is_valid()
 4     cleaned_data
 5     errors
 6     字段参数:
 7         max_length
 8         min_length
 9         validators = [RegexValidators("xxx")]
10         
11     钩子函数
12         clean_字段名
13         注意:
14             必须有返回值
15             只能拿自己当前字段值
16             raise ValidationError("xxx")
17     下拉框数据源时时更新
18         1、重写init方法
19             先执行父类构造方法
20             self.fields["xx"].choices = xxxxx
21         2、ModelChoiceField

二、Form组件的使用

1、创建规则

1 class Foo(Form): #必须继承
2     username = xxx
3     password = xxx
4     email = xxx
5 注意这里的字段必须和input的name字段一致

2、数据和规则进行匹配

先导入需要用到的模块

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

views.py

 1 from django.shortcuts import render,redirect
 2 from app01 import models
 3 # Create your views here.
 4 from django.forms import Form
 5 from django.forms import fields
 6 from django.forms import widgets
 7 # 1、创建规则
 8 class TeacherForm(Form):  #必须继承Form
 9     # 创建字段,本质上是正则表达式
10     username = fields.CharField(
11         required=True,     #必填字段
12         error_messages={"required":"用户名不能为空!!"},  #显示中文错误提示
13         widget=widgets.TextInput(attrs={"placeholder":"用户名","class":"form-control"})  #自动生成input框
14        )
15     password = fields.CharField(required=True, error_messages={'required': '密码不能为空'},
16                                 widget=widgets.TextInput(attrs={'placeholder': '密码', 'class': 'form-control'}))  # 不能为空
17     email = fields.EmailField(
18         required=True,
19         error_messages={"required":"邮箱不能为空!!","invalid":"无效的邮箱"},
20         widget=widgets.EmailInput(attrs={"placeholder": "邮箱", "class": "form-control"})  # 自动生成input框
21     ) #不能为空且邮箱格式要一致
22 
23 # 2、使用规则:将数据和规则进行匹配
24 def teacherindex(request):
25     teacher_obj = models.UserInfo.objects.all()
26     # print(teacher_obj)
27     return render(request,"teacherindex.html",{"teacher_obj":teacher_obj})
28 def add(request):
29     if request.method=="GET":
30         form = TeacherForm()  #只是让显示一个input框
31         return render(request,"add.html",{"form":form })
32     else:
33         form = TeacherForm(data=request.POST)
34         # print(form)  #<QuerySet [<UserInfo: UserInfo object>, <UserInfo: UserInfo object>, <UserInfo: UserInfo object>]>
35         if form.is_valid():# 开始验证
36             # print('执行成功',form.cleaned_data)          # 所有匹配成功,字典
37             # {'username': 'asd', 'password': 'sdf', 'email': 'sadf@live.com','ut_id':1}
38             form.cleaned_data['ut_id'] = 1  #要分的清是班主任还是讲师
39             models.UserInfo.objects.all().create(**form.cleaned_data)
40             return redirect("/teacherindex/")
41         else:
42             # print("=====?",form.errors,type(form.errors))#返回失败的结果
43             # print(form.errors["username"][0])   #拿到返回失败的结果,渲染到页面
44             return render(request,"add.html",{"form":form})

html

{% block right %}
    <h1>添加老师信息</h1>
    <hr>
    <form method="post" novalidate>
        {% csrf_token %}
        <p>姓名:{{ form.username }}</p>{{ form.errors.username.0 }}
        <p>密码:{{ form.password }}</p>{{ form.errors.password.0 }}
        <p>邮箱:{{ form.email }}</p>{{ form.errors.email.0 }}
        <p><input type="submit" value="提交"></p>
    </form>
{% endblock %}

需要注意的几个点:

1.如果访问视图的是一个GET 请求,它将创建一个空的表单实例并将它放置到要渲染的模板的上下文中。这是我们在第一个访问该URL 时会发生的情况。

2.如果表单的提交使用POST 请求,那么视图将再次创建一个表单实例并使用请求中的数据填充它:form = NameForm(request.POST)。这叫做”绑定数据至表单“(它现在是一个绑定的表单)。

3.我们调用表单的is_valid()方法;如果它不为True,我们将带着这个表单返回到模板。这时表单不再为空(未绑定),所以HTML 表单将用之前提交的数据填充,然后可以根据要求编辑并改正它。

如果is_valid()True,我们将能够在cleaned_data 属性中找到所有合法的表单数据。在发送HTTP 重定向给浏览器告诉它下一步的去向之前,我们可以用这个数据来更新数据库或者做其它处理。

4.

form = TeacherForm()  #没有参数,只是一个input框

form = TeacherForm(data=request.POST) # 数据和规则放置一起 (添加的时候用)

form = TeacherForm(initial={'username':obj.username,'password':obj.password,'email':obj.email})   # 显示input,并且将数据库中的默认值填写到input框中 (编辑的时候用)

Widgets

每个表单字段都有一个对应的Widget 类,它对应一个HTML 表单Widget,例如<input type="text">

在大部分情况下,字段都具有一个合理的默认Widget。例如,默认情况下,CharField 具有一个TextInput Widget,它在HTML 中生成一个<input type="text">

局部钩子和全局钩子

局部钩子

 1 from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
 2 def clean_name(self):
 3 
 4         val=self.cleaned_data.get("name")
 5 
 6         ret=UserInfo.objects.filter(name=val)
 7 
 8         if not ret:
 9             return val
10         else:
11             raise ValidationError("该用户已注册!")
12 
13     def clean_tel(self):
14 
15         val=self.cleaned_data.get("tel")
16 
17         if len(val)==11:
18 
19             return val
20         else:
21             raise  ValidationError("手机号格式错误")

全局钩子

 1 def clean(self):
 2         pwd=self.cleaned_data.get('pwd')
 3         r_pwd=self.cleaned_data.get('r_pwd')
 4 
 5         if pwd and r_pwd:
 6             if pwd==r_pwd:
 7                 return self.cleaned_data
 8             else:
 9                 raise ValidationError('两次密码不一致')
10         else:
11 
12             return self.cleaned_data

字段的数据

不管表单提交的是什么数据,一旦通过调用is_valid() 成功验证(is_valid() 返回True),验证后的表单数据将位于form.cleaned_data 字典中。这些数据已经为你转换好为Python 的类型。

注:此时,你依然可以从request.POST 中直接访问到未验证的数据,但是访问验证后的数据更好一些。

在上面的联系表单示例中,is_married将是一个布尔值。类似地,IntegerField 和FloatField 字段分别将值转换为Python 的int 和float

第二种方式:

创建字段,定义规则

 1 class TeacherForm(Form):  #必须继承Form
 2     # 创建字段,本质上是正则表达式
 3     username = fields.CharField(
 4         required=True,     #必填字段
 5         error_messages={"required":"用户名不能为空!!"},  #显示中文错误提示
 6         widget=widgets.TextInput(attrs={"placeholder":"用户名","class":"form-control"}),  #自动生成input框
 7         label="姓名",
 8         label_suffix=":"
 9        )
10     password = fields.CharField(required=True, error_messages={'required': '密码不能为空'},
11                                 widget=widgets.PasswordInput(attrs={'placeholder': '密码', 'class': 'form-control'}),
12                                 label="密码",
13                                 label_suffix=":"
14       )  # 不能为空
15 
16     email = fields.EmailField(
17         required=True,
18         error_messages={"required":"邮箱不能为空!!","invalid":"无效的邮箱"},
19         widget=widgets.EmailInput(attrs={"placeholder": "邮箱", "class": "form-control"}),  # 自动生成input框
20         label = "邮箱",
21         label_suffix = ":"
22     ) #不能为空且邮箱格式要一致

页面上渲染

附上forms组件测试代码

my_forms

 1 from django import forms
 2 
 3 from django.forms import widgets
 4 from app01.models import UserInfo
 5 
 6 from django.core.exceptions import NON_FIELD_ERRORS, ValidationError
 7 
 8 class UserForm(forms.Form):
 9     name=forms.CharField(min_length=4,label="用户名",error_messages={"required":"该字段不能为空"},
10                          widget=widgets.TextInput(attrs={"class":"form-control"})
11                          )
12     pwd=forms.CharField(min_length=4,label="密码",
13                         widget=widgets.PasswordInput(attrs={"class":"form-control"})
14                         )
15     r_pwd=forms.CharField(min_length=4,label="确认密码",error_messages={"required":"该字段不能为空"},widget=widgets.TextInput(attrs={"class":"form-control"}))
16     email=forms.EmailField(label="邮箱",error_messages={"required":"该字段不能为空","invalid":"格式错误"},widget=widgets.TextInput(attrs={"class":"form-control"}))
17     tel=forms.CharField(label="手机号",widget=widgets.TextInput(attrs={"class":"form-control"}))
18 
19 
20     def clean_name(self):
21 
22         val=self.cleaned_data.get("name")
23 
24         ret=UserInfo.objects.filter(name=val)
25 
26         if not ret:
27             return val
28         else:
29             raise ValidationError("该用户已注册!")
30 
31     def clean_tel(self):
32 
33         val=self.cleaned_data.get("tel")
34 
35         if len(val)==11:
36 
37             return val
38         else:
39             raise  ValidationError("手机号格式错误")
40 
41     def clean(self):
42         pwd=self.cleaned_data.get('pwd')
43         r_pwd=self.cleaned_data.get('r_pwd')
44 
45         if pwd and r_pwd:
46             if pwd==r_pwd:
47                 return self.cleaned_data
48             else:
49                 raise ValidationError('两次密码不一致')
50         else:
51 
52             return self.cleaned_data
53 
54 myforms

视图函数

 1 from django.shortcuts import render,HttpResponse
 2 
 3 # Create your views here.
 4 
 5 
 6 
 7 from app01.myforms import *
 8 
 9 
10 def reg(request):
11 
12     if request.method=="POST":
13 
14         print(request.POST)
15 
16         #form=UserForm({"name":"yu","email":"123@qq.com","xxxx":"alex"})
17 
18 
19         form=UserForm(request.POST) # form表单的name属性值应该与forms组件字段名称一致
20 
21         print(form.is_valid()) # 返回布尔值
22 
23         if form.is_valid():
24             print(form.cleaned_data)  # {"name":"yuan","email":"123@qq.com"}
25         else:
26             print(form.cleaned_data)  # {"email":"123@qq.com"}
27             # print(form.errors)        # {"name":[".........."]}
28             # print(type(form.errors))  # ErrorDict
29             # print(form.errors.get("name"))
30             # print(type(form.errors.get("name")))    # ErrorList
31             # print(form.errors.get("name")[0])
32 
33 
34             #   全局钩子错误
35             #print("error",form.errors.get("__all__")[0])
36             errors=form.errors.get("__all__")
37 
38 
39             return render(request,"reg.html",locals())
40 
41         '''
42 
43         form.is_valid()   :返回布尔值
44         form.cleaned_data :{"name":"yuan","email":"123@qq.com"}
45         form.errors       :{"name":[".........."]}
46 
47         '''
48 
49 
50     form=UserForm()
51 
52     return render(request,"reg.html",locals())
53 
54 视图函数

模板文件

 1 <!DOCTYPE html>
 2 <html lang="en">
 3 <head>
 4     <meta charset="UTF-8">
 5     <title>Title</title>
 6     <style>
 7         .error{
 8             color: red;
 9         }
10     </style>
11     <!-- 最新版本的 Bootstrap 核心 CSS 文件 -->
12     <link rel="stylesheet" href="https://cdn.bootcss.com/bootstrap/3.3.7/css/bootstrap.min.css"
13     integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous">
14 </head>
15 <body>
16 
17 <div class="container">
18 
19     <div class="row">
20         <div class="col-md-6 col-lg-offset-3">
21 
22             {#<h3>简单form</h3>#}
23             {##}
24             {##}
25             {#<form action="" method="post" novalidate>#}
26             {#    {% csrf_token %}#}
27             {#    <p>用户名<input type="text" name="name"></p>#}
28             {#    <p>密码 <input type="text" name="pwd"></p>#}
29             {#    <p>确认密码 <input type="text" name="r_pwd"></p>#}
30             {#    <p>邮箱  <input type="text" name="email"></p>#}
31             {#    <p>手机号 <input type="text" name="tel"></p>#}
32             {#    <input type="submit">#}
33             {##}
34             {#</form>#}
35 
36             <hr>
37             <h3>forms组件渲染方式1</h3>
38             <form action="" method="post" novalidate>
39 
40                 {% csrf_token %}
41                 <p>{{ form.name.label }}
42                     {{ form.name }} <span class="pull-right error">{{ form.name.errors.0 }}</span>
43                 </p>
44                 <p>{{ form.pwd.label }}
45                     {{ form.pwd }} <span class="pull-right error">{{ form.pwd.errors.0 }}</span>
46                 </p>
47                 <p>确认密码
48                     {{ form.r_pwd }} <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span><span class="pull-right error">{{ errors.0 }}</span>
49                 </p>
50                 <p>邮箱 {{ form.email }} <span class="pull-right error">{{ form.email.errors.0 }}</span></p>
51                 <p>手机号 {{ form.tel }} <span class="pull-right error">{{ form.tel.errors.0 }}</span></p>
52                 <input type="submit">
53 
54             </form>
55 
56             {#<h3>forms组件渲染方式2</h3>#}
57             {##}
58             {#<form action="" method="post" novalidate>#}
59             {#     {% csrf_token %}#}
60             {##}
61             {#    {% for field in form %}#}
62             {##}
63             {#        <div>#}
64             {#            <label for="">{{ field.label }}</label>#}
65             {#            {{ field }}#}
66             {#        </div>#}
67             {##}
68             {#    {% endfor %}#}
69             {##}
70             {#     <input type="submit">#}
71             {#</form>#}
72             {##}
73             {#<h3>forms组件渲染方式3</h3>#}
74             {##}
75             {#<form action="" method="post">#}
76             {#     {% csrf_token %}#}
77             {##}
78             {#     {{ form.as_p }}#}
79             {##}
80             {#     <input type="submit">#}
81             {#</form>#}
82 
83 
84         </div>
85     </div>
86 </div>
87 
88 </body>
89 </html>
90 
91 模版文件
原文地址:https://www.cnblogs.com/Roc-Atlantis/p/9664312.html