• DRF的版本、认证、权限


    DRF的版本

    版本控制是做什么用的, 我们为什么要用

    首先我们要知道我们的版本是干嘛用的呢~~大家都知道我们开发项目是有多个版本的~~

    当我们项目越来越更新~版本就越来越多~~我们不可能新的版本出了~以前旧的版本就不进行维护了~~~

    那我们就需要对版本进行控制~~这个DRF也给我们提供了一些封装好的版本控制方法~~

    版本控制怎么用

    之前我们学视图的时候知道APIView,也知道APIView返回View中的view函数,然后调用的dispatch方法~

    执行self.initial方法之前是各种赋值,包括request的重新封装赋值,下面是路由的分发,那我们看下这个方法都做了什么~~

    我们可以看到,我们的version版本信息赋值给了 request.version  版本控制方案赋值给了 request.versioning_scheme~~

    只是DRF默认的版本信息是None,我们需要重写一些配置,让request.version携带上我自定义的版本信息
    request.versioning_scheme是实现版本控制的类的实例化对象~

    详细用法

    a. 基于url的get传参方式

    如:/users?version=v1

    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    settings.py
    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'^test/', TestView.as_view(),name='test'),
    ]
    urls.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import QueryParameterVersioning
    
    
    class TestView(APIView):
        versioning_class = QueryParameterVersioning
    
        def get(self, request, *args, **kwargs):
    
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
    
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
    
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')
    
    views.py
    views.py

    b. 基于url的正则方式

    如:/v1/users/

    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    settings.py
    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'^(?P<version>[v1|v2]+)/test/', TestView.as_view(), name='test'),
    ]
    
    urls.py
    urls.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import URLPathVersioning
    
    
    class TestView(APIView):
        versioning_class = URLPathVersioning
    
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
    
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
    
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')
    
    views.py
    views.py

    c. 基于 accept 请求头方式

    如:Accept: application/json; version=1.0

    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',            # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],   # 允许的版本
        'VERSION_PARAM': 'version'          # URL中获取值的key
    }
    settings.py
    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'^test/', TestView.as_view(), name='test'),
    ]
    urls.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import AcceptHeaderVersioning
    
    
    class TestView(APIView):
        versioning_class = AcceptHeaderVersioning
    
        def get(self, request, *args, **kwargs):
            # 获取版本 HTTP_ACCEPT头
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
    
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')
    views.py

    d. 基于主机名方法

    如:v1.example.com

    ALLOWED_HOSTS = ['*']
    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',  # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
        'VERSION_PARAM': 'version'  # URL中获取值的key
    }
    settings.py
    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'^test/', TestView.as_view(), name='test'),
    ]
    urls.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import HostNameVersioning
    
    
    class TestView(APIView):
        versioning_class = HostNameVersioning
    
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
    
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')
    views.py

    e. 基于django路由系统的namespace

    如:example.com/v1/users/

    REST_FRAMEWORK = {
        'DEFAULT_VERSION': 'v1',  # 默认版本
        'ALLOWED_VERSIONS': ['v1', 'v2'],  # 允许的版本
        'VERSION_PARAM': 'version'  # URL中获取值的key
    }
    settings.py
    from django.conf.urls import url, include
    from web.views import TestView
    
    urlpatterns = [
        url(r'^v1/', ([
                          url(r'test/', TestView.as_view(), name='test'),
                      ], None, 'v1')),
        url(r'^v2/', ([
                          url(r'test/', TestView.as_view(), name='test'),
                      ], None, 'v2')),
    
    ]
    urls.py
    #!/usr/bin/env python
    # -*- coding:utf-8 -*-
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.versioning import NamespaceVersioning
    
    
    class TestView(APIView):
        versioning_class = NamespaceVersioning
    
        def get(self, request, *args, **kwargs):
            # 获取版本
            print(request.version)
            # 获取版本管理的类
            print(request.versioning_scheme)
            # 反向生成URL
            reverse_url = request.versioning_scheme.reverse('test', request=request)
            print(reverse_url)
    
            return Response('GET请求,响应内容')
    
        def post(self, request, *args, **kwargs):
            return Response('POST请求,响应内容')
    
        def put(self, request, *args, **kwargs):
            return Response('PUT请求,响应内容')
    views.py

    f. 全局使用

    REST_FRAMEWORK = {
        'DEFAULT_VERSIONING_CLASS':"rest_framework.versioning.URLPathVersioning",
        'DEFAULT_VERSION': 'v1',
        'ALLOWED_VERSIONS': ['v1', 'v2'],
        'VERSION_PARAM': 'version' 
    }
    settings.py

    DRF的versioning模块

    # 基础类
    class BaseVersioning(object):
        default_version = api_settings.DEFAULT_VERSION
        allowed_versions = api_settings.ALLOWED_VERSIONS
        version_param = api_settings.VERSION_PARAM
    
        def determine_version(self, request, *args, **kwargs):
            msg = '{cls}.determine_version() must be implemented.'
            raise NotImplementedError(msg.format(
                cls=self.__class__.__name__
            ))
    
        def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
            return _reverse(viewname, args, kwargs, request, format, **extra)
    
        def is_allowed_version(self, version):
            if not self.allowed_versions:
                return True
            return ((version is not None and version == self.default_version) or
                    (version in self.allowed_versions))
    
    
    # 在请求头中携带版本信息
    class AcceptHeaderVersioning(BaseVersioning):
        """
        GET /something/ HTTP/1.1
        Host: example.com
        Accept: application/json; version=1.0
        """
    
    
    # 在URL中携带版本信息
    class URLPathVersioning(BaseVersioning):
        '''
        urlpatterns = [
            url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
            url(r'^(?P<version>[v1|v2]+)/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
        ]
        '''
    
    
    # 在namespace中携带版本信息
    class NamespaceVersioning(BaseVersioning):
        '''
        # users/urls.py
        urlpatterns = [
            url(r'^/users/$', users_list, name='users-list'),
            url(r'^/users/(?P<pk>[0-9]+)/$', users_detail, name='users-detail')
        ]
    
        # urls.py
        urlpatterns = [
            url(r'^v1/', include('users.urls', namespace='v1')),
            url(r'^v2/', include('users.urls', namespace='v2'))
        ]
        '''
    
    
    # 在域名中携带版本信息
    class HostNameVersioning(BaseVersioning):
        """
        GET /something/ HTTP/1.1
        Host: v1.example.com
        Accept: application/json
        """
    
    
    # 在参数中携带版本信息
    class QueryParameterVersioning(BaseVersioning):
        """
        GET /something/?version=0.1 HTTP/1.1
        Host: example.com
        Accept: application/json
        """
    versioning模块

    DRF的认证

    上面讲版本的时候我们知道~在dispatch方法里~执行了initial方法~~那里初始化了我们的版本~~

    如果我们细心我们能看到~版本的下面其实就是我们的认证,权限,频率组件了~~

    我们先看看我们的认证组件~~

    我们进去我们的认证看下~~

    我们这个权限组件返回的是request.user,那我们这里的request是新的还是旧的呢~~

    我们的initial是在我们request重新赋值之后的~所以这里的request是新的~也就是Request类实例对象~~

    那这个user一定是一个静态方法~我们进去看看~~

    很明显,有传参

    我们通过上面基本可以知道我们的认证类一定要实现的方法~~以及返回值类型~~以及配置的参数authentication_classes~

    DRF的权限 

    权限是什么

    大家之前都应该听过权限~那么我们权限到底是做什么用的呢~~

    大家都有博客~或者去一些论坛~一定知道管理员这个角色~

    比如我们申请博客的时候~一定要向管理员申请~也就是说管理员会有一些特殊的权利~是我们没有的~~

    这些对某件事情决策的范围和程度~我们叫做权限~~权限是我们在项目开发中非常常用到的~~

    那我们看DRF框架给我们提供的权限组件都有哪些方法~~

    权限组件源码

    我们之前说过了DRF的版本和认证~也知道了权限和频率跟版本认证都是在initial方法里初始化的~~

    其实我们版本,认证,权限,频率控制走的源码流程大致相同~~大家也可以在源码里看到~~

    我们的权限类一定要有has_permission方法~否则就会抛出异常~~这也是框架给我提供的钩子~~

    我们先看到在rest_framework.permissions这个文件中~存放了框架给我们提供的所有权限的方法~~

    我这里就不带着大家详细去看每一个了~大家可以去浏览一下每个权限类~看看每个都是干嘛的~~

    这里主要说下BasePermission 这个是我们写权限类继承的一个基础权限类~~~ 

    认证权限的详细用法

     用户url传入的token认证

    from django.db import models
    
    # Create your models here.
    
    
    class User(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        token = models.UUIDField(null=True, blank=True)#随机字符串
        CHOICES = ((1, "vip"), (2, "普通用户"), (3, "vvip"))
        type = models.IntegerField(choices=CHOICES, default=2)
    DRFDemo/AuthDemo/models.py

    执行:makemigrations AuthDemo
    migrate AuthDemo

    from django.conf.urls import url, include
    from django.contrib import admin
    
    
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^book/', include("SerDemo.urls")),
        url(r'^api/user/', include("AuthDemo.urls")),
        url(r'^api/(?P<version>[v1|v2]+)/', include("VersionDemo.urls")),
    ]        
    DRFDemo/DRFDemo/urls.py
    from django.conf.urls import url, include
    from django.contrib import admin
    from .views import RegisterView, LoginView, TestView, PermissionView
    
    urlpatterns = [
        url(r'^register', RegisterView.as_view()),
        url(r'^login', LoginView.as_view()),
        url(r'^test', TestView.as_view()),
        url(r'^permission', PermissionView.as_view()),
    
    ]        
    DRFDemo/AuthDemo/urls.py
    from django.shortcuts import render
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from .models import User
    import uuid
    from utils.auth import MyAuth
    from utils.permission import MyPermission
    
    # Create your views here.
    
    
    class RegisterView(APIView):
        def post(self, request):
            name = request.data.get("name", "")
            pwd = request.data.get("pwd", "")
            if name and pwd:
                User.objects.create(name=name, pwd=pwd)
                return Response("注册成功")
            return Response("用户名或密码不合法")        
            
    class LoginView(APIView):
        def post(self, request):
            name = request.data.get("name", "")
            pwd = request.data.get("pwd", "")
            user_obj = User.objects.filter(name=name, pwd=pwd).first()
            if user_obj:
                # 登录成功 创建一个token并给前端返回
                token = uuid.uuid4()
                user_obj.token = token
                user_obj.save()
                return Response(token)
            return Response("用户名或密码错误")        
    
    class TestView(APIView):
        authentication_classes = [MyAuth, ]
    
        def get(self, request):
            print(request.user)
            print(request.user.name)
            print(request.auth)
            return Response("登录后发送的数据")
    
    
    class PermissionView(APIView):
        authentication_classes = [MyAuth, ]
        permission_classes = [MyPermission, ]
    
        def get(self, request):
            # 这个接口只能vip或者vvip访问
            return Response("权限测试接口")        
    DRFDemo/AuthDemo/views.py
    REST_FRAMEWORK = {
        # "DEFAULT_VERSIONING_CLASS": "utils.version.MyVersion",
        "DEFAULT_VERSIONING_CLASS": "rest_framework.versioning.URLPathVersioning",
        'DEFAULT_VERSION': "v1",
        'ALLOWED_VERSIONS': ["v1", "v2"],
        'VERSION_PARAM': 'version',
        # 配置认证类
        # "DEFAULT_AUTHENTICATION_CLASSES": ["utils.auth.MyAuth", ]
    }
    DRFDemo/DRFDemo/settings.py
    from rest_framework import permissions
    
    
    class MyPermission(permissions.BasePermission):
        message = "请充VIP,999一年"
    
        def has_permission(self, request, view):
            # 判断用户是否有权限
            if request.user.type in [1, 3]:
                return True
            return False        
            
    DRFDemo/utils/permission.py
    from django.db import models
    
    # Create your models here.
    
    
    class User(models.Model):
        name = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
        token = models.UUIDField(null=True, blank=True)
        CHOICES = ((1, "vip"), (2, "普通用户"), (3, "vvip"))
        type = models.IntegerField(choices=CHOICES, default=2)
    DRFDemo/AuthDemo/models.py
  • 相关阅读:
    快速启动jar包脚本【Linux】
    解决Linux报错:/bin/bash^M: 坏的解释器: 没有那个文件或目录
    学习——nginx(2021/09/23)
    react hook中的状态管理方式
    findDOMNode is deprecated in StrictMode. findDOMNode was passed an instance of DomWrapper which is inside StrictMode.
    祝胡老师节日快乐
    vue3+ts+AntV/L7加载钻取地图
    实用的 Bash 快捷键
    react antd form 自定义表单验证validator 需要注意的细节,否则会无法触发表单提交。
    execjs
  • 原文地址:https://www.cnblogs.com/yidashi110/p/10121583.html
Copyright © 2020-2023  润新知