yyz notes yyz notes
首页
  • RBAC权限设计
  • 架构图标设计
  • 账号体系
  • python基础
  • python高级
  • python模块
  • python设计模式
  • python数据结构与算法
  • django
  • django-DRF
  • flask
  • 直接设计开源pip包
  • 直接设计开源项目
  • python示例题/脚本
  • python面试题
  • golang基础
  • golang高级
  • golang常用组件
  • gin框架
  • es6
  • javascript
  • react
  • vue
  • TypeScript
  • mysql
  • redis
  • minio
  • elasticsearch
  • mongodb
  • 消息队列
  • 自动化测试
  • 操作系统

    • linux
    • windows
  • nginx
  • docker
  • k8s
  • git
  • ldap
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)

益章

可乐鸡翅
首页
  • RBAC权限设计
  • 架构图标设计
  • 账号体系
  • python基础
  • python高级
  • python模块
  • python设计模式
  • python数据结构与算法
  • django
  • django-DRF
  • flask
  • 直接设计开源pip包
  • 直接设计开源项目
  • python示例题/脚本
  • python面试题
  • golang基础
  • golang高级
  • golang常用组件
  • gin框架
  • es6
  • javascript
  • react
  • vue
  • TypeScript
  • mysql
  • redis
  • minio
  • elasticsearch
  • mongodb
  • 消息队列
  • 自动化测试
  • 操作系统

    • linux
    • windows
  • nginx
  • docker
  • k8s
  • git
  • ldap
  • 学习
  • 面试
  • 心情杂货
  • 实用技巧
  • 友情链接
关于
收藏
  • 分类
  • 标签
  • 归档
GitHub (opens new window)
  • python基础

  • python高级

  • python模块

  • python设计模式

  • python数据结构与算法

  • django

  • django-DRF

    • win环境快速搭建drf项目
    • DRF介绍及快速使用
    • 序列化
    • DRF请求和响应
    • DRF类视图
    • 认证
    • 权限
    • 接口访问控制(限流)
    • 版本
      • 链接资料
      • 1. 版本控制介绍
      • 2. 自定义版本
        • 2.1 使用自带的版本
        • 注意
      • 3. 更多支持的版本处理方式
        • AcceptHeaderVersioning
        • URLPathVersioning(推荐使用)
        • NamespaceVersioning
        • HostNameVersioning
        • QueryParameterVersioning
        • 示例
      • 源码流程
    • 分页
    • 解析器
    • 自定义异常格式
    • 自定义响应格式
    • 过滤
    • 搜索
    • 排序
  • flask

  • 自己设计开源pip包

  • 自己设计开源项目

  • python小示例

  • python面试题

  • python
  • django-DRF
YiZhang-You
2023-05-20
目录

版本

# 链接资料

  1. 博客园

    8-1 版本-DRF版本 (opens new window)

# 1. 版本控制介绍

API版本控制允许我们在不同的客户端之间更改行为(同一个接口的不同版本会返回不同的数据)。DRF提供了许多不同的版本控制方案。可能会有一些客户端因为某些原因已经不再维护了,但是我们后端的接口还是要不断的更新迭代的,这个时候通过版本控制返回不同的内容就是一种不错的解决方案。

其实说白了,我访问的是同一个视图,但是由于不同的版本,返回的参数是不一样的。那这个是怎么控制的呐?来我们继续往下介绍。

主要是配置settings.py版本信息,然后在参考把版本信息是反正url,还是请求头.....哪里哪里。。

# 2. 自定义版本

自定义:
				http://127.0.0.1:8000/api/users/?version=v2
				
				class ParamVersion(object):
					def determine_version(self, request, *args, **kwargs):
						version = request.query_params.get('version')
						return version

				class UsersView(APIView):

					versioning_class = ParamVersion   # 注意这里是单个,不是列表了
					def get(self,request,*args,**kwargs):
						#version = request._request.GET.get('version')
						#print(version)
						# version = request.query_params.get('version')
						# print(version)

						print(request.version)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# 2.1 使用自带的版本

# 使用:

配置文件:
REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',  # 版本信息
    "DEFAULT_VERSION": 'v1',  # 默认版本号,默认值为None
    "ALLOWED_VERSIONS": ['v1', 'v2'],  # 允许请求的版本号,默认值为None
    "VERSION_PARAM": 'version',  # 识别版本号参数的名称,默认值为'version'
}

路由:
urlpatterns = [ # 主路由
    url(r'^api/', include('api.urls')),
]

urlpatterns = [
    # http://127.0.0.1:8000/api/v1/users/
    # http://127.0.0.1:8000/api/v2/users/
    url(r'^(?P<version>[v1|v2]+)/users/$', views.UsersView.as_view(),name='uuu'),
]
                    
# views.py                    
class UsersView(APIView):
    permission_classes = []

    def get(self, request, *args, **kwargs):
        # 1. 获取版本  v1
        print(request.version) 
        # 2. 获取处理版本的对象 <rest_framework.versioning.URLPathVersioning object at 0x000001C3AA7D3E10>
        print(request.versioning_scheme)  
        # 3. 反向生成URL(rest framework) http://127.0.0.1:8000/api/v1/users/
        u1 = request.versioning_scheme.reverse(viewname='uuu', request=request)
        print(u1)
        # 4. 反向生成URL /api/2/users/
        u2 = reverse(viewname='uuu', kwargs={'version': 2})
        print(u2)
        return HttpResponse('用户列表')
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

