FRI.Django 中的装饰器及 Auth 模块
CBV 装饰器
添加装饰器的三种方式
No.1 Scheme 指名道姓
from django.views import View
from django.utils.decorators import method_decorator
class MyLogin(View):
@method_decorator(login_property)
def get(self, request):
return HttpResponse('get 请求')
No.2 Scheme
@method_decorator(login_property, name='get')
class MyLogin(View):
def get(self, request):
return HttpResponse('get 请求')
No.3 Scheme
class MyLogin(View):
@method_decorator(login_property)
def dispatch(self, request, *args, **kwargs):
pass
Django 中间件
Django中间件是 Django 的门户
1、请求来的时候需要经过中间件才能到达真正的 Django 后端
2、响应走的时候最后也需要经过中间件才能发送出去
Django 生命周期流程图
研究 Django 中间件代码规律
MIDDLEWARE = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
'django.middleware.common.CommonMiddleware',
'django.middleware.csrf.CsrfViewMiddleware',
'django.contrib.auth.middleware.AuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
]
自定义中间件
1、在项目名或者应用名下建一个文件夹
2、在文件中建一个 py 文件
3、写一个类,必须继承 MiddlewareMixin
4、将类的路径以字符串的形式注册到配置文件中才能生效
'''
Django 支持程序员自定义中间件并且暴露给程序员可以自定义的方法
掌握
- prpcess_request
-- 请求来的时候需要经过每一个中间件里面的 prpcess_request 方法
-- 在 Pycharm 中打印顺顺是按照配置文件中注册的中间件从上往下的顺序依次执行
-- 如果中间件里面没有定义该方法,则直接跳过
-- 如果该方法返回了 HttpResponse 对象,那么请求将不再继续往后执行,而是直接原路返回
该方法用来做全局相关的限制功能
- process_response
-- 响应走的时候需要结果每一个中间件里面的 process_response
-- 该方法必须返回一个 HttpResponse 对象
· 默认返回的就是形参 response
· 也可以自己返回自己的
-- 顺序是按照配置文件中注册了的中间件自下而上依次经过,如果没有定义的话,直接跳过执行下一个
'''
'''
了解
- process_view
-- 路由匹配成功之后,执行视图函数之前,会自动执行中间件里面的该方法
-- 顺序是按照配置文件中注册的中间件从上往下顺序依次执行
- process_template_response
-- 返回的 HttpResponse 对象有 render 属性的时候才会触发
-- 顺序是按照配置文件中注册的中间件从下往上依次执行
- process_exception
-- 当视图函数出现异常的情况下触发
-- 顺序是按照配置文件中注册了的中间件从上往下依次执行
'''
中间件执行顺序
process_request => 自上而下
process_request => 自下而上
'''
思考
如果在第一个 process_request 方法已经返回了 HttpResponse 对象,那么响应走的时候是经过所有的中间件里面的 process_response 还是直接返回?
直接通过同级别的 process_response 返回
'''
补充:
flask 框架也有一个中间件,但是两者略有差异
只要有数据返回,就必须经过所有中间件里面的类似于 process_response 方法
CSRF 跨站请求
'''
使用 csrf 跨站请求伪造校验防止钓鱼网站
网站在给用户返回一个具有提交数据功能页面的时候会给这个页面加一个唯一标识
当这个页面超后端发送 post 请求的时候,后端会先校验唯一表示,如果标识不合法会直接拒绝,如果合法则正常执行
'''
如何符合校验
form 表单提交符合校验
<form action="" method="post">
{% csrf_token %}
<p>username:<input type="text" name="username"></p>
<p>target_user:<input type="text" name="target_user"></p>
<p>money:<input type="text" name="money"></p>
<input type="submit">
</form>
Ajax 请求
3、引用自定义 js 文件
<script>
$('#btn').click(function () {
$.ajax({
url:'',
type:'post',
data:{"username": 'Jhin', "csrfmiddlewaretoken": $('[name=csrfmidllewaretoken]').val()},
{"username": 'Jhin', "csrfmiddlewaretoken": '{{ csrf_token }}'}
success:function (data) {
$('#d3').val(data)
}
})
})
</script>
CSRF装饰器
为什么要用装饰器
- 对所有函数进行按需分配,对不需要验证 CSRF 的函数添加 csrf_exempt,对需要验证 CSRF 的函数添加 csrf_protect
csrf_protect -- 需要校验
csrf_exempt -- 忽略校验
FBV 使用 CSRF 装饰器
@csrf_protect/csrf_exempt
def login(request):
if request.method == 'POST':
account = request.POST.get('account')
password = request.POST.get('password')
if account == 'Only' and password == '0310':
last_url = request.GET.get('next')
if last_url:
obj = redirect(last_url)
else:
obj = redirect('/model/')
obj.set_cookie('account', 'Just_you', max_age=20000)
return obj
return render(request, 'login.html')
CBV 使用 CSRF 装饰器
No.1 Scheme
class MyCsrfToken(View):
@method_decorator(csrf_protect)
def k2(self,request):
return HttpResponse('收到了宝贝')
@method_decorator(csrf_exempt)
def f1(self, request):
return HttpResponse('滚犊子')
No.2 Scheme
@method_decorator(csrf_protect, name='k2')
class MyCsrfToken(View):
def k2(self, request):
return HttpResponse('收到了宝贝')
def f1(self, request):
return HttpResponse('滚犊子')
No.3 Scheme
class MyCsrfToken(View):
@method_decorator(csrf_protect)
def dispatch(self, request, *args, **kwargs):
return super(MyCsrfToken, self).dispatch(request, *args, **kwargs)
class MyCsrfToken(View):
@method_decorator(csrf_exempt)
def dispatch(self, request, *args, **kwargs):
return super(MyCsrfToken, self).dispatch(request, *args, **kwargs)
Auth 模块
'''
其实在创建号 Django 项目之后直接执行数据库迁移命令会自动生成 auth_user
Django 在启动之后就可以直接访问 admin 路由,需要输入用户名和密码,数据参考的就是 auth_user 表,并且必须是管理员用户才能进入
'''
创建超级用户
python3 manage.py create superuser
依赖于 auth_user 表完成用户相关所有功能
from django.contrib import auth
from django.contrib.auth.decorators import login_required
def home(request):
if request.user.is_authenticated():
return redirect('/beauty/')
return redirect('/beauty/login/')
def register(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
User.objects.create_superuser(username=username, email='Roger@that.com', password=password)
return render(request, 'register.html')
def login(request):
if request.method == 'POST':
username = request.POST.get('username')
password = request.POST.get('password')
user_obj = auth.authenticate(request, username=username, password=password)
"""
1.自动查找 auth_user 表
2.自动给密码加密并比对
注意: 必须同时传入用户名和密码
"""
if user_obj:
auth.login(request, user_obj)
return render(request, 'login.html')
@login_required(login_url='/beauty/login/')
def set_pwd(request):
if request.method == 'POST':
raw_password = request.POST.get('raw_password')
new_password = request.POST.get('new_password')
confirm_password = request.POST.get('confirm_password')
is_right = request.user.check_password(raw_password)
if is_right:
if new_password == confirm_password:
request.user.set_password(confirm_password)
request.user.save()
return redirect('/beauty/')
return render(request, 'set_pwd.html', locals())
Auth_User 表扩展
1、一对一表关系,建立外键(不推荐)
class UserDetail(models.Model):
phone = models.BigIntegerField()
user = models.OneToOneField(to='User')
2、面向是对象继承
class UserInfo(AbstractUser):
phone = models.BigIntegerField()
'''
注意:
如果继承了 AbstractUser
那么在执行数据库迁移命令的时候 auth_user 表便不再被创建
而 UserInfo 表则会取代 auth_user 表并添加自定义字段
这能更加方便、快捷地完成表的操作及扩展
前提:
1、在继承之前不能执行过数据库迁移命令
继承要发生在 auth_user 表创建之前, 若 auth_user 表已创建, 则需要换一个库
2、继承的类里面不要覆盖 AbstractUser 自带的字段名
只要在原字段的基础上添加之外的字段名即可
3、需要在配置文件中声明使用 UserInfo 替代 auth_user
AUTH_USER_MODEL = '应用名.UserInfo'
'''