Drf04 / drf request请求对象封装、版本、认证、权限

目录

  • Drf04 / drf request请求对象封装、版本、认证、权限

    • 回顾和补充
    • 今日详细
      • 1.请求的封装
      • 2.版本
      • 3.认证(面试)
      • 4.权限

Drf04 / drf request请求对象封装、版本、认证、权限

回顾和补充

  1. restful规范

    1. 建议用https代替http
    2. 在URL中体现api,添加api标识
     https://www.cnblogs.com/xwgblog/p/11812244.html   # 错误
     https://www.cnblogs.com/api/xwgblog/p/11812244.html  # 正确
     https://api.cnblogs.com/xwgblog/p/11812244.html # 正确
    
     建议:https://www.cnblogs.com/api/...
    3. 在URL中要体现版本
     https://www.cnblogs.com/api/v1/userinfo/
     https://www.cnblogs.com/api/v2/userinfo/
    4. 一般情况下对于api接口,用名词不用动词。
     https://www.cnblogs.com/api/v1/userinfo/
    5. 如果有条件的话,在URL后面进行传递。
     https://www.cnblogs.com/api/v1/userinfo/?page=1&category=2
    6. 根据method不同做不同操作
     get/post/put/patch/delete
  2. 类继承关系
    class View(object):
     def dipatch(self):
         print(123)
    
    class APIView(View):
     def dipatch(self):
         method = getattr(self,"get")
         return method()
    
    class GenericAPIView(APIView):
     queryset = None
     serilizer_class = None
     def get_queryset(self):
         return self.queryset
    
     def get_serilizer(self,*arg,**kwargs):
         cls = self.get_serilizer_class()
         return cls(*arg,**kwargs)
    
     def get_serilizer_class(self):
         return self.serilizer_class
    class ListModelMixin(object):
     def list(self):
         queryset = self.get_queryset()
         ser = self.get_serilizer(queryset,many=True)
         return Reponse(ser.data)
    
    class ListAPIView(ListModelMixin,GenericAPIView):
     def get(self):
         return self.list(...)
    
    class TagView(ListAPIView):
     queryset = models.User.object.all()
     serilizer_class = TagSerilizer
    
    obj = TagView()
    x = obj.dispatch()
    给用户返回x
  3. 继承关系
    class View(object):
     def dipatch(self):
         print(123)
    
    class APIView(View):
     version_class = settings.xxx
     parser_class = settings.sxx
     permision_classes = []
    
     def dipatch(self):
    
         self.initial()
    
         method = getattr(self,"get")
         return method()
    
     def initial(self):
         self.version_class()
         self.parser_class()
         for item in self.permision_classes:
             item()
    
    class GenericAPIView(APIView):
     queryset = None
     serilizer_class = None
     def get_queryset(self):
         return self.queryset
    
     def get_serilizer(self,*arg,**kwargs):
         cls = self.get_serilizer_class()
         return cls(*arg,**kwargs)
    
     def get_serilizer_class(self):
         return self.serilizer_class
    class ListModelMixin(object):
     def list(self):
         queryset = self.get_queryset()
         ser = self.get_serilizer(queryset,many=True)
         return Reponse(ser.data)
    
    class ListAPIView(ListModelMixin,GenericAPIView):
     def get(self):
         return self.list(...)
    
    class TagView(ListAPIView):
     queryset = models.User.object.all()
     serilizer_class = TagSerilizer
     version_class = URLPathClass
     parser_class = JSONParser
     permission_classes = [Foo,Bar ]
    
    obj = TagView()
    x = obj.dispatch()
    给用户返回x

今日详细

1.请求的封装

class HttpRequest(object):
    def __init__(self):
        pass

    @propery
    def GET(self):
        pass

    @propery
    def POST(self):
        pass

    @propery
    def body(self):
        pass

class Request(object):
    def __init__(self,request):
        self._request = request

    def data(self):
        if content-type == "application/json"
            reutrn json.loads(self._request.body.decode('urf-8'))
        elif content-type == "x-www-...":
            return self._request.POST

    def query_params(self):
        return self._reqeust.GET

