Django 规范化编程8

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_keysession_dataexpire_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.csdn.net/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.csdn.net/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, 限制请求次数, 跨域请求, 写访问日志等等等等

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值