DRF中的request

1. 前置面向对象知识点

  • 直接访问或利用反射
class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        return 123


obj = Foo("小三", 19)
# obj.name
# obj.age
# obj.show()

v1 = getattr(obj, 'show')
print(v1)
  • getattr
    • 当对象.一个不存在的成员时触发
class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        return 123

    def __getattr__(self, item):
        print("----->", item)
        return 999


obj = Foo("小三", 19)

# 不触发 __getattr
# obj.name
# obj.age
# obj.show()

# 触发 __getattr__ (不存在的成员)
# print(obj.xxx)
v2 = getattr(obj, "xxxx")
print(v2)
  • getattribute
    • 只要执行 对象.xxx都会执行__getattribute__
    • 父类object中的__getattribute__的处理机制
      • 对象中有值,返回
      • 对象中无值,报错
class Foo(object):
    def __init__(self, name, age):
        self.name = name
        self.age = age

    def show(self):
        return 123

    def __getattribute__(self, item):
        print("----->", item)
        return 999


obj = Foo("小三", 19)

print(obj.name)
print(obj.age)
print(obj.xxx)
  • 类分析
class HttpRequest(object):
    def __init__(self):
        pass

    def v1(self):
        print("v1")

    def v2(self):
        print("v2")


class Request(object):
    def __init__(self, req, xx):
        self._request = req
        self.xx = xx


req = HttpRequest()
req.v1()
req.v2()

request = Request(req, 111)
request._request.v1()
request._request.v2()
class HttpRequest(object):
    def __init__(self):
        pass

    def v1(self):
        print("v1")

    def v2(self):
        print("v2")


class Request(object):
    def __init__(self, req, xx):
        self._request = req
        self.xx = xx

    # 对象中无的成员,会触发
    def __getattr__(self, attr):
        # attr="v1"
        try:
            return getattr(self._request, attr)  # self._request.v1
        except AttributeError:
            return self.__getattribute__(attr)


req = HttpRequest()

request = Request(req, 111)
request.v1()
  • request的简单实现原理
class HttpRequest(object):
    def __init__(self):
        pass

    def method(self):
        print("v1")

    def path_info(self):
        print("v2")


class DrfRequest(object):
    def __init__(self, req, xx):
        self._request = req
        self.xx = xx

    def __getattr__(self, attr):
        try:
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)


request = HttpRequest()
request = DrfRequest(request, 123123)

# 普通写法
request._request.method
# 利用__getattr__和__getattribute__
request.method
request.path_info
# 报错
request.uuuu

2. 参数

  • 测试代码
from django.contrib import admin
from django.urls import path, re_path
from api import views

urlpatterns = [
    # path('admin/', admin.site.urls),
    # path('users/<str:version>/<int:pid>/', views.UserView.as_view()),
    # re_path('users/(\w+)/(\d+)/', views.UserView.as_view()),
    re_path('users/(?P<version>\w+)/(?P<pid>\d+)/', views.UserView.as_view()),
]
from rest_framework.views import APIView
from rest_framework.response import Response


class UserView(APIView):
    def get(self, request, version, pid):
        print(version, pid)
        print(self.kwargs)
        print(self.args)
        return Response("...")

3. 源码分析

  • 流程梳理-文字版
注意:下列调用方法的找寻路线遵循先UserView类,后APIView类,最后是View类,就不再详细赘述找寻过程

首先入口是路由中调用UserView类的as_View()方法,找到APIView类的as_view()方法,又调用View类的as_view()方法
View类的as_view()方法调用APIView类的dispatch方法
dispatch()方法调用initialize_request()方法,将django的request传给drf的Request类进行封装,self._request = request,并且定义了__getattr__方法,用于在drf的request中调用原生django的request
此时initialize_request()方法调用完毕,回到dispatch()方法
dispatch()获取请求方法,并调用,将结果一步步返回
  • 源代码分析-精简版
