【一】Django的表单系统
【1】使用表单
(1)原始表单
- 我们之前在HTML页面中利用form表单向后端提交数据时
- 都会写一些获取用户输入的标签并且用form标签把它们包起来。
- 与此同时我们在好多场景下都需要对用户的输入做校验
- 比如校验用户是否输入
- 输入的长度和格式等正不正确。
- 如果用户输入的内容有错误就需要在页面上相应的位置显示对应的错误信息.。
<form action="/your-name/" method="post">
<label for="your_name">Your name: </label>
<input id="your_name" type="text" name="your_name" value="{{ current_name }}">
<input type="submit" value="OK">
</form>
<form action="/your-name/" method="post">
这一行定义了我们的发送目的地/your-name/
和HTTP方法POST
。- form元素内部还定义了一个说明标签
<label>
和一个发送按钮submit
,以及最关键的接收用户输入的<input>
元素。 - 具体的更多HTML语言相关内容,请自行学习。
Django form组件就实现了上面所述的功能。
(2)Django的表单系统
-
Django的Form表单类与Django模型描述对象的逻辑结构、行为以及它呈现给我们内容的形式的方式大致相同。
-
那为什么有了模型,还要自己创建表单类呢?
-
原因之一是模型中有一些字段你不需要用户从前端输入数据,或者需要用户额外输入一些非模型字段的数据。
-
Form表单精确控制了这些行为,相当于你在用户HTML表单输入框和Django模型之间的中间件。
【2】form组件的主要功能
- 生成页面可用的HTML标签
- 对用户提交的数据进行校验
- 保留上次输入内容
【二】需求介绍
- 写一个注册功能
- 获取用户名和密码,利用form表单提交数据
- 在后端判断用户名和密码是否符合一定的条件
- 用户名中不能包含啦啦啦
- 密码不能少于三位
- 如果符合条件需要你将提示信息展示到前端页面
【二】form表单实现
【1】点击提交按钮返回比对信息
(1)前端页面
<form action="" method="post">
<p>username:
<input type="text" class="form-control" name="username">
<span style="color: red">{{ back_dict.username }}</span>
</p>
<p>password:
<input type="password" class="form-control" name="password">
<span style="color: red">{{ back_dict.password }}</span>
</p>
<input type="submit" class="btn btn-danger">
</form>
-
<form action="" method="post">
:-
定义一个表单,其中action属性为空字符串,这意味着表单默认提交到当前页面(或者在后端路由处理时会指定一个具体URL)。
-
method属性设置为"post",表示表单数据将以POST方式发送,这种方式可以更好地保护敏感信息,如密码,因为它不会在URL中显示。
-
-
<p>username: <input type="text" class="form-control" name="username"></p>
:-
这部分创建了一个文本输入框,用户在此输入其用户名。
-
class属性值为"form-control",这是Bootstrap框架提供的CSS类,用来设定输入框的样式。
-
name属性值为"username",这个名称在服务器端接收表单数据时作为键名使用。
-
-
<span style="color: red">{{ back_dict.username }}</span>
:-
这是一个动态内容展示区域
-
根据所使用的模板引擎(如Jinja2、Vue.js等),
{{ back_dict.username }}
会被解析为从后台返回的错误提示信息 -
如果用户名有误,这里会显示红色的错误提示。
-
-
<p>password: <input type="password" class="form-control" name="password"></p>
:-
这部分创建了一个密码输入框,用户在此输入其密码。
-
type属性值为"password",这样输入的内容会以星号或其他符号代替显示,保护用户密码不被他人窥视。
-
同样具有form-control样式和name属性。
-
-
<span style="color: red">{{ back_dict.password }}</span>
:-
与用户名输入框下方的span元素类似
-
此处用于显示密码输入的错误提示信息。
-
-
<input type="submit" class="btn btn-danger">
:- 定义一个提交按钮,点击该按钮时,表单数据将会被发送至服务器。
- class属性值为"btn btn-danger",这是Bootstrap中用于创建危险主题样式的按钮。
(2)后端
from django.shortcuts import render
# Create your views here.
def register(request):
back_dict = {}
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if "啦啦啦" in username:
back_dict['username'] = '用户名不符合格式!'
if len(password) < 3:
back_dict['password'] = '输入的密码长度不够!'
'''
无论是 get 请求 还是 post 请求,页面都能获取到字典
get 请求时,字典是空的,没有值
post 请求时 ,字典可能是非空的
'''
return render(request, 'ab_form.html',locals())
(3)路由
from django.contrib import admin
from django.urls import path, re_path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
# form 组件引入
re_path(r'^register/',views.register),
]
(4)用到的技术点
- 手动书写前端HTML页面代码
- 渲染HTML页面
- 后端对用户数据进行校验
- 校验数据
- 对不符合要求的数据进行前端提示
- 展示提示信息
【2】Form组件校验数据
-
form组件可以帮我们完成
- 渲染HTML页面
- 校验数据
- 展示提示信息
-
为什么数据校验要在后端执行,而不是前端在JS完成?
- 数据校验前端可有可无
- 但是后端必须有!
-
原因
- 前端的校验存在实时被修改的风险,可以在前端直接修改输入的数据
- 利用爬虫程序可以绕过前端页面直接向后端提交数据
-
例如购物网站
- 在前端计算完总价后,直接提交给后端
- 后端如果不做校验就会产生极大的风险安全问题
- 正确的做法是
- 在后端查出所有商品的必要信息,再次计算一遍
- 前段与后端都要进行校验,保证数据的安全性
【三】Form组件如何校验数据
【1】编写表单类
- 我们可以通过Django提供的Form类来自用生成上面的表单,不再需要手动在HTML中编写。
(1)创建文件
- 首先,在你当前app内新建一个
forms.py
文件(这个套路是Django的惯用手法,就像views.py
,models.py
等等)
(2)书写form表单类
# 导入模块
from django import forms
# 按照Django form组件的要求自己写一个类 MyForm
class MyForm(forms.Form):
# username : 字符串类型 最小三位,最大八位
username = forms.CharField(max_length=8, min_length=3)
# # username : 字符串类型 最小三位,最大八位 : 字符串类型 最小三位,最大八位
password = forms.CharField(max_length=8, min_length=3)
# email : 必须符合邮箱格式 xxx@xx.com
email = forms.EmailField()
(3)注意事项
- 提前导入forms模块
- 所有的表单类都要继承forms.Form类
- 每个表单字段都有自己的字段类型比如CharField,它们分别对应一种HTML语言中的
<form>
元素中的表单元素。这一点和Django模型系统的设计非常相似。 - 例子中的label用于设置说明标签
max_length
限制最大长度为8。它同时起到两个作用,一是在浏览器页面限制用户输入不可超过8个字符,二是在后端服务器验证用户输入的长度不可超过8。
(警告:由于浏览器页面是可以被篡改、伪造、禁用、跳过的,所有的HTML手段的数据验证只能防止意外不能防止恶意行为,是没有安全保证的,破坏分子完全可以跳过浏览器的防御手段伪造发送请求!所以,在服务器后端,必须将前端当做“裸机”来对待,再次进行完全彻底的数据验证和安全防护!)
【2】校验数据
- 测试环境可以拷贝代码准备
- 其实在pycharm已经为我们提供了测试环境
- 底下的
Python Console
- 底下的
(准备数据)
# 导入模块
from app01 import views
# 将想要传入的数据组织成字典的格式传入即可
form_obj = views.MyForm({"username":"dream","password":"521","eemail":"123"})
(1)数据是否合法(is_valid)
- 每个Django表单的实例都有一个内置的
is_valid()
方法,用来验证接收的数据是否合法。
form_obj.is_valid()
# False
- 该方法,只有所有传入的数据都合法的情况下才会返回True
(2)查看合法的数据(cleaned_data)
- 如果所有数据都合法,那么该方法将返回True,并将所有的表单数据转存到它的一个叫做
cleaned_data
的属性中,该属性是一个字典类型数据。
form_obj.cleaned_data
# {'username': 'dream', 'password': '521'}
(2)查看合法数据(changed_data)
form_obj.changed_data
# ['username', 'password']
- 展示符合校验规则的数据
(3)查看不合法的数据(errors)
form_obj.errors
# {'username': ['Ensure this value has at most 2 characters (it has 5).'], 'password': ['Ensure this value has at most 2 characters (it has 3).'], 'email': ['This field is required.']}
- 查看所有不符合规则的参数及不符合的原因
- 报错原因可能有多个
(4)多传参数是否会报错
form_obj = views.MyForm({"username":"dream","password":"521","eemail":"123@qq.com","hobby":"music"})
form_obj.is_valid()
# True
- 校验数据只校验类中出现的字段
- 如果有多传的字段会直接自动忽略
(4)少传参数是否会报错
form_obj = views.MyForm({"username":"dream","password":"521"})
form_obj.errors
# {'email': ['This field is required.']}
- 校验数据
- 默认情况下,类中所有的字段都必须传值
(5)小结
- 默认情况下
- 校验数据可以多传
- 但是不能少传