req = HttpRequest()
request = Request(req)

request.data
request.query_prams
request._request.GET
request._request.POST
request._request.body

drf入口请求流程:

  • 路由

    urlpatterns = [
        url(r'^order/$', views.OrderView.as_view()),
    ]
  • 视图关系
    class View(object):
      @classonlymethod
        def as_view(cls, **initkwargs):
            def view(request, *args, **kwargs):
                return self.dispatch(request, *args, **kwargs)
            return view
    
    class APIView(View):
    
      @classmethod
        def as_view(cls, **initkwargs):
            view = super().as_view(**initkwargs)
            return csrf_exempt(view)
      def dispatch(self, request, *args, **kwargs):
            # 新request内部包含老request(_reuqest=老request)
            request = self.initialize_request(request, *args, **kwargs)
            self.request = request
    
            self.initial(request, *args, **kwargs)
    
            # 通过反射执行“get”方法,并传入新的request
            handler = getattr(self, request.method.lower())
            response = handler(request, *args, **kwargs) # get(requst)
            return self.response
    
    class OrderView(APIView):
    
        def get(self,request,*args,**kwargs):
            return Response('海狗')
    
    

2.版本

版本使用三步:

1.settings配置文件

REST_FRAMEWORK = {
    'DEFAULT_VERSIONING_CLASS':'rest_framework.versioning.URLPathVersioning',
    'ALLOWED_VERSIONS':['v1','v2'],
}

2.路由

路由分发
urlpatterns = [
    url(r'^api/(?P<version>\w+)/', include('api.urls')),
]
子路由
urlpatterns = [
    url(r'^order/$', views.OrderView.as_view()),
]

3.通过request.version可以取值

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

class OrderView(APIView):
    def get(self,request,*args,**kwargs):
        print(request.version)
        print(request.versioning_scheme)
        return Response('...')

    def post(self,request,*args,**kwargs):
        return Response('post')

源码流程:

class APIView(View):
    versioning_class = api_settings.DEFAULT_VERSIONING_CLASS

    def dispatch(self, request, *args, **kwargs):

        # ###################### 第一步 ###########################
        """
        request,是django的request,它的内部有:request.GET/request.POST/request.method
        args,kwargs是在路由中匹配到的参数,如:
            url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()),
            http://www.xxx.com/order/1/v2/
        """
        self.args = args
        self.kwargs = kwargs

        """
        request = 生成了一个新的request对象,此对象的内部封装了一些值。
        request = Request(request)
            - 内部封装了 _request = 老的request
        """
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request

        self.headers = self.default_response_headers  # deprecate?

        try:
            # ###################### 第二步 ###########################
            self.initial(request, *args, **kwargs)

            执行视图函数。。

    def initial(self, request, *args, **kwargs):

        # ############### 2.1 处理drf的版本 ##############
        version, scheme = self.determine_version(request, *args, **kwargs)
        request.version, request.versioning_scheme = version, scheme
        ...

    def determine_version(self, request, *args, **kwargs):
        if self.versioning_class is None:
            return (None, None)
        scheme = self.versioning_class() # obj = XXXXXXXXXXXX()
        return (scheme.determine_version(request, *args, **kwargs), scheme)

class OrderView(APIView):
    versioning_class = URLPathVersioning
    def get(self,request,*args,**kwargs):
        print(request.version)
        print(request.versioning_scheme)
        return Response('...')

    def post(self,request,*args,**kwargs):
        return Response('post')
class URLPathVersioning(BaseVersioning):
    """
    urlpatterns = [
        url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),

    ]
    """
    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

使用(局部)

  • url中写version

    url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
    
  • 在视图中应用
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.versioning import URLPathVersioning
    
    class OrderView(APIView):
    
        versioning_class = URLPathVersioning
        def get(self,request,*args,**kwargs):
            print(request.version)
            print(request.versioning_scheme)
            return Response('...')
    
        def post(self,request,*args,**kwargs):
            return Response('post')
    
  • 在settings中配置
    REST_FRAMEWORK = {
        "PAGE_SIZE":2,
        "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
        "ALLOWED_VERSIONS":['v1','v2'],
        'VERSION_PARAM':'version'
    }
    