# 注意

在需要获取请求的版本号时,可以通过request.version来获取版本号。

默认版本功能未开启,request.version 返回None。

开启版本支持功能,需要在配置文件中设置DEFAULT_VERSIONING_CLASS

'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',  # 版本信息
1

其他可选配置:

  • DEFAULT_VERSION 默认版本号,默认值为None
  • ALLOWED_VERSIONS 允许请求的版本号,默认值为None
  • VERSION_PARAM 识别版本号参数的名称,默认值为'version'
request.version
request.versioning_scheme
request.versioning_scheme.reverse(viewname='uuu', request=request)
reverse(viewname='uuu', kwargs={'version': 2})
1
2
3
4

# 3. 更多支持的版本处理方式

# AcceptHeaderVersioning

请求头中传递的Accept携带version版本信息

GET /bookings/ HTTP/1.1
Host: example.com
Accept: application/json; version=1.0
1
2
3

# URLPathVersioning(推荐使用)

URL路径中携带版本信息

urlpatterns = [
    url( r'^(?P<version>(v1|v2))/bookings/$', bookings_list,name='bookings-list' ),
    url( r'^(?P<version>(v1|v2))/bookings/(?P<pk>[0-9]+)/$',bookings_detail,name='bookings-detail')
]
1
2
3
4

# NamespaceVersioning

命名空间中定义

# bookings/urls.py
urlpatterns = [
    url(r'^$', bookings_list, name='bookings-list'),
    url(r'^(?P<pk>[0-9]+)/$', bookings_detail, name='bookings-detail')
]

# urls.py
urlpatterns = [
    url(r'^v1/bookings/', include('bookings.urls', namespace='v1')),
    url(r'^v2/bookings/', include('bookings.urls', namespace='v2'))
]
1
2
3
4
5
6
7
8
9
10
11

# HostNameVersioning

主机域名携带 版本信息

GET /bookings/ HTTP/1.1
Host: v1.example.com
Accept: application/json
1
2
3

# QueryParameterVersioning

查询字符串携带 版本信息

GET /something/?version=0.1 HTTP/1.1
Host: example.com
Accept: application/json
1
2
3

# 示例

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.QueryParameterVersioning'
}

class BookInfoSerializer(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date', 'bread', 'bcomment')

class BookInfoSerializer2(serializers.ModelSerializer):
    """图书数据序列化器"""
    class Meta:
        model = BookInfo
        fields = ('id', 'btitle', 'bpub_date')

class BookDetailView(RetrieveAPIView):
    queryset = BookInfo.objects.all()

    def get_serializer_class(self):
        if self.request.version == '1.0':
            return BookInfoSerializer
        else:
            return BookInfoSerializer2

# 127.0.0.1:8000/books/2/
# 127.0.0.1:8000/books/2/?version=1.0
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27

# 源码流程

# 1.APIView下的dispatch方法
    def dispatch(self, request, *args, **kwargs):
        """
        `.dispatch()` is pretty much the same as Django's regular dispatch,
        but with extra hooks for startup, finalize, and exception handling.
        """
        self.args = args
        self.kwargs = kwargs
        # 获取的参数
        # 把获取的参数,经过initialize_request构建成新的request
        request = self.initialize_request(request, *args, **kwargs)  # 封装requert
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

        try:
            # 认证
            self.initial(request, *args, **kwargs)

            # Get the appropriate handler method
            if request.method.lower() in self.http_method_names:
                handler = getattr(self, request.method.lower(),
                                  self.http_method_not_allowed)
            else:
                handler = self.http_method_not_allowed

            response = handler(request, *args, **kwargs)

        except Exception as exc:
            response = self.handle_exception(exc)

        self.response = self.finalize_response(request, response, *args, **kwargs)
        return self.response
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
# 2. 进入认证self.initial(request, *args, **kwargs)
    def initial(self, request, *args, **kwargs):
        """
        Runs anything that needs to occur prior to calling the method handler.
        """
        self.format_kwarg = self.get_format_suffix(**kwargs)

        # Perform content negotiation and store the accepted info on the request
        neg = self.perform_content_negotiation(request)
        request.accepted_renderer, request.accepted_media_type = neg

        # Determine the API version, if versioning is in use.
        # 版本信息
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme

        # Ensure that the incoming request is permitted
        # 实现认证
        self.perform_authentication(request)
        # 权限判断
        self.check_permissions(request)
        # 限流
        self.check_throttles(request)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# 进入 self.determine_version(request, *args, **kwargs)
    def determine_version(self, request, *args, **kwargs):
        """
        If versioning is being used, then determine any API version for the
        incoming request. Returns a two-tuple of (version, versioning_scheme)
        """
        if self.versioning_class is None:
            return (None, None)
        scheme = self.versioning_class()  # 获取是那种的版本信息方式
        return (scheme.determine_version(request, *args, **kwargs), scheme)  # 重点是这个determine_version
1
2
3
4
5
6
7
8
9
10
编辑 (opens new window)
接口访问控制(限流)
分页

← 接口访问控制(限流) 分页→

最近更新
01
配置yun源
05-24
02
linux-配置python虚拟环境
05-24
03
linux文件目录管理
05-24
更多文章>
Theme by Vdoing | Copyright © 2023-2023 yizhang | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式