class APIView(View):
    def as_view(cls, **initkwargs):
        view = super().as_view(**initkwargs)
        return csrf_exempt(view)

    def initialize_request(self, request, *args, **kwargs):
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(),
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # request还是django中的request
        request = self.initialize_request(request, *args, **kwargs)
        # 此时的request时drf的request,request._request就是原生django的request
        # request._request.method
        # request.method  # __getattr__
        self.request = request
        self.headers = self.default_response_headers

        if request.method.lower() in self.http_method_names:
            # 获取get/post/put等方法
            handler = getattr(self, request.method.lower(),self.http_method_not_allowed)
        # 调用get/post等方法(UserView中)
        response = handler(request, *args, **kwargs)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response


class View:
    def as_view(cls, **initkwargs):
        def view(request, *args, **kwargs):
            return self.dispatch(request, *args, **kwargs)

        return view


class Request:
    def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        self._request = request

    def __getattr__(self, attr):

        try:
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)
        
        
class UserView(APIView):
    def get(self, request, version, pid):
        print(version, pid)
        print(self.kwargs)
        print(self.args)
        return Response("...")

4. request对象

drf中的request其实是对请求的再次封装,其目的就是在原来的request对象基础中再进行封装一些drf中需要用到的值

  • 测试代码
from django.contrib import admin
from django.urls import path, re_path
from api import views

urlpatterns = [
    # path('admin/', admin.site.urls),
    # path('users/<str:version>/<int:pid>/', views.UserView.as_view()),
    # re_path('users/(\w+)/(\d+)/', views.UserView.as_view()),
    re_path('users/(?P<version>\w+)/(?P<pid>\d+)/', views.UserView.as_view()),
]
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework.request import Request


class UserView(APIView):
    def get(self, request, version, pid):
        # drf的request对象
        print(request.query_params)
        print(request.data)
        print(request.auth)
        print(request.user)

        # django的request对象
        print(request.GET)
        print(request.method)
        print(request.path_info)
        return Response("...")
### 下载 Popper.min.js 文件的方法 对于希望获取 `popper.min.js` 的开发者来说,可以通过多种方式来实现这一目标。通常情况下,推荐通过官方渠道或可靠的分发网络 (CDN) 来获得最新的稳定版文件。 #### 使用 CDN 获取 Popper.min.js 最简单的方式之一是从流行的 CDN 中加载所需的 JavaScript 库。这不仅简化了集成过程,还可能提高性能,因为许多用户已经缓存了来自这些服务提供商的内容。例如: ```html <script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2/dist/umd/popper.min.js"></script> ``` 这种方式不需要手动下载文件到本地服务器;只需将上述 `<script>` 标签添加至 HTML 文档中的适当位置即可立即使用 Popper 功能[^1]。 #### 从 npm 或 yarn 安装 如果项目采用模块化构建工具链,则可以直接利用包管理器如 npm 或 Yarn 进行安装。命令如下所示: ```bash npm install @popperjs/core # 或者 yarn add @popperjs/core ``` 之后可以根据具体需求引入特定功能模块,而不是整个库,从而减少打包后的体积并优化加载速度[^2]。 #### 访问 GitHub 发布页面下载压缩包 另一种方法是访问 Popper.js 的 [GitHub Releases](https://github.com/popperjs/popper-core/releases) 页面,在这里可以选择不同版本的 tarball 或 zip 归档进行下载解压操作。这种方法适合那些偏好离线工作环境或是想要定制编译选项的人群[^3]。 #### 手动克隆仓库 最后一种较为少见但也可行的办法便是直接克隆完整的 Git 存储库副本。这样可以获得开发分支以及历史记录等更多信息,适用于贡献代码或者深入学习内部机制的情况。 ```bash git clone https://github.com/popperjs/popper-core.git cd popper-core ``` 完成以上任一途径后便能成功取得所需版本的 Popper.min.js 文件,并将其应用于个人项目之中[^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值