使用(全局)推荐

  • url中写version

    url(r'^(?P<version>[v1|v2]+)/users/$', users_list, name='users-list'),
    
    url(r'^(?P<version>\w+)/users/$', users_list, name='users-list'),
    
  • 在视图中应用
    from rest_framework.views import APIView
    from rest_framework.response import Response
    from rest_framework.request import Request
    from rest_framework.versioning import URLPathVersioning
    
    class OrderView(APIView):
        def get(self,request,*args,**kwargs):
            print(request.version)
            print(request.versioning_scheme)
            return Response('...')
    
        def post(self,request,*args,**kwargs):
            return Response('post')
    
  • 在settings中配置
    REST_FRAMEWORK = {
        "PAGE_SIZE":2,
        "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
        "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
        "ALLOWED_VERSIONS":['v1','v2'],
        'VERSION_PARAM':'version'
    }
    

3.认证(面试)

from django.conf.urls import url,include
from django.contrib import admin
from . import views
urlpatterns = [
    url(r'^login/$', views.LoginView.as_view()),
    url(r'^order/$', views.OrderView.as_view()),
    url(r'^user/$', views.UserView.as_view()),
]

import uuid
from django.shortcuts import render
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from rest_framework.versioning import URLPathVersioning
from rest_framework.views import APIView
from rest_framework.response import Response

from . import models

class LoginView(APIView):

    def post(self,request,*args,**kwargs):
        user_object = models.UserInfo.objects.filter(**request.data).first()
        if not user_object:
            return Response('登录失败')
        random_string = str(uuid.uuid4())
        user_object.token = random_string
        user_object.save()
        return Response(random_string)

# 最好继承Base类有一个约束
class MyAuthentication:
    def authenticate(self, request):
        """
        Authenticate the request and return a two-tuple of (user, token).
        """
        token = request.query_params.get('token')
        user_object = models.UserInfo.objects.filter(token=token).first()
        if user_object:
            return (user_object,token)
        return (None,None)

class OrderView(APIView):
    authentication_classes = [MyAuthentication, ]
    def get(self,request,*args,**kwargs):
        print(request.user)
        print(request.auth)
        return Response('order')

class UserView(APIView):
    authentication_classes = [MyAuthentication,]
    def get(self,request,*args,**kwargs):
        print(request.user)
        print(request.auth)
        return Response('user')

源码分析

class Request:

    def __init__(self, request,authenticators=None):
        self._request = request
        self.authenticators = authenticators or ()

    @property
    def user(self):
        """
        Returns the user associated with the current request, as authenticated
        by the authentication classes provided to the request.
        """
        if not hasattr(self, '_user'):
            with wrap_attributeerrors():
                self._authenticate()
        return self._user

    def _authenticate(self):
        """
        Attempt to authenticate the request using each authentication instance
        in turn.
        """
        for authenticator in self.authenticators:
            try:
                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()

    @user.setter
    def user(self, value):
        """
        Sets the user on the current request. This is necessary to maintain
        compatibility with django.contrib.auth where the user property is
        set in the login and logout functions.

        Note that we also set the user on Django's underlying `HttpRequest`
        instance, ensuring that it is available to any middleware in the stack.
        """
        self._user = value
        self._request.user = value

