forms组件主要功能是检验字段的功能,校验表单中的键值对的功能。
在python中Django 的form组件实现了如下的功能
• 生成页面可用的HTML标签
• 对用户提交的数据进行校验
• 保留上次输入内容
在不使用组件的情况下,我们要想对用户输入的表单的内容进行校验,需要写的代码可以是下面这种:
# 手写form校验密码
def test2(request):
err_msg = {}
username = ''
password = ''
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
if len(username) < 2:
err_msg['username'] = '用户名不能小于两位'
if len(password) < 6:
err_msg['password'] = '密码不能少于六位'
if not err_msg:
models.User.objects.create(
username=username,
password=password,
)
return HttpResponse('注册成功')
return render(request, 'app_1/register.html', {'err_msg': err_msg, 'username': username, 'password': password})
<html lang="en">
<head>
<meta charset="UTF-8">
<title>注册title>
head>
<body>
<form action="/app_1/test2/" method="POST">
{% csrf_token %}
<p>
账号:<input type="text" name="username" value="{{ username }}">
<span style="color: #ff0000;">{{ err_msg.username }}span>
p>
<p>
密码:<input type="password" name="password" value="{{ password }}">
<span style="color: #ff0000;">{{ err_msg.password }}span>
p>
<p><input type="submit" value="注册账号">p>
form>
body>
html>
使用form组件的情况下,我们可能只需下面这些代码:
# 使用form组件
# 1.导入form组件
from django import forms
# 2.编写form类并继承
class RegisterForm(forms.Form):
username = forms.CharField(label='用户名')
password = forms.CharField(label='密码')
# 3.创建视图
def register_form1(request):
# (1).创建对象
register_form = RegisterForm()
# (2).返回页面
return render(request, 'app_1/register_form.html', {'user_form': register_form})
class Register(forms.Form):
username = forms.CharField(
label='用户名',
max_length=6,
min_length=2,
required=True,
error_messages={
'max_length':'最大长度为6',
'min_length':'最小长度为2',
'required':'必填项',
}
)
password = forms.CharField(
label='密码',
max_length=12,
min_length=6,
required=True,
error_messages={
'max_length': '最大长度为6',
'min_length': '最小长度为2',
'required': '必填项',
}
)
def register(request):
register_form = Register()
if request.method == 'POST':
register_form = Register(request.POST)
if register_form.is_valid():
user_dict = register_form.cleaned_data
models.User.objects.create(
username=user_dict.get('username'),
password=user_dict.get('password'),
)
return HttpResponse('注册成功')
return render(request,'app_1/register_form1.html',{'register_form':register_form})
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="/app_1/test3/" method="POST" >
{% csrf_token %}
{{ user_form.username.label_suffix }}{{ user_form.username.label_tag }}{{ user_form.username }}
{{ user_form.password.label_tag }}{{ user_form.password }}
<input type="submit" value="注册">
form>
body>
html>
使用form组件的步骤:
from django import forms
username,pwd属性对应页面中的输入框前的=提示信息
pwd属性,用来修改页面上输入框前的显示内容
在页面中加入form表单,使其能够向后台提交数据。后台中接收到数据后要进行校验,同时如果用户输入的信息与我们要求的不一致,要进行错误提示,因此下面就要编写校验功能以及错误提示功能。
视图文件中Form类:
class UserForm(forms.Form):
username = forms.CharField(
label='用户名',
required=True,
min_length=2,
max_length=5,
error_messages={
'required':'不可为空',
'min_length':'长度不可小于2',
'max_length':'长度不可大于5'
}
)
pwd = forms.CharField(
label='密码',
max_length = 14,
min_length = 6,
error_messages={
'required': '不可为空',
'min_length': '长度不可小于6',
'max_length': '长度不可大于14',
}
)
视图函数:
def register_form(request):
# 创建userform对象
user_form = UserForm()
# 如果提交方式为post,说明用户已经通过form表单将信息提交到了后台
if request.method=='POST':
# 将用户传递的信息当成参数传进UserForm中,可对用户的信息进行校验
user_form = UserForm(request.POST)
return render(request,'app_1/1.html',{'user_form':user_form})
HTML页面:
<body>
<form action="" method="post" novalidate>
{% csrf_token %}
{#novalidate的作用,去掉表单校验,因为自动生成的标签自动添加了required属性#}
{% comment %}
1.user_form是User类的对象
2.user_form.username是user_form调用username属性
3.user_form.username.label:username也是一个对象,
username.label调用Field对象的label属性
{% endcomment %}
<p>
{{ user_form.username.label_tag }}{{ user_form.username }}
{# errors是username对象的一个列表,errors.0表示取出的第一个错误信息#}
{# 后台校验时如果与要求不匹配则停止,抛出错误,因此同一次提交至多一个错误#}
<label style="color: red;">{{ user_form.username.errors.0 }}label>
p>
<p>{{ user_form.username.label }}{{ user_form.username }}p>
<p>{{ user_form.pwd.label }}{{ user_form.pwd }}
<label style="color: red;">{{ user_form.pwd.errors.0 }}label>
p>
<p><input type="submit" value="注册提交">p>
form>
body>
只需在视图函数中增加创建数据库对象的语句即可。
代码块如下:
def register_form(request):
# 创建userform对象
user_form = UserForm()
# 如果提交方式为post,说明用户已经通过form表单将信息提交到了后台
if request.method=='POST':
# 将用户传递的信息当成参数传进UserForm中,可对用户的信息进行校验
user_form = UserForm(request.POST)
if user_form.is_valid():
# is_valid方法为:user_form对象中无错误信息
user_data = user_form.cleaned_data
# user_data为字典类型,以键值对的形式只存储了用户所填写的信息
#print(user_data)#{'pwd': '1234567', 'username': '111'}
username = user_data.get('username')
password = user_data.get('pwd')
models.User.objects.create(
username=username,
password=password,
)
return render(request,'app_1/1.html',{'user_form':user_form})
在此,我们已经将form组件进行用户信息验证并提交至数据库的基本代码块完成了,但是还是可以对代码块添加方法,使其功能更加完善。
步骤:
a) 视图文件中引入模块:from django.forms import ValidationError
b) 在组件类下重写clean方法,比如名称中不能包含特殊字符
def clean(self):
user_data = self.cleaned_data
username = user_data.get('username')
if user_data != {}:
if (username.find('@') != -1) or (username.find('#') != -1):
error = ValidationError('名称中不能包含特殊字符')
#第一个参数为字段名称
self.add_error('username',error)
raise error
else:
error = ValidationError('不可为空')
self.add_error('username',error)
raise error
return self.cleaned_data
除了可以自定义错误类型外,我们还可以自定义form组件对用户名与密码的检验。这主要是通过正则表达式来完成的。
步骤:
a) 视图文件中引入模块:from django.core.validators import RegexValidator
b) 给用户增加新的信息输入框,比如手机号码。
视图类User中增加属性:
mobile = forms.CharField(
label='手机号码',
required=True,
max_length=11,
validators=[
RegexValidator(r'^[0-9]$','手机号码必须全为数字'),
RegexValidator(r'^1[4-9][0-9]{9}$','手机号码为11位')
]
)
可以发现,在HTML中,无法为表单输入框以及表单输入文字设置样式,因为输入框并不是在网页中设置的。但是form组件中已经为我们写好了一种方法,可以方便的设置这些样式。
步骤:
a) 视图文件中引入模块:from django.forms import widgets
b) 为用户名与密码框添加样式
class UserForm(forms.Form):
username = forms.CharField(
label='用户名',
required=True,
min_length=2,
max_length=5,
error_messages={
'required':'不可为空',
'min_length':'长度不可小于2',
'max_length':'长度不可大于5'
},
widget=widgets.TextInput(attrs={'class':'box1'})
)
pwd = forms.CharField(
label='密码',
max_length = 14,
min_length = 6,
error_messages={
'required': '不可为空',
'min_length': '长度不可小于6',
'max_length': '长度不可大于14'
},
widget=widgets.PasswordInput(attrs={'class': 'box1'},render_value=True),
)
<style>
.box1{
color: cadetblue;
font-size: 20px;
border-color: red;
}
</style>
class User(models.Model):
username = models.CharField(max_length=10)
password = models.CharField(max_length=10)
def __str__(self):
return 'username:{},password:{}'.format(self.username,self.password)
views.py文件中
from django.shortcuts import render
from app_1 import models
from django import forms
from django.forms import ValidationError
from django.core.validators import RegexValidator
from django.forms import widgets
class UserForm(forms.Form):
username = forms.CharField(
label='用户名',
required=True,
min_length=2,
max_length=5,
error_messages={
'required':'不可为空',
'min_length':'长度不可小于2',
'max_length':'长度不可大于5'
},
widget=widgets.TextInput(attrs={'class':'box1'})
)
pwd = forms.CharField(
label='密码',
max_length = 14,
min_length = 6,
error_messages={
'required': '不可为空',
'min_length': '长度不可小于6',
'max_length': '长度不可大于14'
},
widget=widgets.PasswordInput(attrs={'class': 'box1'},render_value=True),
)
mobile = forms.CharField(
label='手机号码',
required=True,
max_length=11,
validators=[
RegexValidator(r'^[0-9]$','手机号码必须全为数字'),
RegexValidator(r'^1[4-9][0-9]{9}$','手机号码为11位')
]
)
def clean(self):
user_data = self.cleaned_data
print(user_data)
username = user_data.get('username')
if user_data != {}:
if (username.find('@') != -1) or (username.find('#') != -1):
error = ValidationError('名称中不能包含特殊字符')
#第一个参数为字段名称
self.add_error('username',error)
raise error
else:
error = ValidationError('不可为空')
self.add_error('username',error)
raise error
return self.cleaned_data
def register_form(request):
# 创建userform对象
user_form = UserForm()
# 如果提交方式为post,说明用户已经通过form表单将信息提交到了后台
if request.method=='POST':
# 将用户传递的信息当成参数传进UserForm中,可对用户的信息进行校验
user_form = UserForm(request.POST)
if user_form.is_valid():
# is_valid方法为:user_form对象有无错误信息
user_data = user_form.cleaned_data
# user_data为字典类型,以键值对的形式只存储了用户所填写的信息
#print(user_data)#{'pwd': '1234567', 'username': '111'}
username = user_data.get('username')
password = user_data.get('pwd')
models.User.objects.create(
username=username,
password=password,
)
return render(request,'app_1/1.html',{'user_form':user_form})
1.html文件中
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>第一个页面</title>
<style>
.box1{
color: cadetblue;
font-size: 20px;
border-color: red;
}
</style>
</head>
<body>
{#{{ user_form.as_p }}#}
{#也可以这样写,会将user_form中的每一行外面都包上ul标签#}
{#{{ user_form.as_ul }}#}
{#或者这样写,会将user_form中的每一行外面都包上table标签#}
{#{{ user_form.as_table }}#}
<form action="" method="post" novalidate>
{% csrf_token %}
{# novalidate的作用,去掉表单校验,因为自动生成的标签自动添加了required属性#}
{% comment %}
1.user_form是User类的对象
2.user_form.username是user_form调用username属性
3.user_form.username.label:username也是一个对象,
username.label调用Field对象的label属性
{% endcomment %}
<p>
{{ user_form.username.label_tag }}{{ user_form.username }}
{# errors是username对象的一个列表,errors.0表示取出的第一个错误信息#}
{# 后台校验时如果与要求不匹配则停止,抛出错误,因此同一次提交至多一个错误#}
<label style="color: red;">{{ user_form.username.errors.0 }}</label>
</p>
{# {{ user_form.username.label }}{{ user_form.username }}
#}
<p>{{ user_form.pwd.label }}{{ user_form.pwd }}
<label style="color: red;">{{ user_form.pwd.errors.0 }}</label>
</p>
<p><input type="submit" value="注册提交"></p>
</form>
</body>
</html>
用户开一个浏览器,点击多个超链接,访问服务器多个web资源,然后关闭浏览器,整个过程称之为一个会话。
1.会话过程中要解决的问题
http协议是无状态的,意为:每次都是基于一个请求一个响应.每次请求和响应都跟上次没有关系。
第一次我们登陆网站成功了,当点击购物车的时候就有可能访问的是别人的购物车。因为第一次和第二次访问是没有关系的。那怎么解决这个问题呢,我们可以在第一次请求的时候服务端制作一张身份证给浏览器,当浏览器再次请求的时候带着身份证到服务器,服务器拿到身份证后进行识别然后返回当前用户的内容。
上面的思路,我们有一个技术叫做Cookie。
Cookie是由服务器端生成,存储在浏览器中的一段纯文本信息,建议不要存 储敏感信息如密码,因为电脑上的浏览器可能被其它人使用。
1) 第一次访问服务器的时候,从服务端创建cookie,响应的时候,将cookie信息存放在响应头中,返回给浏览器,浏览器接收到之后,保存到本地中
2) 当浏览器再次访问服务器的时候,浏览器会在请求头中携带与该服务器有关的所有cookie信息,一起发送到服务端
3) 服务端接收到来自浏览器的二次请求时,根据需要从多个cookie中选择自己需要的cookie信息
视图函数中:
def login(request):
if request.method == 'POST':
#1.获取用户名与密码
username = request.POST.get('username')
password = request.POST.get('password')
rm = request.POST.get('rm','dsdad')#,复选框勾选会返回on,不选没有返回值,但是可以指定默认返回值rm = request.POST.get('rm','xxx')
# print(username,password,rm)
# try:
# rm = request.POST['rm']#用中括号形式在获取不到rm时会报错误,以便捕捉,小括号不会报错
# except MultiValueDictKeyError as e:
# re = 'xxx'
if username == 'za'and password == '123':
response = HttpResponse('登录成功')
if rm == 'on':
response .set_cookie('username',username,max_age=3600*24)
return response
username = request.COOKIES.get('username','')
return render(request,'app_1/login.html',{'username':username})
页面中:
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Titletitle>
head>
<body>
<form action="" method="post">
{% csrf_token %}
<p>
用户名:<input type="text" name="username" value="{{ username }}">
p>
<p>
密码:<input type="password" name="password" >
p>
<p>
<input type="checkbox" name="rm">记住用户名
p>
<p>
<input type="submit" value="登录" >
p>
form>
body>
html>
cookie不安全,一些重要信息比如密码之类,不能存放在cookie中,有泄露风险。
上面介绍了cookie,可以将用户的一些不重要的信息保存在浏览器本地中,比如用户名,用户在某网页的搜索记录等,但是类似于用户密码,用户银行卡号,用户身份证号等敏感信息,不能存放在cookie中,因为很容易就会被人盗用。所以有另一种方法可以来保存用户的这些敏感信息,就是session。
第一次访问服务端时生成session并且生成一个随机字符串sessionid作为session的唯 一标识保存到数据库。然后将sessionid设置给cookie,由cookie返回给浏览器,当浏览器下次访问时携带sessionid 即可从数据库中查找用户的信息,并且在数据库中cookieID以及sessionkey都是以base64加密方式保存的。
1)设置session:request.session[key]=value
2)获取session:request.session.get(key)
3)删除session:
request.session.flush() # 将整条记录删除
request.session.clear() # 删除内容部分
del request.session[‘username’]# 删除指定的key
注:Clear()只删除内容,session记录不会被删除
4) 指定session过期时间:request.session.set_expiry(2) 2s后过期
默认保存时间是14天。
同一浏览器在访问同一页面时,只会产生一条session记录