zoukankan      html  css  js  c++  java
  • Django rest framework(4) ---版本

    版本

     新建一个工程Myproject和一个app名为api

    (1)api/models.py

    复制代码
    from django.db import models
    
    class UserInfo(models.Model):
        USER_TYPE = (
            (1,'普通用户'),
            (2,'VIP'),
            (3,'SVIP')
        )
    
        user_type = models.IntegerField(choices=USER_TYPE)
        username = models.CharField(max_length=32,unique=True)
        password = models.CharField(max_length=64)
        group = models.ForeignKey('UserGroup',on_delete=models.CASCADE)
        roles = models.ManyToManyField('Role')
    
    
    class UserToken(models.Model):
        user = models.OneToOneField('UserInfo',on_delete=models.CASCADE)
        token = models.CharField(max_length=64)
    
    
    class UserGroup(models.Model):
        title = models.CharField(max_length=32)
    
    
    class Role(models.Model):
        title = models.CharField(max_length=32)
    复制代码

    (2)Myproject/urls.py

    复制代码
    from django.conf.urls import url,include
    from django.contrib import admin

    urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^api/', include('api.urls')),
    ]
    复制代码

    (3)api/urls.py

    复制代码
    # api/urls.py
    from django.conf.urls import url,include
    from django.contrib import admin

    from api.views import UserView
    urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    url(r'^users/', UserView.as_view()),
    ]
    复制代码

    (4)views.py

    复制代码
    # api/views.py
    
    from django.shortcuts import render,HttpResponse
    from rest_framework.views import APIView
    from rest_framework.request import Request
    from rest_framework.versioning import QueryParameterVersioning
    
    class UserView(APIView):
    
        versioning_class = QueryParameterVersioning
    
        def get(self,request,*args,**kwargs):
            #获取版本
            print(request.version)
            return HttpResponse('用户列表')
    复制代码

    (5)settings.py

    复制代码
    #版本
    REST_FRAMEWORK = {
        "DEFAULT_VERSION":'v1',               #默认的版本
        "ALLOWED_VERSIONS":['v1','v2'],       #允许的版本
        "VERSION_PARAM":'version'             #GET方式url中参数的名字  ?version=xxx
    }
    复制代码

     1.url中通过GET传参

    QueryParameterVersioning用于去GET参数中取version
    http://127.0.0.1:8000/api/users/?version=v2

    后台可以看到当前的版本

     

     如果url中没有传版本参数,则显示默认的版本("DEFAULT_VERSION":'v1')

    http://127.0.0.1:8000/api/users/

     如果url传的版本超过settings中的允许范围则报错

    http://127.0.0.1:8000/api/users/?version=v3

    2.在URLPATH中获取

     (1)修改api/urls.py

    通常情况我门应该用URLPATH的方式,而不是用前面GET()传参方式

    url里面通过正则表达式定义哪些版本,

    复制代码
    from django.conf.urls import url,include
    from django.contrib import admin

    from api.views import UserView
    urlpatterns = [
    # url(r'^admin/', admin.site.urls),
    # url(r'^users/', UserView.as_view()),
    url('(?P<version>[v1|v2]+)/users/', UserView.as_view()),
    ]

    (2)views.py

    URLPathVersioning:去url路径里面获取版本
    复制代码
    # api/views.py
    
    from django.shortcuts import render,HttpResponse
    from rest_framework.views import APIView
    from rest_framework.request import Request
    from rest_framework.versioning import URLPathVersioning
    
    class UserView(APIView):
    
        versioning_class = URLPathVersioning
    
        def get(self,request,*args,**kwargs):
            #获取版本
            print(request.version)
            return HttpResponse('用户列表')
    复制代码

    这个URLPathVersioning我们可以放到settings里面,全局配置,就不用写到views里面,每个类都要写一遍了

    settings.py

    复制代码
    # 版本
    # REST_FRAMEWORK = {
    #     "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    #     "DEFAULT_VERSION":'v1',               #默认的版本
    #     "ALLOWED_VERSIONS":['v1','v2'],       #允许的版本
    #     "VERSION_PARAM":'version'             #get方式url中参数的名字  ?version=xxx
    # }
    
    #全局
    REST_FRAMEWORK = {
        "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    }
    复制代码

    修改views.py

    复制代码
    # api/views.py
    
    from django.shortcuts import render,HttpResponse
    from rest_framework.views import APIView
    from rest_framework.request import Request
    
    class UserView(APIView):
    
        def get(self,request,*args,**kwargs):
            #获取版本
            print(request.version)
            return HttpResponse('用户列表')
    复制代码

     浏览器访问地址

    http://127.0.0.1:8000/api/v1/users/

    然后后台拿到版本信息

    3.反向解析访问的url

    1)api/urls.py

    添加name = 'api_user'

    复制代码
    # api/urls.py
    from django.conf.urls import url,include
    from django.contrib import admin

    from api.views import UserView
    urlpatterns = [
    url('(?P<version>[v1|v2]+)/users/', UserView.as_view(),name='api_user'),
    ]
    复制代码

    (2)views.py

    复制代码
    # api/views.py
    
    from django.shortcuts import render,HttpResponse
    from rest_framework.views import APIView
    from rest_framework.request import Request
    
    class UserView(APIView):
    
        def get(self,request,*args,**kwargs):
            #获取版本
            print(request.version)
            #获取处理版本的对象
            print(request.versioning_scheme)
            #获取浏览器访问的url,reverse反向解析
            #需要两个参数:viewname就是url中的别名,request=request是url中要传入的参数
            #(?P<version>[v1|v2]+)/users/,这里本来需要传version的参数,但是version包含在request里面(源码里面可以看到),所有只需要request=request就可以
            url_path = request.versioning_scheme.reverse(viewname='api_user',request=request)
            print(url_path)
            # self.dispatch
            return HttpResponse('用户列表')
    复制代码

     浏览器访问

    http://127.0.0.1:8000/api/v1/users/

    后台获取

    源码流程

     (1)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
            #对原始request进行加工,丰富了一些功能
            #Request(
            #     request,
            #     parsers=self.get_parsers(),
            #     authenticators=self.get_authenticators(),
            #     negotiator=self.get_content_negotiator(),
            #     parser_context=parser_context
            # )
            #request(原始request,[BasicAuthentications对象,])
            #获取原生request,request._request
            #获取认证类的对象,request.authticators
            #1.封装request
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
            self.headers = self.default_response_headers  # deprecate?
    
            try:
                #2.认证
                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
    复制代码

    (2)initial

    复制代码
        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.
            #request.version获取版本信息
            #request.versioning_scheme获取处理版本你的对象
            version, scheme = self.determine_version(request, *args, **kwargs)
            request.version, request.versioning_scheme = version, scheme
    
            # Ensure that the incoming request is permitted
            #4.实现认证
            self.perform_authentication(request)
            #5.权限判断
            self.check_permissions(request)
            #6.控制访问频率
            self.check_throttles(request)
    复制代码

    (3)determine_version

    复制代码
     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)
    复制代码

    (4)versioning_class

    URLPathVersioning源码

    复制代码
    class URLPathVersioning(BaseVersioning):
        """
        To the client this is the same style as `NamespaceVersioning`.
        The difference is in the backend - this implementation uses
        Django's URL keyword arguments to determine the version.
    
        An example URL conf for two views that accept two different versions.
    
        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')
        ]
    
        GET /1.0/something/ HTTP/1.1
        Host: example.com
        Accept: application/json
        """
        invalid_version_message = _('Invalid version in URL path.')
    
        def determine_version(self, request, *args, **kwargs):
            version = kwargs.get(self.version_param, self.default_version)
            if not self.is_allowed_version(version):
                raise exceptions.NotFound(self.invalid_version_message)
            return version
    
        def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
            if request.version is not None:
                kwargs = {} if (kwargs is None) else kwargs
                kwargs[self.version_param] = request.version
    
            return super(URLPathVersioning, self).reverse(
                viewname, args, kwargs, request, format, **extra
            )
    复制代码

     可以看到

    (1)url配置

    (2)determine_version

     里面有个is_allowed_version,点进去可以看到一些基本参数 (继承BaseVersioning基类)

    复制代码
    class BaseVersioning(object):
        #默认的版本
        default_version = api_settings.DEFAULT_VERSION
        #允许的版本
        allowed_versions = api_settings.ALLOWED_VERSIONS
        #默认参数(是version,比如你可以自定义为v)
        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))
  • 相关阅读:
    Java 简单算法--打印乘法口诀(只使用一次循环)
    Java简单算法--求100以内素数
    ubuntu 16.04 chrome flash player 过期
    java 网络API访问 web 站点
    java scoket (UDP通信模型)简易聊天室
    leetcode1105 Filling Bookcase Shelves
    leetcode1140 Stone Game II
    leetcode1186 Maximum Subarray Sum with One Deletion
    leetcode31 Next Permutation
    leetcode834 Sum of Distances in Tree
  • 原文地址:https://www.cnblogs.com/XLHIT/p/11629853.html
Copyright © 2011-2022 走看看