Task5 Cookie与Session与token
众所周知,Cookie是我们进行请求的时候一个很常见的响应参数,它可以做到保持我们的状态信息等操作,也可以装载一些减轻应用负担的数据,(比如购物车) 注: Cookie不能跨浏览器,也不能跨域名
Cookie在Djangoz中可以用如下的方法:HttpReponse.set_cookie().其中涉及到如下属性的操作:
- key: value cookie肯定是以键值对的形式设置的嘛
- max_age: cookie的有效时长,单位s。 当指定为0时,默认关闭浏览器就失效。默认的有效值为100,100s后自动失效,如果未指定,Django默认最长的保存时间为2weeks
- expire: 可以指定过期时间,参数形式为datatime.datatimec对象
获取Cookie的方法: HttpRequest.COOKIEs.get() 删除Cookie HttpReponse.delete_cookies()
但是具体怎么传参我们还是先翻源码。虽说cookies是字典,但是不看源码不知道怎么传参啊
def set_cookie(self,key,value="",max_age=None,expires=None,path="/",domain=None,secure=False,httponly=False,
samesite=None,):
# 好的我们setcookies的值已经可以确定了,key和value都应该是数字或字符,value可以是数组但是一般没人那么设
self.cookies[key] = value
# 后面一些参数设置没放上来,自己去打开源码看一下嘛,很简单
好的,我们已经知道了基础的传参条件,那不就可以直接冲cookie了
def cookie_demo(request: HttpRequest):
cookie = {'name': 'Status404', 'sex': 'None', 'study': 'Django'}
reponse = HttpResponse('设置Cookie尝试')
max_age = 40
for a, b in cookie.items():
reponse.set_cookie(key=a, value=b, max_age=max_age)
return reponse
可以看到,我们第二次访问此网页的时候已经有了我们的Cookie了(name,sex,study)
在设置一个删除的demo:
def get_delete_cookie_demo(request: HttpRequest):
m = request.COOKIES.items()
print(m)
n = HttpResponse('hello')
n.delete_cookie('name')
return n
dict_items([*, ('name', 'Status404'), ('sex', 'None'), ('study', 'Django')])
[22/Mar/2022 12:56:56] "GET /son1/getcookie HTTP/1.1" 200 5
dict_items([*, ('sex', 'None'), ('study', 'Django')])
这里我们访问了一次,刷新了一次,可以看到第一次我们请求的时候获取Cookie还是有name的,之后请求结束时把他删了,第二次就没有这个cookie值了,删除成功。
Cookie中还可以设置一些我们验证的重要信息,比如Token, 比如Session等等。Session在task15里面有讲过。这里说一下session的匹配,因为session是请求头有一份,服务端自己也为了匹配存一份。**服务端的session在Django框架下存在django_session这张表下
session_key | session_data | expire_date |
---|---|---|
lno4horglc0… | .eJxVjs0Kw… | 2022-04-03 09:11:19.866505(没设置默认有效时间为两周后的日期) |
request.session.flush() # 清空数据库表session中的数据致使匹配失败
Task6 CBV初识
在之前我们在Django中定义视图的时候,一般采用的def, 也就是定义函数的方法定义视图。然而本着python万物皆对象的原则,我们应该能用类来完成的views的操作的。没错,基于类的视图函数的编写,我们就称其为CVB.
CVB通过继承,重写等相关特性实现业务功能。Django内置了很多的视图类(View) . 下面是一个demo
# views.py
from django.views import (View):
class Game(View):
@csrf_exempt
def get(self, request):
n = request
print('Got a Get request')
return HttpResponse('Got a Get request')
@csrf_exempt
def post(self, request):
return HttpResponse('Got a POST request')
@csrf_exempt
def put(self, request):
print('Got a a put request')
return HttpResponse('Got a PUT request')
@csrf_exempt
def delete(self, request):
print('Got a a delete request')
return HttpResponse('Got a DELETE request')
## urls.py
path('cvb/', Game.as_view())
之后咱们还是Get, POST , PUT , Delete全轰一边。不轰不知道,一轰吓一跳, 除了get, 其他完全挂了。。。。。。POST因为@csrf_exempt在视图类中没有作用直接403. 而PUT 和 Delete, 请求发出去了,请求方式也是对的,但是会和POST一样会403。同时更狗的是,我不知道为啥,它的选项变成了options) 属于是离大谱。没办法,继续debug吧
# 一个方便我们请求的demo
<a href="">Get请求</a>
<form method="post" action="">
<p><button type="submit">Post请求</button></p>
</form>
<p><button onclick="PUT_method()">PUT方法</button> </p>
<script>
function PUT_method() {
data2 = {
value:'This is a aPUT'
},
fetch('',{
method:'PUT',
headers:{
'Content_Type': "application/x-www-form-urlencoded"
},
body: JSON.stringify(data2)
}).then(response => response.text()).then(html => {document.write(html)})
}
</script>
<p><button onclick="Delete_method()">Delete方法</button> </p>
<script>
function Delete_method() {
data1 = {
value:'This is a aDelete'
},
fetch(',{
method:'DELETE',
headers:{
'Content_Type': "application/x-www-form-urlencoded"
},
body: JSON.stringify(data1)
}).then(response => response.text()).then(html => {document.write(html)})
}
</script>
</body>
**好吧,我知道为啥会给我强转OPTIONS了,我直接打开的HTML访问导致跨域了。**大家真的别像我一样傻逼操作了,放在同源位置,搞定。https://blog.youkuaiyun.com/k_runtu/article/details/80889797?utm_source=blogxgwz0
在没啥颁发的情况下,我们就可以首当其冲的去翻源码了。既然是Views的子类,自身集成了直接将request分成GET POST应该在父类中都有所体现
class View:
"""
Intentionally simple parent class for all views. Only implements
dispatch-by-method and simple sanity checking.
"""
# 首先映入眼前的这玩应直接说明他是可以接受put和delete请求的,但是我们的请求确实没接到,所以就冲吧
http_method_names = ["get","post","put","patch","delete","head","options","trace",]
def __init__(self, **kwargs):
"""
Constructor. Called in the URLconf; can contain helpful extra
keyword arguments, and other things.
"""
# Go through keyword arguments, and either save their values to our
# instance, or raise an error.
# 获取参数字典,把自己的属性一一设置为参数
for key, value in kwargs.items():
setattr(self, key, value)
# 很有缘的,我们直接看到了分发
# 这是分发请求到相应函数的方法
def dispatch(self, request, *args, **kwargs):
# Try to dispatch to the right method; if a method doesn't exist,
# defer to the error handler. Also defer to the error handler if the
# request method isn't on the approved list.
if request.method.lower() in self.http_method_names:
handler = getattr(
# 如果有method对应的方法直接调用,否则返回not allowed这个方法
self, request.method.lower(), self.http_method_not_allowed
)
else:
handler = self.http_method_not_allowed
return handler(request, *args, **kwargs)
好吧,我们这下子知道了这玩应的调用原理,先是父类的dispatch调用,之后调用我们写的函数,那么我们就有方法搞定CSRF了,直接重写dispthch()。反正他调用的也是dispatch, 直接在dispatch上面套上我们的@csrf_exempt。 我甚至想在源代码里把他改了。当然,还有最简单粗暴的删除中间件办法我就不搞了
其他具体的视图类就跟着链接玩玩就行了:https://blog.youkuaiyun.com/xujin0/article/details/84038778
Task7 了解Django中间件
中间件(Middleware) 是我们Django的核心工具之一,保证了WSGI层到我们上层HttpRequest的对象封装。之前使用CSRF就是中间件。
他的主要概念是AOP(面向切面编程,也就是钩子) 什么叫面向切面呢,就是在class的fuction执行前后去拦截(切面).Django的整体框架如下,红色的部分就是我们的钩子函数。
关于中间件的官方文档:https://docs.djangoproject.com/zh-hans/4.0/ref/middleware/
Django的中一共有五个钩子函数:
- process_request() 从Django框架到路由的过程
- process_view() 从urls路由到views视图函数的过程
- process_template_reponse() 在views视图函数中渲染模板的过程(不常用)
- process_exception() 从请求到相应的整个过程中,如果发生异常,会被此函数处理
- process_reponse() 从视图函数向Django响应数据,即返回HTTPResponse对象之后
如果我们要写中间件的话,就要了解中间件是咋写的。首先我们翻开的是Django.utils.deprecation 其中有一个中间件重要的类构成: MiddlewareMixin. Middlewaremixin会帮助我们调用自定义中间件的钩子函数。值得一提的是,钩子函数中的request请求对象不是HttpRequest, 而是WSGIRequest, 可以自己翻翻源码看看咋去搞
class MiddlewareMixin:
sync_capable = True
async_capable = True
# 当你的中间见被调用的时候, MiddlewareMixin会拿到你个请求对象(由Django对象给过来的),之后给你返回响应(get_reponse)
def __init__(self, get_response):
if get_response is None:
raise ValueError("get_response must be provided.")
self.get_response = get_response
self._async_check()
super().__init__()
# 输出的时候方便我们查看对象的值
def __repr__(self):
return "<%s get_response=%s>" % (
self.__class__.__qualname__,
getattr(
self.get_response,
"__qualname__",
self.get_response.__class__.__name__,
),
)
# 防止一个需要等待的请求占用了整个线程
def _async_check(self):
"""
If get_response is a coroutine function, turns us into async mode so
a thread is not consumed during a whole request.
"""
if asyncio.iscoroutinefunction(self.get_response):
# Mark the class as async-capable, but do the actual switch
# inside __call__ to avoid swapping out dunder methods
self._is_coroutine = asyncio.coroutines._is_coroutine
# 实施例对象变为可调用的方法,主要是示例一个response对象返回
def __call__(self, request):
# Exit out to async mode, if needed
if asyncio.iscoroutinefunction(self.get_response):
return self.__acall__(request)
response = None
# 如果有这两个勾子函数就执行,没有就pass
if hasattr(self, "process_request"):
response = self.process_request(request)
response = response or self.get_response(request)
if hasattr(self, "process_response"):
response = self.process_response(request, response)
return response
async def __acall__(self, request):
"""
Async version of __call__ that is swapped in when an async request
is running.
"""
response = None
if hasattr(self, "process_request"):
response = await sync_to_async(
self.process_request,
thread_sensitive=True,
)(request)
response = response or await self.get_response(request)
if hasattr(self, "process_response"):
response = await sync_to_async(
self.process_response,
thread_sensitive=True,
)(request, response)
return response
在了解了最基本的中间件构成组件,我们就可以简单写一个类装饰器中间件。一个中间件需要钩子函数,当然并不是5个钩子函数都需要。那我们开冲一个中间件demo:
# 中间件最好放在根目录下,可以实现登录状态的判断。
# 我的位置: middleware
# 检查是否是登陆的状态,但是写的不是很严谨
from django.core.handlers.wsgi import WSGIRequest
from django.http import HttpResponseRedirect
from django.shortcuts import redirect
from django.utils.deprecation import MiddlewareMixin
class CheckLogin(MiddlewareMixin):
def process_request(self, request):
# 从请求到urls过程,触发此函数
# 这里一定要有return 不然就会触发无线跳转
if not(request.path == '/son1/login/'):
if not request.COOKIES.get('name'):
print(request.COOKIES)
return HttpResponseRedirect('/son1/login/')
else:
return
else:
return
# def process_view(self, request):
# print('This is view middleware')
def process_expection(self, request):
print('This is exception middleware')
def process_response(self, request, reponse):
print('This is response middleware')
return reponse
Django中间件的存在让我们过滤一些规则的时候更加方便,可以用于权限验证,限制ip, 限制请求次数, 跨域请求, 写访问日志等等等等