zoukankan      html  css  js  c++  java
  • DRF源码刨析

    一、开发模式

    1、前后端不分离

    • 前后端放在一块写

    2、前后端分离

    • 2.1、前端开发

    • 2.2、后端开发

      • 为前端提供API开发
      • 永远返回HttpResponse

    二、Django-wsgi

    1、wsgi

    wsgi 备注
    wsgi 协议
    wsgiref 是实现了wsgi协议的一个模块,一个socket服务端 (django)
    werkzeug 是实现了wsgi协议的一个模块,一个socket服务端 (flask)
    tornado 是实现了wsgi协议的一个模块,一个socket服务端 (tornado)
    uwsgi 是实现了wsgi协议的一个模块,一个socket服务端

    三、Django FBV、 CBV

    1、FBV

    # 路由
    path('user/', view.users)
    
    # 视图
    def users(request):
        if request.method == 'GET':
            user_list = ['name': 'yiwen']
            return HttpResponse(json.dumps((user_list))) 
    

    2、CBV

    • 2.1、django中CBV是基于反射实现根据请求方式不同,执行不同的方法

    • 2.2、原理:

      • url ——> view方法 ——> dispatch方法(反射执行其他:GET/POST/DELETE/PUT/...)
    • 2.3、什么是反射

      • 它可以把字符串映射到实例的变量或者实例的方法然后可以去执行调用、修改等操作。它有四个重要的方法:

        方法 备注
        getattr 获取指定字符串名称的对象属性
        setattr 为对象设置一个对象
        hasattr 判断对象是否有对应的对象(字符串)
        delattr 删除指定属性
      • 反射详解见博客

    • 2.4、代码

      # 路由
      path('student/', views.LoginView.as_view(), name='student'),
      
      
      # 视图
      class BaseView(View):
          def dispatch(self, request, *args, **kwargs):
              print('hello')
              ret = super(BaseView, self).dispatch(request, *args, **kwargs)
              return ret
              
              
      class StudentsView(BaseView):
          def get(self, request):
              return HttpResponse('get')
      
          def post(self, request):
              return HttpResponse('post')
      
          def put(self, request):
              return HttpResponse('put')
      
          def delete(self, request):
              return HttpResponse('delete')
      

    四、django中间件

    适用于所有请求批量做操作
    	基于角色的权限控制
    	用户认证
    	csrf
    	session
    	日志
    

    1、中间件

    • process_request
    • process_view
    • process_response
    • process_exception
    • process_render_template

    2、django的csrf是如何实现的

    • process_view方法
      • 去请求体或cookie中获取token进行校验

    3、CBV中csrf中使用csrf_exempt装饰器

    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    from django.utils.decorators import method_decorator
    
    
    # 方式一
    @method_decorarot(csrf_exempt, name='dispatch')
    class StudentsView(View):
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
    
        def put(self, request):
            return HttpResponse('put')
    
        def delete(self, request):
            return HttpResponse('delete')
        
    
    # 方式二
    class StudentsView(View):
        
        @method_decorator(csrf_exempt)
        def dispatch(self, request, *args, **kwargs):
            ret = super(BaseView, self).dispatch(request, *args, **kwargs)
            return ret
        
        def get(self, request):
            return HttpResponse('get')
    
        def post(self, request):
            return HttpResponse('post')
    
        def put(self, request):
            return HttpResponse('put')
    
        def delete(self, request):
            return HttpResponse('delete')
    

    五、RESTFUL规范

    restful 10 规范

    规范 示例 备注
    协议 https://www.baidu.com/ API与用户的通信协议(通常使用https)
    域名 https://api.example.com或https://example.org/api/ 将API部署在专用域名之下或放在主域名下
    版本 https://api.example.com/v1/ 将API的版本号放入URL。
    路径 https://api.example.com/v1/user 路径又称"终点"(endpoint),表示API的具体网址
    HTTP动词 GET/POST/PUT/DELETE 对于资源的具体操作类型,由HTTP动词表示
    过滤信息 ?limit=10&offset=10&page=2&per_page=100 API应该提供参数,过滤返回结果
    状态码 200/201/204/401/404/403/500 服务器向用户返回的状态码和提示信息
    错误处理 {error: "Invalid API key" } 如果状态码是4xx,就应该向用户返回出错信息。一般来说,返回的信息中将error作为键名,出错信息作为键值即可。
    返回结果 GET /collection:返回资源对象的列表 针对不同操作,服务器向用户返回的结果遵循规范
    Hypermedia API {"link": { "rel": "collection https://www.example.com/zoos", "href": "https://api.example.com/zoos", "title": "List of zoos", "type": "application/vnd.yourformat+json" }} RESTful API最好做到Hypermedia,即返回结果中提供链接,连向其他API方法,使得用户不查文档,也知道下一步应该做什么

    1、根据method不同做不同的操作

    # 路由
    path('user/', views.UserView.as_view())
    
    # 视图
    class UserView(View):
        def get(self, request):
            return HttpResponse('获取')
    
        def post(self, request):
            return HttpResponse('创建')
    
        def put(self, request):
            return HttpResponse('更新')
    
        def delete(self, request):
            return HttpResponse('删除')
    

    六、Django Rest framework

    1、认证

    有些api需要认证才能访问
    
    • 1.1、认证流程原理

      • ①、dispatch()对原生request进行加工

        class APIView(View):
        
            permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
        	
            def dispatch(self, request, *args, **kwargs):
                self.args = args
                self.kwargs = kwargs
                # 对原生的request进行加工(丰富了一些功能)
                request = self.initialize_request(request, *args, **kwargs)
                self.request = request
                self.headers = self.default_response_headers  # deprecate?
        
                try:
                	# 认证
                    self.initial(request, *args, **kwargs)
        
                    # 反射
                    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)
                    
            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 get_authenticators(self):
                return [auth() for auth in self.authentication_classes]
        
      • ②、initial认证

        def initial(self, request, *args, **kwargs):
        	self.perform_authentication(request)
        
      • ③、调用request.user

        def perform_authentication(self, request):
            request.user
        
      • ④、request.py

        class Request:
        	
            @property
            def user(self):
                if not hasattr(self, '_user'):
                    with wrap_attributeerrors():
                        # 获取认证对象,进行进一步认证
                        self._authenticate()
                return self._user
        
      • ⑤、循环所有authenticatior对象

        def _authenticate(self):
            for authenticator in self.authenticators:
                try:
                    # 执行认证类的authenticate方法
                    # 1、如果authenticate方法抛出异常:self._not_authenticated()执行
                    # 2、成功,返回值必须是元组(request.user, request.auth)
                    # 3、返回None
                    user_auth_tuple = authenticator.authenticate(self)
                except exceptions.APIException:
                    self._not_authenticated()
                    raise
        
                    if user_auth_tuple is not None:
                        self._authenticator = authenticator
                        self.user, self.auth = user_auth_tuple
                        return
        
            self._not_authenticated()
        
      • ⑥、Authication认证类

        class Authication:
        	def authenticate(self, request):
        		token = request._request.Get.get('token')
        		token_obj = models.UserToken.objects.filter(token=token).first()
        		if not token_obj:
        			raise exceptions.AuthenticationFailed('用户认证失败')
        		return token_obj.user, token_obj
        	
        	def authenticate_header(self, request):
        		pass
        
      • ⑦、执行方法

        class UserView(APIView):
        	def get(self, request):
        		pass
        	
        	def post(...):
        		...
        
    • 1.2、认证类配置

      • ①、在CBV中配置

        class UserView(APIView):	
        	authentication_classes = [Xxx, Xzz]
        	def get(self, request):
        		pass
        	
        	def post(...):
        		...
        
      • ②、全局配置

        # setting.py
        
        REST_FRAMEWORK = {
        	"DEFAULT_AUTHENTICATION_CLASSES": ['类路径']
        }
        
    • 1.3、匿名用户

      # setting.py
      
      REST_FRAMEWORK = {
      	"DEFAULT_AUTHENTICATION_CLASSES": ['类路径'],
      	# request.user = None
      	# request.auth = None
      	"UNAUTHENTICATED_USER": None,
      	"UNAUTHENTICATED_TOKEN": None
      }
      
    • 1.4、内置认证类

      • ①、认证基类

        rest_framework.authentication.BaseAuthentication
        
        • 源码

          class BaseAuthentication:
              """
              All authentication classes should extend BaseAuthentication.
              所有认证类都应该继承于BaseAuthentication
              """
          
              def authenticate(self, request):
                  """
                  Authenticate the request and return a two-tuple of (user, token).
                  """
                  raise NotImplementedError(".authenticate() must be overridden.")
          
              def authenticate_header(self, request):
                  """
                  Return a string to be used as the value of the `WWW-Authenticate`
                  header in a `401 Unauthenticated` response, or `None` if the
                  authentication scheme should return `403 Permission Denied` responses.
                  """
                  pass
          
      • ②、其他认证类

        • 源码

          class BasicAuthentication(BaseAuthentication):
              """
              HTTP Basic authentication against username/password.
              """
              ...
          
          
          class SessionAuthentication(BaseAuthentication):
              """
              Use Django's session framework for authentication.
              """
              ...
              
          class TokenAuthentication(BaseAuthentication):
              """
              Simple token based authentication.
          
              Clients should authenticate by passing the token key in the "Authorization"
              HTTP header, prepended with the string "Token ".  For example:
          
                  Authorization: Token 401f7ac837da42b97f613d789819ff93537bee6a
              """
              ...
          
          
          
          class RemoteUserAuthentication(BaseAuthentication):
              """
              REMOTE_USER authentication.
          
              To use this, set up your web server to perform authentication, which will
              set the REMOTE_USER environment variable. You will need to have
              'django.contrib.auth.backends.RemoteUserBackend in your
              AUTHENTICATION_BACKENDS setting
              """
              ...
          
    • 1.5、总结

      • ①、使用

        • 创建类:继承BaseAuthentication

        • 实现authenticate方法

          返回值 备注
          None 下一认证来执行
          raise exceptions.AuthenticationFailed('用户认证失败') rest_framework.exceptions
          (元素一, 元素二) 元素一赋值给request.user, 元素二赋值给request.auth
      • ②、源码流程

        • dispatch

          • 封装request

            • 获取定义的认证类(全局/局部),通过列表生成式创建对象
          • inital

            • perform_authentication
              • request.user(内部循环...)

    2、权限

    不同的用户访问接口有不同的权限
    
    • 2.1、源码流程

      •   与认证类源码流程相似
        
        • dispatch
          • 封装request
          • inital
            • check_permissions
              • get_permissions获取定义的权限类(全局/局部),通过列表生成式创建对象
              • permission.has_permission(判断权限)
    • 2.2、权限内置类

      •   rest_framework.permissions.BasePermission
        
      • ①、内置基类

        • 源码

          class BasePermission(metaclass=BasePermissionMetaclass):
              """
              A base class from which all permission classes should inherit.
              """
          
              def has_permission(self, request, view):
                  """
                  Return `True` if permission is granted, `False` otherwise.
                  """
                  return True
          
              def has_object_permission(self, request, view, obj):
                  """
                  Return `True` if permission is granted, `False` otherwise.
                  """
                  return True
          
      • ②、其他权限类

        • 源码

          class AllowAny(BasePermission):
              """
              Allow any access.
              This isn't strictly required, since you could use an empty
              permission_classes list, but it's useful because it makes the intention
              more explicit.
              """
          
              def has_permission(self, request, view):
                  return True
          
          
          class IsAuthenticated(BasePermission):
              """
              Allows access only to authenticated users.
              """
          
              def has_permission(self, request, view):
                  return bool(request.user and request.user.is_authenticated)
          
          
          class IsAdminUser(BasePermission):
              """
              Allows access only to admin users.
              """
          
              def has_permission(self, request, view):
                  return bool(request.user and request.user.is_staff)
          
          
          class IsAuthenticatedOrReadOnly(BasePermission):
              """
              The request is authenticated as a user, or is a read-only request.
              """
          
              def has_permission(self, request, view):
                  return bool(
                      request.method in SAFE_METHODS or
                      request.user and
                      request.user.is_authenticated
                  )
          
    • 2.3、使用

      • 创建类: 继承BasePermission(rest_framework.permissions.BasePermission)

      • 实现 has_permission方法

        返回值 备注
        True 有权访问
        False 无权访问
      • 全局使用

        # settings.py
        
        REST_FRAMEWORK = {
        	"DEFAULT_PERMISSION_CLASSES": ["类路径"]
        }
        
      • 局部使用

        class UserView(APIView):	
        	permission_classes = [Xxx, Xzz]
        	def get(self, request):
        		pass
        	
        	def post(...):
        		...
        

    3、节流

    控制访问频率
    
    • 3.1、源码流程

      • dispatch
      • inital
        • check_throttles
          • get_throttles
          • throttle.allow_request方法
    • 3.2、内置类

      rest_framework.throtting.BaseThrottle
      
      • ①、基类源码

        class BaseThrottle:
            """
            Rate throttling of requests.
            """
        
            def allow_request(self, request, view):
                """
                Return `True` if the request should be allowed, `False` otherwise.
                """
                raise NotImplementedError('.allow_request() must be overridden')
        
            def get_ident(self, request):
                """
                Identify the machine making the request by parsing HTTP_X_FORWARDED_FOR
                if present and number of proxies is > 0. If not use all of
                HTTP_X_FORWARDED_FOR if it is available, if not use REMOTE_ADDR.
                """
                xff = request.META.get('HTTP_X_FORWARDED_FOR')
                remote_addr = request.META.get('REMOTE_ADDR')
                num_proxies = api_settings.NUM_PROXIES
        
                if num_proxies is not None:
                    if num_proxies == 0 or xff is None:
                        return remote_addr
                    addrs = xff.split(',')
                    client_addr = addrs[-min(num_proxies, len(addrs))]
                    return client_addr.strip()
        
                return ''.join(xff.split()) if xff else remote_addr
        
            def wait(self):
                """
                Optionally, return a recommended number of seconds to wait before
                the next request.
                """
                return None
        
        
        class SimpleRateThrottle(BaseThrottle):
            """
            A simple cache implementation, that only requires `.get_cache_key()`
            to be overridden.
        
            The rate (requests / seconds) is set by a `rate` attribute on the View
            class.  The attribute is a string of the form 'number_of_requests/period'.
        
            Period should be one of: ('s', 'sec', 'm', 'min', 'h', 'hour', 'd', 'day')
        
            Previous request information used for throttling is stored in the cache.
            """
            cache = default_cache
            timer = time.time
            cache_format = 'throttle_%(scope)s_%(ident)s'
            scope = None
            THROTTLE_RATES = api_settings.DEFAULT_THROTTLE_RATES
        
            def __init__(self):
                if not getattr(self, 'rate', None):
                    self.rate = self.get_rate()
                self.num_requests, self.duration = self.parse_rate(self.rate)
        
            def get_cache_key(self, request, view):
                """
                Should return a unique cache-key which can be used for throttling.
                Must be overridden.
        
                May return `None` if the request should not be throttled.
                """
                raise NotImplementedError('.get_cache_key() must be overridden')
        
            def get_rate(self):
                """
                Determine the string representation of the allowed request rate.
                """
                if not getattr(self, 'scope', None):
                    msg = ("You must set either `.scope` or `.rate` for '%s' throttle" %
                           self.__class__.__name__)
                    raise ImproperlyConfigured(msg)
        
                try:
                    return self.THROTTLE_RATES[self.scope]
                except KeyError:
                    msg = "No default throttle rate set for '%s' scope" % self.scope
                    raise ImproperlyConfigured(msg)
        
            def parse_rate(self, rate):
                """
                Given the request rate string, return a two tuple of:
                <allowed number of requests>, <period of time in seconds>
                """
                if rate is None:
                    return (None, None)
                num, period = rate.split('/')
                num_requests = int(num)
                duration = {'s': 1, 'm': 60, 'h': 3600, 'd': 86400}[period[0]]
                return (num_requests, duration)
        
            def allow_request(self, request, view):
                """
                Implement the check to see if the request should be throttled.
        
                On success calls `throttle_success`.
                On failure calls `throttle_failure`.
                """
                if self.rate is None:
                    return True
        
                self.key = self.get_cache_key(request, view)
                if self.key is None:
                    return True
        
                self.history = self.cache.get(self.key, [])
                self.now = self.timer()
        
                # Drop any requests from the history which have now passed the
                # throttle duration
                while self.history and self.history[-1] <= self.now - self.duration:
                    self.history.pop()
                if len(self.history) >= self.num_requests:
                    return self.throttle_failure()
                return self.throttle_success()
        
            def throttle_success(self):
                """
                Inserts the current request's timestamp along with the key
                into the cache.
                """
                self.history.insert(0, self.now)
                self.cache.set(self.key, self.history, self.duration)
                return True
        
            def throttle_failure(self):
                """
                Called when a request to the API has failed due to throttling.
                """
                return False
        
            def wait(self):
                """
                Returns the recommended next request time in seconds.
                """
                if self.history:
                    remaining_duration = self.duration - (self.now - self.history[-1])
                else:
                    remaining_duration = self.duration
        
                available_requests = self.num_requests - len(self.history) + 1
                if available_requests <= 0:
                    return None
        
                return remaining_duration / float(available_requests)
        
    • 3.3、使用

      • 创建类,继承BaseThrottle, 实现allow_reauest、 wait

      • 创建类, 继承SimpleRateThrottle, 实现get_cache_key、 scope(配置文件中的key)

      • 全局使用

        DEFAULT_THROTTLE_CLASSES = ['类路径']
        
      • 局部使用

        throttle_classes = [类]
        

    4、 版本

    • 4.1、全局使用

      # url路由配置
      path('meituan/<str:version>/', include('meituanapp.urls')),
      
      # settings配置
      REST_FRAMEWORK = {
          # 版本类
          'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning',
          # 默认版本
          'DEFAULT_VERSION': 'v1',
          # 允许使用的版本
          'ALLOWED_VERSIONS': ['v1', 'v2']
      }
      
    • 4.2、源码流程

      • dispatch

        • initial

          • determine_versuib

            返回值 request方法 备注
            scheme.determine_version(request, *args, **kwargs) request.version 获取当前版本
            scheme request.versioning_scheme 版本控制类对象
    • 4.3、request.versioning_scheme.reverse方法(路由反转)

      # 路由
          path('meituan/<str:version>/', include('serializeapp.urls', namespace='meituan')),
      	# seruakuzeapp.urls.py
      	path('good/', views.GoodView.as_view(), name='good'),
      
      
      # 视图
      class GoodView(APIView):
          def get(self, request, **kwargs):
              print(request.versioning_scheme.reverse(viewname='meituan:good', request=request))
              # http://127.0.0.1:8000/meituan/v1/good/
              print(reverse('meituan:good', kwargs={'version': 'v2'}))
              # /meituan/v2/good/
              return Response({'good': '111'})
      
    • 4.4、内置版本控制类

      • ①、基类

        class BaseVersioning:
            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
            """
            invalid_version_message = _('Invalid version in "Accept" header.')
        
            def determine_version(self, request, *args, **kwargs):
                media_type = _MediaType(request.accepted_media_type)
                version = media_type.params.get(self.version_param, self.default_version)
                version = unicode_http_header(version)
                if not self.is_allowed_version(version):
                    raise exceptions.NotAcceptable(self.invalid_version_message)
                return version
        
            # We don't need to implement `reverse`, as the versioning is based
            # on the `Accept` header, not on the request URL.
        
        
        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 = [
                re_path(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
                re_path(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 version is None:
                    version = 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().reverse(
                    viewname, args, kwargs, request, format, **extra
                )
        
        
        class NamespaceVersioning(BaseVersioning):
            """
            To the client this is the same style as `URLPathVersioning`.
            The difference is in the backend - this implementation uses
            Django's URL namespaces to determine the version.
        
            An example URL conf that is namespaced into two separate versions
        
            # users/urls.py
            urlpatterns = [
                path('/users/', users_list, name='users-list'),
                path('/users/<int:pk>/', users_detail, name='users-detail')
            ]
        
            # urls.py
            urlpatterns = [
                path('v1/', include('users.urls', namespace='v1')),
                path('v2/', include('users.urls', namespace='v2'))
            ]
        
            GET /1.0/something/ HTTP/1.1
            Host: example.com
            Accept: application/json
            """
            invalid_version_message = _('Invalid version in URL path. Does not match any version namespace.')
        
            def determine_version(self, request, *args, **kwargs):
                resolver_match = getattr(request, 'resolver_match', None)
                if resolver_match is None or not resolver_match.namespace:
                    return self.default_version
        
                # Allow for possibly nested namespaces.
                possible_versions = resolver_match.namespace.split(':')
                for version in possible_versions:
                    if self.is_allowed_version(version):
                        return version
                raise exceptions.NotFound(self.invalid_version_message)
        
            def reverse(self, viewname, args=None, kwargs=None, request=None, format=None, **extra):
                if request.version is not None:
                    viewname = self.get_versioned_viewname(viewname, request)
                return super().reverse(
                    viewname, args, kwargs, request, format, **extra
                )
        
            def get_versioned_viewname(self, viewname, request):
                return request.version + ':' + viewname
        
        
        class HostNameVersioning(BaseVersioning):
            """
            GET /something/ HTTP/1.1
            Host: v1.example.com
            Accept: application/json
            """
            hostname_regex = re.compile(r'^([a-zA-Z0-9]+).[a-zA-Z0-9]+.[a-zA-Z0-9]+$')
            invalid_version_message = _('Invalid version in hostname.')
        
            def determine_version(self, request, *args, **kwargs):
                hostname, separator, port = request.get_host().partition(':')
                match = self.hostname_regex.match(hostname)
                if not match:
                    return self.default_version
                version = match.group(1)
                if not self.is_allowed_version(version):
                    raise exceptions.NotFound(self.invalid_version_message)
                return version
        
            # We don't need to implement `reverse`, as the hostname will already be
            # preserved as part of the REST framework `reverse` implementation.
        
        
        class QueryParameterVersioning(BaseVersioning):
            """
            GET /something/?version=0.1 HTTP/1.1
            Host: example.com
            Accept: application/json
            """
            invalid_version_message = _('Invalid version in query parameter.')
        
            def determine_version(self, request, *args, **kwargs):
                version = request.query_params.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):
                url = super().reverse(
                    viewname, args, kwargs, request, format, **extra
                )
                if request.version is not None:
                    return replace_query_param(url, self.version_param, request.version)
                return url
        

    5、解析器

    6、序列化

    7、分页

    8、路由

    9、视图

    10、渲染器

    你的无畏来源于你的无知!

  • 相关阅读:
    汇编指令记录
    nginx源码剖析(3)nginx中的内存池
    STL中的vector
    Direct3D学习笔记
    委托的作用
    vs2010 快捷键大全
    Web Service学习笔记:什么是Web Service
    [Serializable]在C#中的作用NET 中的对象序列化
    .NET中反射机制的使用与分析
    什么时候用WebService
  • 原文地址:https://www.cnblogs.com/YiwenGG/p/14304222.html
Copyright © 2011-2022 走看看