class APIView(View):
    authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES

    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.
        """
        # ###################### 第一步 ###########################
        """
        request,是django的request,它的内部有:request.GET/request.POST/request.method
        args,kwargs是在路由中匹配到的参数,如:
            url(r'^order/(\d+)/(?P<version>\w+)/$', views.OrderView.as_view()),
            http://www.xxx.com/order/1/v2/
        """
        self.args = args
        self.kwargs = kwargs

        """
        request = 生成了一个新的request对象,此对象的内部封装了一些值。
        request = Request(request)
            - 内部封装了 _request = 老的request
            - 内部封装了 authenticators = [MyAuthentication(), ]
        """
        request = self.initialize_request(request, *args, **kwargs)
        self.request = request

    def initialize_request(self, request, *args, **kwargs):
        """
        Returns the initial request object.
        """
        parser_context = self.get_parser_context(request)

        return Request(
            request,
            parsers=self.get_parsers(),
            authenticators=self.get_authenticators(), # [MyAuthentication(),]
            negotiator=self.get_content_negotiator(),
            parser_context=parser_context
        )

    def get_authenticators(self):
        """
        Instantiates and returns the list of authenticators that this view can use.
        """
        return [ auth() for auth in self.authentication_classes ]

class LoginView(APIView):
    authentication_classes = []
    def post(self,request,*args,**kwargs):
        user_object = models.UserInfo.objects.filter(**request.data).first()
        if not user_object:
            return Response('登录失败')
        random_string = str(uuid.uuid4())
        user_object.token = random_string
        user_object.save()
        return Response(random_string)

class OrderView(APIView):
    # authentication_classes = [TokenAuthentication, ]
    def get(self,request,*args,**kwargs):
        print(request.user)
        print(request.auth)
        if request.user:
            return Response('order')
        return Response('滚')

class UserView(APIView):
    同上

总结

当用户发来请求时,找到认证的所有类并实例化成为对象列表,然后将对象列表封装到新的request对象中。

以后在视图中调用request.user

在内部会循环认证的对象列表,并执行每个对象的authenticate方法,该方法用于认证,他会返回两个值分别会赋值给
request.user/request.auth 

4.权限

from rest_framework.permissions import BasePermission
from rest_framework import exceptions

class MyPermission(BasePermission):
    message = {'code': 10001, 'error': '你没权限'}
    def has_permission(self, request, view):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        if request.user:
            return True

        # raise exceptions.PermissionDenied({'code': 10001, 'error': '你没权限'})
        return False

    def has_object_permission(self, request, view, obj):
        """
        Return `True` if permission is granted, `False` otherwise.
        """
        return False
class OrderView(APIView):
    permission_classes = [MyPermission,]
    def get(self,request,*args,**kwargs):
        return Response('order')

class UserView(APIView):
    permission_classes = [MyPermission, ]
    def get(self,request,*args,**kwargs):
        return Response('user')

REST_FRAMEWORK = {
    "PAGE_SIZE":2,
    "DEFAULT_PAGINATION_CLASS":"rest_framework.pagination.PageNumberPagination",
    "DEFAULT_VERSIONING_CLASS":"rest_framework.versioning.URLPathVersioning",
    "ALLOWED_VERSIONS":['v1','v2'],
    'VERSION_PARAM':'version',
    "DEFAULT_AUTHENTICATION_CLASSES":["kka.auth.TokenAuthentication",]
}

源码分析

class APIView(View):
    permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES

    def dispatch(self, request, *args, **kwargs):
        封装request对象
        self.initial(request, *args, **kwargs)
        通过反射执行视图中的方法

    def initial(self, request, *args, **kwargs):
        版本的处理
        # 认证
        self.perform_authentication(request)

        # 权限判断
        self.check_permissions(request)

        self.check_throttles(request)

    def perform_authentication(self, request):
        request.user

    def check_permissions(self, request):
        # [对象,对象,]
        for permission in self.get_permissions():
            if not permission.has_permission(request, self):
                self.permission_denied(request, message=getattr(permission, 'message', None))
    def permission_denied(self, request, message=None):
        if request.authenticators and not request.successful_authenticator:
            raise exceptions.NotAuthenticated()
        raise exceptions.PermissionDenied(detail=message)

    def get_permissions(self):
        return [permission() for permission in self.permission_classes]

class UserView(APIView):
    permission_classes = [MyPermission, ]

    def get(self,request,*args,**kwargs):
        return Response('user')

原文地址:https://www.cnblogs.com/liubing8/p/11827608.html

时间: 2024-07-31 09:56:38

Drf04 / drf request请求对象封装、版本、认证、权限的相关文章

Servlet的学习之Request请求对象(3)

本篇接上一篇,将Servlet中的HttpServletRequest对象获取RequestDispatcher对象后能进行的[转发]forward功能和[包含]include功能介绍完. 首先来看RequestDispatcher对象的“转发”功能: 在<Servlet的学习(五)>中说过,使用ServletContext对象的getRequestDispatcher方法可以获得转发对象RequestDispatcher对象,将请求进行转发给其他的Servlet或者JSP处理,同时在该篇的结

django 获取request请求对象及response响应对象中的各种属性值

1 django request对象和HttpResponse对象 2 HttpRequest对象(除非特殊说明,所有属性都是只读,session属性是个例外) 3 HttpRequest.scheme 请求方案(通常为http或https) 4 HttpRequest.body 字节字符串,表示原始http请求正文 5 HttpRequest.path 字符串,表示请求的页面的完整路径,不包含域名 6 7 HttpRequest.get_host() 获取主机地址 8 9 HttpReques

uniapp下uni.request请求的封装

//核心代码,需要使用vue.use全局注册,只需参照博主的封装axios // import {apiServer} from './../../common.js' class http { static request(url, params = {}, method = "POST", contentType = "application/x-www-form-urlencoded") { return new Promise((resolve, rejec

3-7 公共请求对象封装及优雅验证数据实现

这是提前准备好的接口文档 新建UserController 接收的参数用对象的形式 controller下新建vo的包,然后新建登陆接口需要的对象类LoginReqVO 下面这个时候就要写数据的验证了,一般都要几十行的验证代码. 提供另外一种方法 这个方法只能做一些基础的验证.因为没有办法注入逻辑层啊数据层啊这些.所以只能做一些公共的基础验证. 这样我们的loginVO继承BaserRequestVO然后去实现这个方法 这样你的controller里面这一行代码就去验证数据源的合法性 自定义ex

版本,认证,权限

版本 DRF中版本 导入 from rest_framework.versioning import 全局配置版本控制系统 /v1/books/    是在 URL加查询参数 # DRF的配置 REST_FRAMEWORK = { # 配置默认使用的版本控制类 'DEFAULT_VERSIONING_CLASS': 'rest_framework.versioning.URLPathVersioning', 'DEFAULT_VERSION': 'v1', # 默认的版本 'ALLOWED_VE

Request To JavaBean(请求对象转换为JavaBean对象)

一 参考资料 1 http://jc-dreaming.iteye.com/blog/563893 2 http://www.iteye.com/topic/76043 3 http://xubindehao.iteye.com/blog/754807 4 http://javafenger.iteye.com/blog/96829 5 http://www.kaila.com.cn/space.php?uid=7114&do=blog&id=458578 6 http://blog.cs

Django视图函数之request请求与response响应对象

官方文档: https://docs.djangoproject.com/en/1.11/ref/request-response/ 视图中的request请求对象: 当请求页面时,Django创建一个HttpRequest包含有关请求的元数据的对象. 常用的值和操作: ·         request.method      #获取请求属性 ·         request.GET         #获取GET请求的参数字典信息,用.get()取值 ·         request.PO

微信小程序request请求封装,验签

1/ 公共文件util添加 request请求 //简单封装请求 function request(params, path, isShowLoading = true, goBack = false, type = 'none', obj={}) { try { console.log(path) let NowTime = Date.parse(new Date()) / 1000; let defaultParams = { platform: app.globalData.platfor

请求对象&amp;响应对象

请求对象&响应对象WEB服务器会针对每一个客户端发出的HTTP请求,分别的创建一个请求对象和一个响应对象如果需要获取客户端提交的数据,需要使用请求对象如果需要向客户端发送一些数据,需要使用响应对象响应对象HttpServletResponse封装了向客户端发送数据,发送响应头,以及发送响应码等功能 请求对象HttpServletRequest请求对象封装了HTTP协议的请求行,请求头,请求体我们可以通过请求对象的方法来获取这些信息 获取请求行 StringBuffer getRequestURL