第六模块: WEB框架开发之Django框架开发学习笔记3
上接: 第六模块: WEB框架开发之Django框架开发学习笔记2
一百: forms组件的校验功能
参考:https://www.cnblogs.com/yuanchenqi/articles/9036474.html
100.1 校验就是检查用于输入的是否符合规范. 比如用户注册时,检查邮箱输入是否正确.
Django中有专门用于校验的模块
100.2 实例: 用户注册页面,对用户输入进行校验
# views.py from django.shortcuts import render, HttpResponse from django import forms # 引入表单验证的模块 class RegForm(forms.Form): """ 验证规则创建 需要验证哪个表单项,就创建相应的方法 """ user = forms.CharField(min_length=2) # 此处的user命名应当与html中表单的name值一致 pwd = forms.CharField(min_length=4) # 如果不加参数,则至少验证是否为空 pwd2 = forms.CharField(min_length=4) email = forms.EmailField() tel = forms.IntegerField() def reg(request): """ # 验证的格式, 及验证详解 ret = RegForm({'user': 'yuan', 'email': '123', "XXX": 'alex'}) # 对于class RegForm中没有定义的验证表单项,将不予理会"XXX": 'alex' print(ret.is_valid()) # 获取验证结果True/False, 只要有一条验证错误,就是False,当所有的验证通过,才显示True """ if request.method == "POST": # 对用户输入内容进行验证 ret = RegForm(request.POST) # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用. # print(ret) print(ret.is_valid()) # 获取验证结果True/False if ret.is_valid(): print(ret.cleaned_data) # 获取验证正确结果的详情{'user': 'alex', 'pwd': '1234', 'pwd2': '1234', 'email': '123@123.com', 'tel': 123} else: print(ret.cleaned_data) # 获取所有正确的验证项目{'user': 'alex', 'tel': 123} print(ret.errors) # 获取所有错误的验证项目,这里也是字典格式,比较特殊,下面是其返回值 # <ul class="errorlist"><li>pwd<ul class="errorlist"><li>Ensure this value has at least 4 characters (it has 3).</li></ul></li><li>pwd2<ul class="errorlist"><li>Ensure this value has at least 4 characters (it has 3).</li></ul></li><li>email<ul class="errorlist"><li>Enter a valid email address.</li></ul></li></ul> print(type(ret.errors)) # <class 'django.forms.utils.ErrorDict'> #
print(ret.errors.get('email')[0]) # 通过get可取值.这里打印出 Enter a valid email address.
return render(request, 'reg.html')
# reg.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户注册</title> </head> <body> <form action="" method="post"> {% csrf_token %} 用户名<input type="text" name="user"> 密码<input type="text" name="pwd"> 确认密码<input type="text" name="pwd2"> 邮箱地址<input type="text" name="email"> 手机号码<input type="text" name="tel"> <input type="submit"> </form> </body> </html>
一百零一: forms组件的渲染标签功能1
参考:https://www.cnblogs.com/yuanchenqi/articles/9036474.html 标签渲染
101.1 html中的form表单中的标签可以通过Django的forms组件直接渲染而成.
101.2 这里还是是用户注册为例. 注意观察reg.html页面中的from表单中的标签,已经不是原来的<input>标签了.
最终效果:
查看上图渲染出的客户端浏览器代码:, 注意观察name值, id值
源代码:
# views.py from django.shortcuts import render, HttpResponse from django import forms # 引入forms模块 # Create your views here. class RegForm(forms.Form): """ 验证规则创建,同时也将可以直接渲染至模板页面,成为html中form表单中的一个个标签. user将渲染成input标签的name属性值 """ user = forms.CharField(min_length=2, label='用户名') # label='用户名' 将渲染至<label>标签中 pwd = forms.CharField(min_length=4, label='密码') # pwd将渲染成input标签的name属性值 r_pwd = forms.CharField(min_length=4, label='确认密码') email = forms.EmailField(label='电子邮件') tel = forms.IntegerField(label='联系电话') def reg(request): form = RegForm() # 实例化forms对象, 这一步至关重要 return render(request, 'reg.html', locals()) # locals()将form对象传递到html模板页面中去
# reg.html <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户注册</title> </head> <body> <h3>forms渲染标签功能1</h3> <form action="" method="post"> // <form>标签还是要的 {% csrf_token %} <p>{{ form.user.label }}{{ form.user }}</p> // 注意, 这里将要渲染出<labe>标签和<input>标签 <p>{{ form.pwd.label }}{{ form.pwd }}</p> <p>{{ form.r_pwd.label }}{{ form.r_pwd }}</p> <p>{{ form.email.label }}{{ form.email }}</p> <p>{{ form.tel.label }}{{ form.tel }}</p> <input type="submit" value="提交" class="btn"> // 提交按钮的<input>标签不能丢 </form> </body> </html>
一百零二: forms组件的渲染标签功能2
102.1 第二种渲染的方法将采用for循环取每一个渲染对象
102.2 接着第一种方法.第二中方法只修改html模板文件中的form表单内部就可以了,别的不用动.
最终效果和第一种方法是一样的:
源代码如下:
<hr> <h3>forms渲染标签功能2</h3> <form action="" method="post"> {% csrf_token %} {% for item in form %} // for循环取值即可 <p>{{ item.label }}{{ item }}</p> {% endfor %} <input type="submit" value="注册" class="btn"> </form>
102.3 forms渲染标签的第三种方法,更加简单,但是不常用,一般只在测试代码时使用.关键代码{{ form.as_p }}
<hr> <h3>forms渲染标签功能3</h3> <form action="" method="post"> {% csrf_token %} {{ form.as_p }} // as_p 表示按照<p>标签进行渲染. 还有.as_ul等属性表示按照<ul>标签进行渲染 <input type="submit" value="注册" class="btn"> </form>
第3中方法不常用的原因是: 格式固定,不太好根据需要修改页面.
一百零三: forms组件的渲染错误信息
103.1 比如当用户注册输错电子邮件格式时,能给予提示.
html关键代码:
<h3>forms组件的渲染错误信息</h3> <form action="" method="post"> {% csrf_token %} <p>{{ form.user.label }}{{ form.user }}{{ form.user.errors.0 }}</p> <p>{{ form.pwd.label }}{{ form.pwd }}{{ form.pwd.errors.0 }}</p> <p>{{ form.r_pwd.label }}{{ form.r_pwd }}{{ form.r_pwd.errors.0 }}</p> <p>{{ form.email.label }}{{ form.email }}{{ form.email.errors.0 }}</p> <p>{{ form.tel.label }}{{ form.tel }}{{ form.tel.errors.0 }}</p> <input type="submit" value="提交" class="btn"> </form>
views.py关键代码:
def reg(request): if request.method == 'POST': form = RegForm(request.POST) # 对用户输入的表单内容进行验证 if form.is_valid(): # 验证通过 return HttpResponse('注册成功') else: # 验证失败, 返回错误信息给客户端 return render(request, 'reg.html', locals()) form = RegForm() # 实例化forms对象 return render(request, 'reg.html', locals()) # locals()将form对象传递到html模板页面中去
103.2 forms表单渲染的完整代码:
from django.shortcuts import render, HttpResponse from django import forms # 引入forms模块 # Create your views here. class RegForm(forms.Form): """ 验证规则创建,同时也将可以直接渲染至模板页面,成为html中form表单中的一个个标签. user将渲染成input标签的name属性值 """ user = forms.CharField(min_length=2, label='用户名') # label='用户名' 将渲染至<label>标签中 pwd = forms.CharField(min_length=4, label='密码') # pwd将渲染成input标签的name属性值 r_pwd = forms.CharField(min_length=4, label='确认密码') email = forms.EmailField(label='电子邮件') tel = forms.IntegerField(label='联系电话') def reg(request): if request.method == 'POST': form = RegForm(request.POST) # 对用户输入的表单内容进行验证 if form.is_valid(): # 验证通过 return HttpResponse('注册成功') else: # 验证失败, 返回错误信息给客户端 return render(request, 'reg.html', locals()) form = RegForm() # 实例化forms对象 return render(request, 'reg.html', locals()) # locals()将form对象传递到html模板页面中去
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户注册</title> </head> <body> <h3>forms渲染标签功能1</h3> <form action="" method="post"> {% csrf_token %} <p>{{ form.user.label }}{{ form.user }}</p> <p>{{ form.pwd.label }}{{ form.pwd }}</p> <p>{{ form.r_pwd.label }}{{ form.r_pwd }}</p> <p>{{ form.email.label }}{{ form.email }}</p> <p>{{ form.tel.label }}{{ form.tel }}</p> <input type="submit" value="提交" class="btn"> </form> <hr> <h3>forms渲染标签功能2</h3> <form action="" method="post"> {% csrf_token %} {% for item in form %} <p>{{ item.label }}{{ item }}</p> {% endfor %} <input type="submit" value="注册" class="btn"> </form> <hr> <h3>forms渲染标签功能3</h3> <form action="" method="post"> {% csrf_token %} {{ form.as_p }} <input type="submit" value="注册" class="btn"> </form> <hr> <h3>forms组件的渲染错误信息</h3> <form action="" method="post"> {% csrf_token %} <p>{{ form.user.label }}{{ form.user }}{{ form.user.errors.0 }}</p> <p>{{ form.pwd.label }}{{ form.pwd }}{{ form.pwd.errors.0 }}</p> <p>{{ form.r_pwd.label }}{{ form.r_pwd }}{{ form.r_pwd.errors.0 }}</p> <p>{{ form.email.label }}{{ form.email }}{{ form.email.errors.0 }}</p> <p>{{ form.tel.label }}{{ form.tel }}{{ form.tel.errors.0 }}</p> <input type="submit" value="提交" class="btn"> </form> </body> </html>
104.3 需要说明的是新版的Django已经自动提供了错误渲染功能.所以就无需在在标签后面加上
{{ form.user.errors.0 }}了. views.py中的验证代码还是要加的.
一百零四: forms组件的参数配置
104.1 比如让input框变成密码框, 改变错误的提示内容等.增添修改标签的css样式等.
引入参数配置功能模块 from django.forms import widgets
104.2 修改用户注册,实现效果如下:
关键代码:注意这里借助了bootstrap.
class RegForm(forms.Form):
"""
验证规则创建,同时也将可以直接渲染至模板页面,成为html中form表单中的一个个标签.
user将渲染成input标签的name属性值
"""
user = forms.CharField(min_length=2, label='用户名', error_messages={'required': '自定义错误提示:该字段不能为空'},
widget=widgets.TextInput(attrs={"class": "form-control"}) # 为该标签添加class属性,对css样式进行渲染
)
pwd = forms.CharField(min_length=4, label='密码',
widget=widgets.PasswordInput(attrs={"class": "form-control"}), # 将input输入框变成密码输入框
)
r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={"class": "form-control"}))
email = forms.EmailField(label='电子邮件', error_messages={'invalid': '格式错误'}, widget=widgets.TextInput(attrs={"class": "form-control"}))
tel = forms.IntegerField(label='联系电话', widget=widgets.TextInput(attrs={"class": "form-control"}))
<head> <meta charset="UTF-8"> <title>用户注册</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <h3>forms渲染标签功能1</h3> <form action="" method="post"> {% csrf_token %} <p>{{ form.user.label }}{{ form.user }}{{ form.user.errors.0 }}</p> <p>{{ form.pwd.label }}{{ form.pwd }}{{ form.pwd.errors.0 }}</p> <p>{{ form.r_pwd.label }}{{ form.r_pwd }}{{ form.r_pwd.errors.0 }}</p> <p>{{ form.email.label }}{{ form.email }}{{ form.email.errors.0 }}</p> <p>{{ form.tel.label }}{{ form.tel }}{{ form.tel.errors.0 }}</p> <input type="submit" value="提交" class="btn"> </form> </div> </div> </div>
一百零五: forms组件校验的局部钩子
105.1 让校验条件更加灵活,比如判断用户名有么有注册过.比如校验手机号码是否是11位.
需要引入一个模块from django.core.exceptions import ValidationError
105.2 实例:
关键代码:
# views.py class RegForm(forms.Form): """ 初步验证规则创建 """ name = forms.CharField(min_length=2, label='用户名', widget=widgets.TextInput(attrs={'class': "form-control"})) pwd = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={'class': "form-control"})) r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={'class': "form-control"})) email = forms.EmailField(label='电子邮件', widget=widgets.TextInput(attrs={'class': "form-control"})) tel = forms.CharField(label='手机号码', widget=widgets.TextInput(attrs={'class': "form-control"})) """ 自定义验证规则(局部钩子) """ def clean_name(self): # 这里的函数名clean_name的格式是 clean_字段名 # 定义验证用户名是否已经注册过 val = self.cleaned_data.get('name') # 从初步验证的结果中,再次取出数据 ret = User.objects.filter(name=val) # 从数据库中取数据 if not ret: return val else: raise ValidationError("该用户已经注册过") def clean_tel(self): # 定义手机号码必须是11位数 val = self.cleaned_data.get('tel') if len(val) == 11: return val else: raise ValidationError("手机号码必须是11位")
完整代码:
from django.shortcuts import render, HttpResponse from django import forms # 引入表单验证的模块 from django.forms import widgets # 表单验证的附加功能,如添加css样式 from app01.models import User from django.core.exceptions import ValidationError # Create your views here. class RegForm(forms.Form): """ 初步验证规则创建 """ name = forms.CharField(min_length=2, label='用户名', widget=widgets.TextInput(attrs={'class': "form-control"})) pwd = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={'class': "form-control"})) r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={'class': "form-control"})) email = forms.EmailField(label='电子邮件', widget=widgets.TextInput(attrs={'class': "form-control"})) tel = forms.CharField(label='手机号码', widget=widgets.TextInput(attrs={'class': "form-control"})) """ 自定义验证规则(局部钩子) """ def clean_name(self): # 这里的函数名clean_name的格式是 clean_字段名 # 定义验证用户名是否已经注册过 val = self.cleaned_data.get('name') # 从初步验证的结果中,再次取出数据 ret = User.objects.filter(name=val) # 从数据库中取数据 if not ret: return val else: raise ValidationError("该用户已经注册过") def clean_tel(self): # 定义手机号码必须是11位数 val = self.cleaned_data.get('tel') if len(val) == 11: return val else: raise ValidationError("手机号码必须是11位") def reg(request): if request.method == "POST": # 对用户输入内容进行验证 form = RegForm(request.POST) # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用. if form.is_valid(): return HttpResponse("注册成功") else: return render(request, 'reg.html', locals()) # 返回验证错误的信息 form = RegForm() return render(request, 'reg.html', locals())
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户注册</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <h3>forms组件校验的局部钩子</h3> <form action="" method="post"> {% csrf_token %} {% for item in form %} <p>{{ item.label }}{{ item }}<span>{{ item.errors.0 }}</span></p> {% endfor %} <input type="submit"> </form> </div> </div> </div> </body> </html>
Django源代码中钩子的位置,正是使用了下面这个钩子,我们才可以进行自定义验证规则:
一百零六: forms组件之全局钩子
106.1 什么时候需要用全局钩子:
比如校验两次输入的密码是否一致.
106.2 注意:forms的相关校验代码应当单独放到一个py文件中,尽量不要放在views.py视图文件中
106.3 实例, 全局钩子校验两次输入的密码是否一致:
关键代码:
# app01下myforms.py(新建文件) """ 自定义验证规则(全局钩子) """ 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("两次输入密码不一致")
# views.py中获取全局钩子错误 def reg(request): if request.method == "POST": # 对用户输入内容进行验证 form = RegForm(request.POST) # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用. if form.is_valid(): return HttpResponse("注册成功") else: # 全局钩子错误 # print(form.errors.get("__all__")[0]) error_all = form.errors.get("__all__") # 获取全局错误 return render(request, 'reg.html', locals()) # 返回验证错误的信息 form = RegForm() return render(request, 'reg.html', locals())
# 在reg.html中的确认密码处显示全局钩子错误 error_all.0 <p>{{ form.r_pwd.label }}{{ form.r_pwd }} <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span> <span class="pull-right error">{{ error_all.0 }}</span> </p>
完整代码:
from django.shortcuts import render, HttpResponse from app01.myforms import RegForm # 引入自定义的forms组件校验模块 def reg(request): if request.method == "POST": # 对用户输入内容进行验证 form = RegForm(request.POST) # request.POST的返回值是一个字典{}, 和上面所讲的验证格式相符, 所以这里直接用. if form.is_valid(): return HttpResponse("注册成功") else: # 全局钩子错误 # print(form.errors.get("__all__")[0]) error_all = form.errors.get("__all__") # 获取全局错误 return render(request, 'reg.html', locals()) # 返回验证错误的信息 form = RegForm() return render(request, 'reg.html', locals())
# -*- coding: utf-8 -*- # programming environment:windows7_64 + python3.8.3_64 from django import forms # 引入表单验证的模块 from django.forms import widgets # 表单验证的附加功能,如添加css样式 from app01.models import User from django.core.exceptions import ValidationError class RegForm(forms.Form): """ 初步验证规则创建 """ name = forms.CharField(min_length=2, label='用户名', widget=widgets.TextInput(attrs={'class': "form-control"})) pwd = forms.CharField(min_length=4, label='密码', widget=widgets.PasswordInput(attrs={'class': "form-control"})) r_pwd = forms.CharField(min_length=4, label='确认密码', widget=widgets.PasswordInput(attrs={'class': "form-control"})) email = forms.EmailField(label='电子邮件', widget=widgets.TextInput(attrs={'class': "form-control"})) tel = forms.CharField(label='手机号码', widget=widgets.TextInput(attrs={'class': "form-control"})) """ 自定义验证规则(局部钩子) """ def clean_name(self): # 这里的函数名clean_name的格式是 clean_字段名 # 定义验证用户名是否已经注册过 val = self.cleaned_data.get('name') # 从初步验证的结果中,再次取出数据 ret = User.objects.filter(name=val) # 从数据库中取数据 if not ret: return val else: raise ValidationError("该用户已经注册过") def clean_tel(self): # 定义手机号码必须是11位数 val = self.cleaned_data.get('tel') if len(val) == 11: return val else: raise ValidationError("手机号码必须是11位") """ 自定义验证规则(全局钩子) """ 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("两次输入密码不一致")
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>用户注册</title> <!-- 最新版本的 Bootstrap 核心 CSS 文件 --> <link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@3.3.7/dist/css/bootstrap.min.css" integrity="sha384-BVYiiSIFeK1dGmJRAkycuHAHRg32OmUcww7on3RYdg4Va+PmSTsz/K68vbdEjh4u" crossorigin="anonymous"> </head> <body> <div class="container"> <div class="row"> <div class="col-md-6 col-lg-offset-3"> <h3>forms组件之全局钩子</h3> <form action="" method="post"> {% csrf_token %} <p>{{ form.name.label }}{{ form.name }}<span class="pull-right error">{{ form.name.errors.0 }}</span></p> <p>{{ form.pwd.label }}{{ form.pwd }}<span class="pull-right error">{{ form.pwd.errors.0 }}</span></p> <p>{{ form.r_pwd.label }}{{ form.r_pwd }} <span class="pull-right error">{{ form.r_pwd.errors.0 }}</span> <span class="pull-right error">{{ error_all.0 }}</span> </p> <p>{{ form.email.label }}{{ form.email }}<span class="pull-right error">{{ form.email.errors.0 }}</span></p> <p>{{ form.tel.label }}{{ form.tel }}<span class="pull-right error">{{ form.tel.errors.0 }}</span></p> <input type="submit"> </form> </div> </div> </div> </body> </html>
from django.db import models # Create your models here. class User(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32) email = models.EmailField() tel = models.IntegerField(max_length=11)
一百零七: HTTP协议的无状态保存
服务器对于客户的每一次访问,它都认为是全新的.然而我们经常需要知道用户是否已经访问过,然后针对访问过的用户展示不同的内容.
这就需要用到cookie和session
一百零八: cookie简介
参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html
cookie: 具体一个浏览器针对一个服务器存储key-value({})
cookie的数据是存储在浏览器本地的.浏览器第一次访问某个网站时会携带空字典的cookie,如果服务器端有相关的cookie处理视图则会返回到客户端的cookie中,当下次再访问该网站时就会携带该有数据的cookie访问网站.常用于用户登录.
一百零九: cookie的设置与读取
109.1 关键代码:设置cookie
def login(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: """ 响应体 return HttpResponse() return render() return redirect() """ response = HttpResponse('登录成功') response.set_cookie('is_login', True) # 设置cookies response.set_cookie('name', ret.name) # 设置cookies return response
return render(request, 'login.html')
关键代码 读取cookie
def index(request): is_login = request.COOKIES.get('is_login') # 获取cookies if is_login: name = request.COOKIES.get('name') # 获取cookies return render(request, 'index.html', {'name': name}) return redirect('/login/')
登录成功后index的显示效果:
检查网页客户端,发现的cookie信息如下:和设置的cookies一致
109.2 实例,验证用户是否登录过本网站,如果没有登录,则返回登录页面.
from django.db import models # Create your models here. class UserInfo(models.Model): name = models.CharField(max_length=32) pwd = models.CharField(max_length=32)
from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('add/', views.add), path('login/', views.login), path('index/', views.index), ]
from django.shortcuts import render, redirect, HttpResponse from app01.models import UserInfo # Create your views here. def add(request): UserInfo.objects.create(name='alex', pwd='123') UserInfo.objects.create(name='papa', pwd='456') return HttpResponse('新建数据完成!') def login(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: """ 响应体 return HttpResponse() return render() return redirect() """ response = HttpResponse('登录成功') response.set_cookie('is_login', True) # 设置cookies response.set_cookie('name', ret.name) # 设置cookies return response return render(request, 'login.html') def index(request): print(request.COOKIES) is_login = request.COOKIES.get('is_login') # 获取cookies if is_login: name = request.COOKIES.get('name') # 获取cookies return render(request, 'index.html', {'name': name}) return redirect('/login/')
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>用户登录</h3> <form action="" method="post"> {% csrf_token %} 用户名<input type="text" name="name"> 密码<input type="text" name="pwd"> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>你好, {{ name }}!</h3> </body> </html>
一百一十: 设置cookie的超时参数
参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html
超过设置的时间后,浏览器中携带的cookie将失效.
110.1 设置cookie的有效时间,超过这个时间则已经获取的cookie失效, 参数max_age默认为None, 即浏览器关闭后失效.
response.set_cookie('is_login', True, max_age=10) # 设置cookie, 10秒后is_login==False
110.2 设置cookie失效的指定日期时间点,参数expires默认值是None
import datetime date = datetime.datetime(year=2021, month=2, day=21, hour=2, minute=38, second=0) # 指定过期日期, 因为我们是东八区,所有hour要减去8 response.set_cookie('name', ret.name, expires=date) # 设置cookies
一百一十一: 设置cookie的有效路径
参数path默认是所有路径都有效.
response.set_cookie('name', ret.name, path='/index/') # 设置有效路径, index这个路径才有包含name的cookie
一百一十二: cookie应用之保存上次访问时间
112.1 删除cookie
response.delete_cookie("cookie_key", path='/', domain=name) # 删除cookies的操作
还可以直接在浏览器中清空cookie
112.2 客户端显示上次登录时间
关键代码:
def index(request): print(request.COOKIES) is_login = request.COOKIES.get('is_login') # 获取cookies if is_login: name = request.COOKIES.get('name') # 获取cookies import datetime now_time = datetime.datetime.now().strftime("%Y-%m-%d %X") # 设置当前时间 last_time = request.COOKIES.get('last_time', '') # 获取cookie中的上次登录时间, 取不到时间则默认为空 response = render(request, 'index.html', {'name': name, 'now_time': now_time, 'last_time': last_time}) response.set_cookie('last_time', now_time) # 把本次登录时间设置到cookie中 return response return redirect('/login/')
一百一十三: session的流程简介
参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html session
也是一个会话跟踪技术
113.1 session是服务端技术,是基于cookie开发的.主要是基于安全考虑.
cookies将数据存到客户端, session将数据存储到服务端.
session相当于你去澡堂洗澡,你的衣服放在澡堂的柜子里面,session就是柜子号牌钥匙.你通过柜子号牌钥匙就可以取到衣服.
113.2 数据库中自动创建的django_session表
一一四: session之保存登录状态信息
114.1 设置session的值,request.session['is_login']=True,注意每设置一次session值,django做了三件事
def login_session(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: request.session['is_login'] = True # 设置session值 """ # 每设置一次session值,django做了三件事 1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 在django-session表中创建一条记录: session-key session-data 59b3k5f9fxpg17t2ikdoh7x787axaz8c {'is_login': True} # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs """ request.session['name'] = ret.name # 设置session值 return HttpResponse('登录成功') return render(request, "login.html")
114.2 读取session的值, request.session.get('is_login'),注意每读取一次session值,django也做了三件事
def index_session(request): is_login = request.session.get('is_login') # 读取session值 """ # 每读取一次session值,django也做了三件事 1. request.COOKIE.get("is_login") 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. django-session表中过滤记录 django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 取出'is_login'值 obj.session-data.get('is_login') """ if is_login: name = request.session.get('name') # 读取session值 return render(request, 'index.html', {'name': name}) return redirect('/login_session/')
114.3 完整代码:
from django.shortcuts import render, redirect, HttpResponse from app01.models import UserInfo # Create your views here. def add(request): UserInfo.objects.create(name='alex', pwd='123') UserInfo.objects.create(name='papa', pwd='456') return HttpResponse('新建数据完成!') def login(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: """ 响应体 return HttpResponse() return render() return redirect() """ response = HttpResponse('登录成功') response.set_cookie('is_login', True, max_age=None) # 设置cookies import datetime # date = datetime.datetime(year=2021, month=2, day=21, hour=2, minute=38, second=0) # 指定过期日期, 因为我们是东八区,所有hour要减去8 # response.set_cookie('name', ret.name, expires=date) # 设置cookies response.set_cookie('name', ret.name, path='/index/') # 设置有效路径, index这个路径才有包含name的cookie return response return render(request, 'login.html') def index(request): print(request.COOKIES) is_login = request.COOKIES.get('is_login') # 获取cookies if is_login: name = request.COOKIES.get('name') # 获取cookies import datetime now_time = datetime.datetime.now().strftime("%Y-%m-%d %X") # 设置当前时间 last_time = request.COOKIES.get('last_time', '') # 获取cookie中的上次登录时间, 取不到时间则默认为空 response = render(request, 'index.html', {'name': name, 'now_time': now_time, 'last_time': last_time}) response.set_cookie('last_time', now_time) # 把本次登录时间设置到cookie中 return response return redirect('/login/') def login_session(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: request.session['is_login'] = True # 设置session值 """ # 每设置一次session值,django做了三件事 1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 在django-session表中创建一条记录: session-key session-data 59b3k5f9fxpg17t2ikdoh7x787axaz8c {'is_login': True} # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs """ request.session['name'] = ret.name # 设置session值 return HttpResponse('登录成功') return render(request, "login.html") def index_session(request): is_login = request.session.get('is_login') # 读取session值 """ # 每读取一次session值,django也做了三件事 1. request.COOKIE.get("is_login") 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. django-session表中过滤记录 django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 取出'is_login'值 obj.session-data.get('is_login') """ if is_login: name = request.session.get('name') # 读取session值 return render(request, 'index.html', {'name': name}) return redirect('/login_session/')
"""cookieSession URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('add/', views.add), path('login/', views.login), path('index/', views.index), path('login_session/', views.login_session), path('index_session/', views.index_session), ]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>你好, {{ name }}!</h3> <h4>上次登录时间{{ last_time }}</h4> <h4>本次登录时间{{ now_time }}</h4> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>用户登录</h3> <form action="" method="post"> {% csrf_token %} 用户名<input type="text" name="name"> 密码<input type="text" name="pwd"> <input type="submit"> </form> </body> </html>
114.4 效果:
django_session表中生成的记录
浏览器客户端cookies中存储的值
一一五: session应用之保存上次登录时间
115.1 先看效果
115.2 设置session的值, 记录登录时间.
def login_session(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: request.session['is_login'] = True # 设置session值 """ # 每设置一次session值,django做了三件事 1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 在django-session表中创建一条记录: session-key session-data 59b3k5f9fxpg17t2ikdoh7x787axaz8c {'is_login': True} # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs """ request.session['name'] = ret.name # 设置session值 import datetime now_time = datetime.datetime.now().strftime('%Y-%m-%d %X') request.session['last_time'] = now_time # 设置session值, 记录用户登录时间 return HttpResponse('登录成功') return render(request, "login.html")
115.3 读取session中登录的时间
def index_session(request): is_login = request.session.get('is_login') # 读取session值 """ # 每读取一次session值,django也做了三件事 1. request.COOKIE.get("is_login") 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. django-session表中过滤记录 django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 取出'is_login'值 obj.session-data.get('is_login') """ if is_login: name = request.session.get('name') # 读取session值 last_time = request.session.get('last_time') # 读取session值, 上次用户登录时间 return render(request, 'index.html', {'name': name, 'last_time': last_time}) return redirect('/login_session/')
一一六: session的更新操作
没有单独的更新操作的方法,更新操作就用上面的设置session方法.
接上节课,当对session执行设置操作时,如果该客户端的该浏览器已经设置过session,则有新数据时,就只更新session中的相应记录,而不会新增记录, session-key不会变,session-data数据更新.
比如:A电脑的谷歌浏览器上午用alex用户登录过该网页,下午还是用A电脑的谷歌浏览器,但用户变成了papa登录,这时django不会新增sessionid,还用上午的那个sessionid,然后修改表中对应的session-data数据.原有的alex登录数据就被覆盖了.
一一七: 基于session的注销功能与session的配置参数
参考:https://www.cnblogs.com/yuanchenqi/articles/9036467.html
117.1 注销功能, 使用flush()方法
def logout(request): # del request.session['is_login'] # 删除session中某个键值, 一般不用这个 request.session.flush() # 删除表中当前session一整条记录, 还会删除客户端浏览器的cookie相应的记录 """ # flush()操作也做了三件事 1. randon_str = request.COOKIE.get('sessionid') 获取cookie中的sessionid 2. django-session.objects.filter(session-key=randon_str).delete() 从表中过滤出该条记录,并删除掉 3. response.delete_cookie('sessionid', randon_str) 删除客户端浏览器的cookie记录 """ return redirect('/login_session/')
完整代码:
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>你好, {{ name }}!</h3> <h4>上次登录时间{{ last_time }}</h4> <h4>本次登录时间{{ now_time }}</h4> <a href="/logout">注销</a> </body> </html>
"""cookieSession URL Configuration
The `urlpatterns` list routes URLs to views. For more information please see:
https://docs.djangoproject.com/en/3.1/topics/http/urls/
Examples:
Function views
1. Add an import: from my_app import views
2. Add a URL to urlpatterns: path('', views.home, name='home')
Class-based views
1. Add an import: from other_app.views import Home
2. Add a URL to urlpatterns: path('', Home.as_view(), name='home')
Including another URLconf
1. Import the include() function: from django.urls import include, path
2. Add a URL to urlpatterns: path('blog/', include('blog.urls'))
"""
from django.contrib import admin
from django.urls import path
from app01 import views
urlpatterns = [
path('admin/', admin.site.urls),
path('add/', views.add),
path('login/', views.login),
path('index/', views.index),
path('login_session/', views.login_session),
path('index_session/', views.index_session),
path('logout/', views.logout),
]
from django.shortcuts import render, redirect, HttpResponse from app01.models import UserInfo # Create your views here. def add(request): UserInfo.objects.create(name='alex', pwd='123') UserInfo.objects.create(name='papa', pwd='456') return HttpResponse('新建数据完成!') def login(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: """ 响应体 return HttpResponse() return render() return redirect() """ response = HttpResponse('登录成功') response.set_cookie('is_login', True, max_age=None) # 设置cookies import datetime # date = datetime.datetime(year=2021, month=2, day=21, hour=2, minute=38, second=0) # 指定过期日期, 因为我们是东八区,所有hour要减去8 # response.set_cookie('name', ret.name, expires=date) # 设置cookies response.set_cookie('name', ret.name, path='/index/') # 设置有效路径, index这个路径才有包含name的cookie return response return render(request, 'login.html') def index(request): print(request.COOKIES) is_login = request.COOKIES.get('is_login') # 获取cookies if is_login: name = request.COOKIES.get('name') # 获取cookies import datetime now_time = datetime.datetime.now().strftime("%Y-%m-%d %X") # 设置当前时间 last_time = request.COOKIES.get('last_time', '') # 获取cookie中的上次登录时间, 取不到时间则默认为空 response = render(request, 'index.html', {'name': name, 'now_time': now_time, 'last_time': last_time}) response.set_cookie('last_time', now_time) # 把本次登录时间设置到cookie中 return response return redirect('/login/') def login_session(request): if request.method == "POST": name = request.POST.get('name') pwd = request.POST.get('pwd') ret = UserInfo.objects.filter(name=name, pwd=pwd).first() if ret: request.session['is_login'] = True # 设置session值 """ # 每设置一次session值,django做了三件事 1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 在django-session表中创建一条记录: session-key session-data 59b3k5f9fxpg17t2ikdoh7x787axaz8c {'is_login': True} # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs """ request.session['name'] = ret.name # 设置session值 import datetime now_time = datetime.datetime.now().strftime('%Y-%m-%d %X') request.session['last_time'] = now_time # 设置session值, 记录用户登录时间 return HttpResponse('登录成功') return render(request, "login.html") def index_session(request): is_login = request.session.get('is_login') # 读取session值 """ # 每读取一次session值,django也做了三件事 1. request.COOKIE.get("is_login") 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. django-session表中过滤记录 django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 取出'is_login'值 obj.session-data.get('is_login') """ if is_login: name = request.session.get('name') # 读取session值 last_time = request.session.get('last_time') # 读取session值, 上次用户登录时间 return render(request, 'index.html', {'name': name, 'last_time': last_time}) return redirect('/login_session/') def logout(request): # del request.session['is_login'] # 删除session中某个键值, 一般不用这个 request.session.flush() # 删除表中当前session一整条记录, 还会删除客户端浏览器的cookie相应的记录 """ # flush()操作也做了三件事 1. randon_str = request.COOKIE.get('sessionid') 获取cookie中的sessionid 2. django-session.objects.filter(session-key=randon_str).delete() 从表中过滤出该条记录,并删除掉 3. response.delete_cookie('sessionid', randon_str) 删除客户端浏览器的cookie记录 """ return redirect('/login_session/')
117.2 session的配置参数
Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。 a. 配置 settings.py, 在settings.py中新增以下需要的项目. SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认) SESSION_COOKIE_NAME = "sessionid" # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认) SESSION_COOKIE_PATH = "/" # Session的cookie保存的路径(默认) SESSION_COOKIE_DOMAIN = None # Session的cookie保存的域名(默认) SESSION_COOKIE_SECURE = False # 是否Https传输cookie(默认) SESSION_COOKIE_HTTPONLY = True # 是否Session的cookie只支持http传输(默认) SESSION_COOKIE_AGE = 1209600 # Session的cookie失效日期(2周)(默认) SESSION_EXPIRE_AT_BROWSER_CLOSE = False # 是否关闭浏览器使得Session过期(默认) SESSION_SAVE_EVERY_REQUEST = False # 是否每次请求都保存Session,默认修改之后才保存(默认)
一一八: session总结
需要掌握的的内容:
1. 写cookie操作 response.set_cookie(key, value) 2. 读cookie操作 request.COOKIE.get(key) 3. 写(设置)session操作 request.session[key] = value """ # 每设置一次session值,django做了三件事 1. 生成随机字符串 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. response.set_cookie('sessionid', '59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 在django-session表中创建一条记录: session-key session-data 59b3k5f9fxpg17t2ikdoh7x787axaz8c {'is_login': True} # 注意此处data将会以加密序列化形式存储在数据库中,eyJpc19sb2dpbiI6dHJ1ZSwibmFtZSI6ImFsZXgifQ:1lE0AL:inRnarARLVqyDSEpXghTWZFyMce4v2nQ4HZ57j8PrHs """ 4. 读取session操作 request.session.get[key] """ # 每读取一次session值,django也做了三件事 1. request.COOKIE.get("is_login") 59b3k5f9fxpg17t2ikdoh7x787axaz8c 2. django-session表中过滤记录 django_session.objects.filter(session-key='59b3k5f9fxpg17t2ikdoh7x787axaz8c') 3. 取出'is_login'值 obj.session-data.get('is_login') """ 5. 删除session操作 request.session.flush() """ # flush()操作也做了三件事 1. randon_str = request.COOKIE.get('sessionid') 获取cookie中的sessionid 2. django-session.objects.filter(session-key=randon_str).delete() 从表中过滤出该条记录,并删除掉 3. response.delete_cookie('sessionid', randon_str) 删除客户端浏览器的cookie记录 """
一一九: 用户认证组件简介
参考:https://www.cnblogs.com/yuanchenqi/articles/9064397.html
119.1 使用cookie,session会出现一些问题,多用户使用时会数据会混淆
119.2 使用用户认证组件会使程序更完善,更严谨,可以避免出现数据混淆等错误.推荐使用该组件.
auth模块 from django.contrib import auth
119.2 用户认证组件说明:
功能: 用session记录登录验证状态
前提: 用户表: Django自带auth_user表 (该表字段比较多,可能不符合自己的需求,怎么办?可以根据自己需要新建新表,然后关联到auth_user表,或者继承该表.)
先进行迁移生成数据库,表.
然后,创建超级用户: 命令:python manage.py createsuperuser
一二0: 基于用户认证组件的登录验证信息存储
120.1 用户登录验证, 并存储信息.
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth # 导入用户认证组件 def login(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选 user = auth.authenticate(username=user, password=pwd) # 与表中记录进行验证(相当于fillter筛选) if user: # request.user=user就是当前登录对象,它是全局变量,可以在任意地方直接使用, 这里非常重要,将自动向session表添加记录. auth.login(request, user) # 如果没有登录,则是匿名对象. return redirect('/index/') return render(request, 'login.html')
120.2 读取登录用户的信息,并在模板显示
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth # 导入用户认证 def index(request): print(request.user) # 打印当前用户对象, request.user是全局变量. print(request.user.username) # 打印当前用户 print(request.user.id) # 用户id,匿名用户是None print(request.user.is_anonymous) # 是否是匿名用户 if request.user.is_anonymous: # 如果是匿名用户(就是没有登录),则跳转到登录页面. return redirect('/login/') # username = request.user.username # 这一步可以省略了. return render(request, 'index.html') # 这里省略了向模板传递参数.因为request.user是全局变量,甚至可以直接用在模板中. # 如果没有登录,那么request.user显示匿名用户AnonymousUser
120.3 使用request.user.username全局变量,在模板中显示用户登录信息.
<h3>你好, {{ request.user.username }}</h3>
120.4 完整代码
"""authDemo URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), path('index/', views.index), ]
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth # 导入用户认证组件 def login(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选 user = auth.authenticate(username=user, password=pwd) # 与表中记录进行验证(相当于fillter筛选) if user: # request.user=user就是当前登录对象,它是全局变量,可以在任意地方直接使用, 这里非常重要,将自动向session表添加记录. auth.login(request, user) # 如果没有登录,则是匿名对象. return redirect('/index/') return render(request, 'login.html') def index(request): print(request.user) # 打印当前用户对象, request.user是全局变量. print(request.user.username) # 打印当前用户 print(request.user.id) # 用户id,匿名用户是None print(request.user.is_anonymous) # 是否是匿名用户 if request.user.is_anonymous: # 如果是匿名用户(就是没有登录),则跳转到登录页面. return redirect('/login/') # username = request.user.username # 这一步可以省略了. return render(request, 'index.html') # 这里省略了向模板传递参数.因为request.user是全局变量,甚至可以直接用在模板中. # 如果没有登录,那么request.user显示匿名用户AnonymousUser
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>用户登录</h3> <form action="" method="post"> {% csrf_token %} 用户名<input type="text" name="user"> 密码<input type="text" name="pwd"> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>你好, {{ request.user.username }}</h3> </body> </html>
一二一: 基于用户认证组件的注销功能
def logout(request): auth.logout(request) # 注销会删除session表中的记录 return redirect('/login/')
一二二: 基于用户认证组件的注册用户功能
122.1 关键代码
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth from django.contrib.auth.models import User # 导入用户表模块,对应数据库中的auth_user表 def reg(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') # create_user创建普通用户 # User.objects.create(username=user, password=pwd) 不能用create因为password是需要加密的 User.objects.create_user(username=user, password=pwd) # 写入用户信息到auth_user表中 return redirect('/login/') # 注册成功则跳转到登录页面 return render(request, 'reg.html')
122.2 项目完整代码
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth from django.contrib.auth.models import User # 导入用户表模块,对应数据库中的auth_user表 def login(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选 user = auth.authenticate(username=user, password=pwd) # 与表中记录进行验证(相当于fillter筛选) if user: # request.user=user就是当前登录对象,它是全局变量,可以在任意地方直接使用, 这里非常重要,将自动向session表添加记录. auth.login(request, user) # 如果没有登录,则是匿名对象. return redirect('/index/') return render(request, 'login.html') def index(request): print(request.user) # 打印当前用户对象, request.user是全局变量. print(request.user.username) # 打印当前用户 print(request.user.id) # 用户id,匿名用户是None print(request.user.is_anonymous) # 是否是匿名用户 # if not request.user.is_authenticated: # 判断该用户是否登录过, 和下面的一行,效果一样. if request.user.is_anonymous: # 如果是匿名用户(就是没有登录),则跳转到登录页面. return redirect('/login/') # username = request.user.username # 这一步可以省略了. return render(request, 'index.html') # 这里省略了向模板传递参数.因为request.user是全局变量,甚至可以直接用在模板中. # 如果没有登录,那么request.user显示匿名用户AnonymousUser def logout(request): auth.logout(request) # 注销会删除session表中的记录 return redirect('/login/') def reg(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') # create_user创建普通用户 # User.objects.create(username=user, password=pwd) 不能用create因为password是需要加密的 User.objects.create_user(username=user, password=pwd) # 写入用户信息到auth_user表中 return redirect('/login/') # 注册成功则跳转到登录页面 return render(request, 'reg.html')
"""authDemo URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), path('index/', views.index), path('logout/', views.logout), path('reg/', views.reg), ]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>注册</h3> <form action="" method="post"> {% csrf_token %} 用户名<input type="text" name="user"> 密码<input type="text" name="pwd"> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>用户登录</h3> <form action="" method="post"> {% csrf_token %} 用户名<input type="text" name="user"> 密码<input type="text" name="pwd"> <input type="submit"> </form> </body> </html>
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>你好, {{ request.user.username }}</h3> <a href="/logout/">注销</a> </body> </html>
112.3 修改密码
112.4 用户认证组件总结
用户认证组件最重要的API: from django.contrib import auth 1. # if 验证成功返回user对象,否则返回None. 注意这里的表里的password是加密文,所以有别与以前的表查询fillter筛选 user = auth.authenticate(username=user, password=pwd) 2. auth.login(request, user) # request.user:当前登录对象 3. auth.logout(request) # 注销会删除session表中的记录 from django.contrib.auth.models import User # User==auth_user 4. request.user.is_authenticated: # 判断该用户是否登录过 5. User.objects.create_user(username=user, password=pwd) # 写入用户信息到auth_user表中 补充: 匿名用户对象: 参考:https://www.cnblogs.com/yuanchenqi/articles/8876856.htmlni匿名用户 匿名用户 class models.AnonymousUser django.contrib.auth.models.AnonymousUser 类实现了django.contrib.auth.models.User 接口,但具有下面几个不同点: id 永远为None。 username 永远为空字符串。 get_username() 永远返回空字符串。 is_staff 和 is_superuser 永远为False。 is_active 永远为 False。 groups 和 user_permissions 永远为空。 is_anonymous() 返回True 而不是False。 is_authenticated() 返回False 而不是True。 set_password()、check_password()、save() 和delete() 引发 NotImplementedError。 New in Django 1.8: 新增 AnonymousUser.get_username() 以更好地模拟 django.contrib.auth.models.User。 总结: if not: auth.login(request, user) request.user == AnonymousUser() else:request.user==登录对象 request.user是一个全局变量,在任何视图和模板中直接使用
一二三: 基于用户认证组件的认证装饰器
123.1 关键代码
# settings.py中添加下面的常量 LOGIN_URL = '/login/' # 设置跳转的路径(设置认证装饰器时使用)
from django.contrib.auth.decorators import login_required # 认证装饰器 @login_required # 登录认证装饰器 def index(request): # print(request.user) # print(request.user.username) # print(request.user.id) # print(request.user.is_anonymous) # # if not request.user.is_authenticated: # 自己写的登录认证代码 # return redirect('/login/') return render(request, 'index.html') @login_required # 登录认证装饰器 def order(request): # 有了登录认证装饰器,就省去了,自己写认证代码. # if not request.user.is_authenticated: # 自己写的登录认证代码 # return redirect('/login/') return render(request, 'order.html')
def login(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') user = auth.authenticate(username=user, password=pwd) if user: auth.login(request, user) next_url = request.GET.get('next', '/index/') # 获取地址栏中next后面的路径, 注意看下图 return redirect(next_url) return render(request, 'login.html')
在地址栏输入http://127.0.0.1:8000/lorder/因为没有登陆,所以地址栏变成了http://127.0.0.1:8000/login/?next=/order/如下图.next=/order/的意思是登录后跳转到的网址
123.2 完整代码.注意setting.py中添加LOGIN_URL = '/login/' 模板文件基本未变.
from django.shortcuts import render, redirect, HttpResponse from django.contrib import auth from django.contrib.auth.models import User from django.contrib.auth.decorators import login_required # 认证装饰器 def login(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') user = auth.authenticate(username=user, password=pwd) if user: auth.login(request, user) next_url = request.GET.get('next', '/index/') # 获取地址栏中next后面的路径 return redirect(next_url) return render(request, 'login.html') @login_required # 登录认证装饰器 def index(request): # print(request.user) # print(request.user.username) # print(request.user.id) # print(request.user.is_anonymous) # # if not request.user.is_authenticated: # 自己写的登录认证代码 # return redirect('/login/') return render(request, 'index.html') def logout(request): auth.logout(request) # 注销会删除session表中的记录 return redirect('/login/') def reg(request): if request.method == "POST": user = request.POST.get('user') pwd = request.POST.get('pwd') # create_user创建普通用户 # User.objects.create(username=user, password=pwd) 不能用create因为password是需要加密的 User.objects.create_user(username=user, password=pwd) # 写入用户信息到auth_user表中 return redirect('/login/') # 注册成功则跳转到登录页面 return render(request, 'reg.html') @login_required # 登录认证装饰器 def order(request): # 有了登录认证装饰器,就省去了,自己写认证代码. # if not request.user.is_authenticated: # 自己写的登录认证代码 # return redirect('/login/') return render(request, 'order.html')
"""authDemo URL Configuration The `urlpatterns` list routes URLs to views. For more information please see: https://docs.djangoproject.com/en/3.1/topics/http/urls/ Examples: Function views 1. Add an import: from my_app import views 2. Add a URL to urlpatterns: path('', views.home, name='home') Class-based views 1. Add an import: from other_app.views import Home 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') Including another URLconf 1. Import the include() function: from django.urls import include, path 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) """ from django.contrib import admin from django.urls import path from app01 import views urlpatterns = [ path('admin/', admin.site.urls), path('login/', views.login), path('index/', views.index), path('logout/', views.logout), path('reg/', views.reg), path('order/', views.order), ]
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Title</title> </head> <body> <h3>订单中心</h3> </body> </html>
一二四: 中间件的实现流程
参考:https://www.cnblogs.com/yuanchenqi/articles/9036479.html
124.1 Django中默认的中间件, 在settings.py文件中. 中间件事全局的变量.
124.2 中间件的实现流程
一二五: 中间件的process_request和process_response方法
125. 1 中间件的实现流程
125.2 自定义中间件
在项目中新建自定义中间件文件名my_middlewares.py
关键代码:
# my_middlewares.py from django.utils.deprecation import MiddlewareMixin # 导入中间件类的父类 class CustomerMiddleware1(MiddlewareMixin): def process_request(self, request): # process_request方法是必须要有的, 其可以没有返回值.参数必须要有 print("CustomerMiddleware1 process_request") def process_response(self, request, response): # 注意它的参数,是必须要有两个的. print("CustomerMiddleware1 process_response") return response # 这里必须要有返回值 class CustomerMiddleware2(MiddlewareMixin): def process_request(self, request): # process_request方法是必须要有的, 其可以没有返回值.参数必须要有 print("CustomerMiddleware2 process_request") def process_response(self, request, response): # 注意它的参数,是必须要有两个的. print("CustomerMiddleware2 process_response") return response # 这里必须要有返回值
# views.py中新建了视图 def index_new(request): print('index_new') return HttpResponse('index_new')
在settings.py中把上面定义的my_middlewares.py中的两个类加入进去.
最终执行效果:再次体验一下中间件的执行过程.
一二六: 中间件之process_view方法
126.1 接上面.如果一个中间件的process_request有返回值,那么将,直接返回回去,下面的中间件不会再执行.如下图所示.
应用场景:比如某个用户没有登录,某个用户访问太过频繁.
class CustomerMiddleware1(MiddlewareMixin): def process_request(self, request): print("CustomerMiddleware1 process_request") return HttpResponse('CustomerMiddleware1 process_request的有返回值') # 这里增加返回值 def process_response(self, request, response): print("CustomerMiddleware1 process_response") return response
最终输出效果:
126.2 有了process_view后,的执行顺序,看下图.
# my_middlewares.py from django.utils.deprecation import MiddlewareMixin # 导入中间件类的父类 class CustomerMiddleware1(MiddlewareMixin): def process_request(self, request): # process_request方法是必须要有的, 其可以没有返回值.参数必须要有 print("CustomerMiddleware1 process_request") def process_response(self, request, response): # 注意它的参数,是必须要有两个的. print("CustomerMiddleware1 process_response") return response # 这里必须要有返回值 def process_view(self, request, callback, callback_ares, callback_kwargs): # 参数callback指的是本次路径对应的视图函数,最后面两个参数是视图函数的参数. 也就是说,视图函数可以在这里直接调出执行,而不需要再到视图中去执行. print("CustomerMiddleware1 process_view") class CustomerMiddleware2(MiddlewareMixin): def process_request(self, request): # process_request方法是必须要有的, 其可以没有返回值.参数必须要有 print("CustomerMiddleware2 process_request") def process_response(self, request, response): # 注意它的参数,是必须要有两个的. print("CustomerMiddleware2 process_response") return response # 这里必须要有返回值 def process_view(self, request, callback, callback_ares, callback_kwargs): print("CustomerMiddleware2 process_view")
执行效果:
126.3 process_view有返回值时
def process_view(self, request, callback, callback_ares, callback_kwargs): print("CustomerMiddleware2 process_view") # print(callback(callback_ares)) # 调用执行网址路径对应的视图函数 return HttpResponse("中间件执行process_view的返回值") # 这里有返回值,则后面的视图函数部分就不会执行了
一二七: 中间件之process_exception方法
当视图函数执行出错时,才执行该方法
def process_exception(self, request, exception): # 当视图函数执行出错的时候才执行这个.参数exception就是出错的提示.
print('CustomerMiddleware2 process_exception')
一二八: 中间件之应用
128.1 做IP访问频率限制
128.2 URL访问过滤
如果用户访问的是login视图(放过)
如果访问其他视图,需要检测是不是有session认证,已经有了放行,没有返回login,这样就省得在多个视图函数上写装饰器了!
用中间件全局一次对用户登录进行验证.就不需要对每一个视图函数加装饰器了.
# my_middlewares.py自定义中间件文件
from django.utils.deprecation import MiddlewareMixin from django.shortcuts import redirect from authDemo.settings import WHITE_LIST # 导入无需用户登录验证的白名单 class AuthMiddleware(MiddlewareMixin): # 用户登录验证中间件 def process_request(self, request): if request.path in WHITE_LIST: # 路径在白名单中则不需要验证 return None if not request.user.is_authenticated: # 是否登录过 return redirect("/login/")
# settings.py中的白名单 WHITE_LIST = ['/login/', '/reg/', '/logout/'] # 白名单中的路径将不会进行登录验证(中间件用)
# response.delete_cookie("cookie_key", path='/', domain=name) # 删除cookies的操作