首页 > 其他分享 >03请求数据封装request、版本管理

03请求数据封装request、版本管理

时间:2024-05-15 16:53:47浏览次数:25  
标签:__ 03 封装 self request ._ import data

请求数据封装request、版本管理

一、请求数据再封装

  • 以前我们通过django开发项目时,视图中的request是 django.core.handlers.wsgi.WSGIRequest 类的对象,其中包含了请求相关的所有数据。

  • 而在使用drf框架时,视图中的request是rest_framework.request.Request类的对象,其是又对django的request进行了一次封装,包含了除django原request对象以外,还包含其他后期会使用的其他对象。

from rest_framework.views import APIView
from rest_framework.response import Response


class UserView(APIView):
    def get(self, request, *args, **kwargs):
        # request,不再是django中的request,而是又被封装了一层,内部包含:django的request、认证、解析器等。
        return Response({"code": 1000, "data": "xxx"})

    def post(self, request, *args, **kwargs):
        return Response({"code": 1000, "data": "xxx"})
对象 = (request, 其他数据)
# rest_framework.request.Request 类
# Request类
class Request:
    """
    Wrapper allowing to enhance a standard `HttpRequest` instance.
    Kwargs:
        - request(HttpRequest). The original request instance. (django中的request)
        - parsers(list/tuple). The parsers to use for parsing the
          request content.
        - authenticators(list/tuple). The authenticators used to try
          authenticating the request's user.
    """

    def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):
    		self._request = request
        self.parsers = parsers or ()
        self.authenticators = authenticators or ()
        ...
	
    @property
    def query_params(self):
        """
        More semantically correct name for request.GET.
        """
        return self._request.GET

    @property
    def data(self):
        if not _hasattr(self, '_full_data'):
            self._load_data_and_files()
        return self._full_data
    
	def __getattr__(self, attr):
        try:
            return getattr(self._request, attr) # self._request.method
        except AttributeError:
            return self.__getattribute__(attr)

在使用drf框架开发时,视图中的request对象与原来的有些不同,例如

from rest_framework.views import APIView
from rest_framework.response import Response
from django.views import View
from rest_framework.request import Request


class UserView(APIView):
    def get(self, request, *args, **kwargs):
        
        # 通过对象的嵌套直接找到原request,读取相关值
        request._request.method
        request._request.GET
        request._request.POST
        request._request.body
        
        # 举例:
        	content-type: url-form-encoded
        	v1=123&v2=456&v3=999
            django一旦读取到这个请求头之后,就会按照 {"v1":123,"v2":456,"v3":999}
            
            content-type: application/json
            {"v1":123,"v2":456}
            request._request.POST
            request._request.body
        
        # 直接读取新request对象中的值,一般此处会对原始的数据进行一些处理,方便开发者在视图中使用。
        request.query_params  # 内部本质上就是request._request.GET
        request.data # 内部读取请求体中的数据,并进行处理,例如:请求者发来JSON格式,他的内部会对json字符串进行反序列化。
        
        # 通过 __getattr__ 去访问 request._request 中的值
        request.method
        
        

二、request对象分析,源码解析Request

# 分析APIVIew时,分析出,以后request都是新的request了,是drf提供的Request的对象
	from rest_framework.request import Request
    
    
# 源码解析之 __init__--->老的request在新的内部---》request._request:
	-先看 __init__--->类实例化得到对象时,对对象进行初始化,往对象中放数据
    def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None):
        # 传入的request是老的,django原生的request
        # 放到了self._request,self 是新的request类的对象
        self._request = request
        self._data = Empty
        self._files = Empty
    -什么时候调用的 __init__?
    	新的                                老的
    	-request = self.initialize_request(request, *args, **kwargs)
        				  老的
        	return Request(request)
        
        
# 以后用新的跟用老的一样,为什么?
	新的  requet.method
    新的   request.path
# 魔法方法:
	在类内部,以 __开头  __结尾的方法, 在某种情况下会自动调用,他们称之为魔法方法
    学过:__init__:  类名() 自动触发
          __str__:   print(对象)  自动触发
        
    还有哪些? 很多---》所有类都继承object类---》它都在object类中
    # 今天要学的 __getattr__ 
    	-对象.属性 ,属性不存在会触发
        
# 回头看  新的 requet.method用的时候,如果method不存在就会触发 Request类的 __getattr__
# 源码解析之 __getattr__
	-逻辑肯定是:从老的request中取出,你想要的东西
    
    def __getattr__(self, attr):
        try:
            # 通过反射,去老的中取,能取到就返回,取不到,执行except代码,再取不到就报错
            return getattr(self._request, attr)
        except AttributeError:
            return self.__getattribute__(attr)
        
        
        
# 以后新的request中多了个属性 data---》前端post,put提交的请求体中得数据,都会放在request.data中,无论何种编码格式,它都是字典




######## 总结
	-1 新的request中有老的requet, 在request._request
    -2 新的request 多了data属性,客户端提交的请求体中得数据,无论以那种方式编码,都在request.data中
    
    -3 其他的使用,跟之前老request一模一样
    	request.method
        request.path
        request.POST
        request.GET
        request.FILES
        。。。
        
# 总结:
	- 1 原生django--》post--》提交数据,只能处理urlencoded和form-data编码,从request.POST中取
    - 2 原生djagno--》put--》提交数据,处理不了,需要我们自己从body中取出来处理
    	-分不同编码格式:
        	urlencoded ---》name=lqz&age=19-->字符串切割
            json----》{"xxz":"xx","yyz":"yyy"}---》json.loads
            
   -3 原生django不能处理json提交的数据,需要自己做(put,post)
	 	json----》body中:{"xxz":"xx","yyz":"yyy"}---》json.loads
    
   -4 新的request解决了所有问题
		request.data
        

三、版本管理

在restful规范中要去,后端的API中需要体现版本。

drf框架中支持5种版本的设置。

【1】URL的GET参数传递(*)QueryParameterVersioning

  • views视图层
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
# 引入版本处理器类
from rest_framework.versioning import QueryParameterVersioning


class UserView(APIView):
  	# 此处声明版本处理器
    versioning_class = QueryParameterVersioning

    def get(self, request, *args, **kwargs):
        print(request.version)
        return Response({"code": 1000, "data": "xxx"})

    def post(self, request, *args, **kwargs):
        return Response({"code": 1000, "data": "xxx"})
  • settings配置文件配置drf相关配置以后编写在这里
REST_FRAMEWORK = {
  	# 以v=版本号形式传参
    "VERSION_PARAM": "v",
    # 不传版本号的话,默认为v1,DEFAULT_VERSION默认版本
    "DEFAULT_VERSION": "v1",
    # 允许的版本,版本不在其中drf会自动捕捉报错
    "ALLOWED_VERSIONS": ["v1", "v2", "v3"]	
  
  	# 设置全局版本处理器,后面跟上处理器路径
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.QueryParameterVersioning"
}

Not Found: /api/users/
[01/Apr/2024 01:17:33] "GET /api/users/?v=v4 HTTP/1.1" 404 6849

注意:

  • 单独某个视图类使用版本处理器,创建完视图类后直接声明处理器即可
  • 如果想所有视图类都使用版本处理器,就要在settings里设置全局版本处理起,这样就不需要在一个个视图类中声明处理器
  • 如果单独使用和全局使用混合在一起,单独使用的处理器会覆盖全局默认的处理器

源码执行流程:

image-20240401101159253

【2】URL路径传递版本参数(*)URLPathVersioning

  • views视图层
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
# 引入路径版本处理器
from rest_framework.versioning import QueryParameterVersioning, URLPathVersioning


class UserView(APIView):
		# 声明版本处理 URLPathVersioning
    versioning_class = URLPathVersioning

    def get(self, request, *args, **kwargs):
        print(request.version)
        return Response({"code": 1000, "data": "xxx"})

    def post(self, request, *args, **kwargs):
        return Response({"code": 1000, "data": "xxx"})

  • url层
from django.urls import path
from app01 import views
urlpatterns = [
  	# 此处用路径专户起可以取到路径版本参数值
    path('api/<str:version>/users/', views.UserView.as_view()),
]

  • settings
REST_FRAMEWORK = {
    "VERSION_PARAM": "version",
    # 不传版本号的话,默认为v1,DEFAULT_VERSION默认版本
    "DEFAULT_VERSION": "v1",
    # 允许的版本,版本不在其中drf会自动捕捉报错
    "ALLOWED_VERSIONS": ["v1", "v2", "v3"],

    # 设置全局版本处理起,后面跟上处理起路径
    "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning"
}

注意:

  • settings里的VERSION_PARAM的值一定要urls path里的路径转换器的值一样,不然取不到版本号

【3】请求头传递 AcceptHeaderVersioning

  • views视图类
from django.shortcuts import render
from rest_framework.response import Response
from rest_framework.views import APIView
# 引入请求头版本器AcceptHeaderVersioning
from rest_framework.versioning import QueryParameterVersioning, URLPathVersioning, AcceptHeaderVersioning


# Create your views here.


class UserView(APIView):
  	# 声明请求头版本器
    versioning_class = AcceptHeaderVersioning

    def get(self, request, *args, **kwargs):
        print(request.version)
        return Response({"code": 1000, "data": "xxx"})

    def post(self, request, *args, **kwargs):
        return Response({"code": 1000, "data": "xxx"})

  • urls层
from django.urls import path
from app01 import views
urlpatterns = [
    path('api/users/', views.UserView.as_view()),
]
  • postman中调用

反向生成URL

在每个版本处理的类中还定义了reverse方法,他是用来反向生成URL并携带相关的的版本信息用的,例如

标签:__,03,封装,self,request,._,import,data
From: https://www.cnblogs.com/Formerly/p/18194204

相关文章

  • index.js from Terser Error: error:0308010C:digital envelope routines::unsupporte
    Vue报错error:0308010C:digitalenveloperoutines::unsupported出现这个错误是因为node.jsV17版本中最近发布的OpenSSL3.0,而OpenSSL3.0对允许算法和密钥大小增加了严格的限制,可能会对生态系统造成一些影响.方法1.打开终端(按健win+R弹出窗口,键盘输入cmd,然后敲回车)并......
  • P8803 [蓝桥杯 2022 国 B] 费用报销
    P8803[蓝桥杯2022国B]费用报销一、问题简析本题是一道01背包。重点是\(K\)的限制,使我们在取\(a_i\)时,不能无所顾忌地套用模板\(dp_{i-1,j-a_i.worth}+a_i.worth\)。我们必须找到上一张合法的\(a_j\),即\(a_j\)与\(a_i\)之间的日期不小于\(K\)。通过以下步骤确......
  • Kubernetes - [03] 安装部署
    Kubeadm部署k8s集群  一、准备工作1.1、组件组件:Harbor(私有DockerHub)、Router服务器操作系统:Centos7+(内核3.0+,最好内核4.40+) 1.2、服务器主机名IP地址角色备注ctos79-01192.168.2.131master管理节点ctos79-02192.168.2.132worker ctos79-0......
  • C++封装dll(__cdecl和__stdcall)
    【1】使用__stdcall还需要添加def文件编译,使用工具DEPENDS.EXE打开dll文件成功。【2】使用__cdecl直接编译即可,不需要导入def文件......
  • P1044 [NOIP2003 普及组] 栈
    链接:https://www.luogu.com.cn/problem/P1044两种很好的思路:代码:#include<iostream>#include<vector>#include<algorithm>#include<math.h>#include<sstream>#include<string>#include<string.h>#include<iomanip>#incl......
  • 错误解决 TypeError: __init__() got an unexpected keyword argument 'size'import l
    TypeError:__init__()gotanunexpectedkeywordargument'size'importlogging代码段如下importloggingimportosfromgensim.modelsimportword2veclogging.basicConfig(format='%(asctime)s:%(levelname)s:%(message)s',level=logging.IN......
  • IceRPC之调用管道Invocation pipeline与传出请求Outgoing request->快乐的RPC
    作者引言.Net8.0下的新RPC很高兴啊,我们来到了IceRPC之调用管道Invocationpipeline与传出请求Outgoingrequest->快乐的RPC,基础引导,让自已不在迷茫,快乐的畅游世界。调用管道Invocationpipeline了解如何发送请求requests和接收响应responses。定义发送请求并接收......
  • 脚本库语法提示支持,Fast Request 2024.1.5 发布
    FastRequest 是一个类似于Postman的IDEA插件。它是一个强大的restfulapi工具包插件,可以根据已有的方法帮助您快速、自动生成url和params。RestfulFastRequest=API调试工具+API管理工具+API搜索工具。它有一个漂亮的界面来完成请求、检查服务器响应、存储......
  • ROS学习日记:(报错)terminate called after throwing an instance of 'rclcpp::excepti
    论坛里的一个老哥给出答案https://discourse.ros.org/t/how-to-shutdown-and-reinitialize-a-publisher-node-in-ros-2/4090就是我在初始化环境前先初始化了节点autonode=std::make_shared<Static_tf_broadcaster>(argv);rclcpp::init(argc,argv);rclcpp::spin(nod......
  • Structures Or Why Don't Things Fall Down (Reading)
    1BentmasonrycolumninSalisburyCathendral2Stressconcentrationatcracktip3'Aneurism'incylindricalballoon4Sectionofarterywalltissue5CorbelledvaultatTiryns6Simi-corbelledposterngateatTiryns7Clarebridge,Cambride(c......