インストールと使用のジャンゴ - restframework

ジャンゴ - restframework

まず、インストールと使用

インストール1.

>: pip3 install djangorestframework

2.

  • settings.pyに登録:

    INSTALLED_APPS = [   
        ....
        'api.apps.ApiConfig',
        # drf必须注册
        'rest_framework',
    ]
  • モジュール

    # drf的封装风格
    from rest_framework.views import APIView  # CBV
    from rest_framework.response import Response # 响应
    from rest_framework.request import Request # 请求
    from rest_framework.filters import SearchFilter # 过滤器
    from rest_framework.pagination import PageNumberPagination # 分页
    from rest_framework.exceptions import APIException # 异常
    from rest_framework.authentication import BaseAuthentication # 验证
    from rest_framework.permissions import IsAuthenticated # 组件
    from rest_framework.throttling import SimpleRateThrottle # 
    from rest_framework.settings import APISettings  # rest_framework配置文件
    from rest_framework import status # 状态码
    
    from django.http.request import QueryDict  # 类型
  • CBVはRSSTfulを満たすためのインタフェース仕様に基づいて完成します

二つは、要求分析を依頼します

2.1。要求データ要求

# views.py
from rest_framework.views import APIView
from rest_framework.response import Response
from django.http.request import QueryDict
class BookAPIView(APIView):

    def get(self, request, *args, **kwargs):
        print(request._request.GET)  # 原生wigs中值
        print(request.GET) # 二次封装的值
        print(request.META) # 所有get请求信息
        print(request.META.get("HTTP_AUTH")) # 前台发来的头都会大写并加上HTTP
        print(request.query_params) # 所有url数据
        
        print(request.POST) # get请求不能获取Post请求数据

        return Response('get ok')

    def post(self, request, *args, **kwargs):
        print(request._request.POST)  # 原生wigs中值
        print(request.POST) # 二次封装的值
        print(request.data) # 所有post请求数据
        print(request._request) # url数据包<WSGIRequest: POST '/books/?age=123'>
        print(request.GET) # POST请求可以Post请求数据
            
         # QueryDict转为
        print(request.query_params.dict())
        if isinstance(request.data, QueryDict):
            print(request.data.dict())

        return Response('post ok')
    
    
    
# urls.py
from . import views
urlpatterns = [
    url(r'^books/$', views.BookAPIView.as_view()),
]

IMG

要約:

  1. 要求はWSGIに基づいて、再び要求にカプセル化されたDRF
  2. WSGI DRFの属性の要求として要求、 _request
  3. 要求が新しいデータと完全に互換性行わWSGIの要求が直接WSGIを得ることができるDRF
  4. より多くの標準化データ分析の要求DRF、(URL?= 18歳)がquery_paramsに解決されているすべてのステッチのパラメータは、すべてのデータパケットは、データに解析されています
  5. query_paramsとデータ型のQueryDictに属しは、().dictによって辞書に変換することができます。

2.2リクエスト要求元コード解析

# 1. 2. urls.py
from . import views
urlpatterns = [
    url(r'^books/$', views.BookAPIView.as_view()),
]

#3.调用drf中的as_view
@classmethod
def as_view(cls, **initkwargs):     # cls 为 views.BookAPIView类
    ...
    view = super().as_view(**initkwargs) # as_view原生的as_view,super() 为 view
    view.cls = cls
    view.initkwargs = initkwargs

    return csrf_exempt(view)
# 4.进入dif中dispatch 
def dispatch(self, request, *args, **kwargs):   # self为views.BookAPIView类
    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)

        # 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
                
# 4.1 返回封装的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(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context
    )
# 5.Request类创建 self._request = request自己的属性
 def __init__(self, request, parsers=None, authenticators=None,
                 negotiator=None, parser_context=None):
        assert isinstance(request, HttpRequest), (
           
            .format(request.__class__.__module__, request.__class__.__name__)
        )

        self._request = request
        self.parsers = parsers or ()
        self.authenticators = authenticators or ()
        self.negotiator = negotiator or self._default_negotiator()
        self.parser_context = parser_context
        
#6.如何实现获取wgis中的属性
def __getattr__(self, attr):   
    """
        If an attribute does not exist on this instance, then we also attempt
        to proxy it to the underlying HttpRequest object.
        """
    try:
        return getattr(self._request, attr)
    except AttributeError:
        return self.__getattribute__(attr)

1574161117696

  1. クラスをAPIViewにDRFインポートし、作成し継承していることも、コンフィギュレーションのURLで: url(r'^books/$', views.BookAPIView.as_view()),
  2. as_viewプロジェクト開始()メソッドにDRF実行されるときにビュー方式(ローカル無効にCSRFの認定)を返し、URL:url(r'^books/$', views.BookAPIView.view
  3. ブラウザが返されたビューが実行中であるときに実行されるビュー関数への要求URLを送信しself.dispatch(request, *args, **kwargs)、発送はDRF発送です、発送はネイティブWSGIではありません
  4. :第二のパッケージのネイティブする最初の要求にディスパッチDRF request = self.initialize_request(request, *args, **kwargs)におけるinitialize_requestリターンオブジェクト要求プロセスのインスタンス
  5. 「self._request =要求」:リクエストにrequest.pyの方法は、その方法は、プロパティなるWSGI初期化要求時処理において見出されます
  6. 場合は、要求反射法によって得られたリクエストは、リクエストの属性をWSGI。まず_request検索プロパティではなく、チェック自体のを取得します。
  7. コア
    • 走drf的Request初始化方法__init__:self._request = request
    • drf的Request的getter方法__getattr__:先从self._request反射取属性,没取到再从drf的request中取

三、渲染模板

根据用户请求的RUL向服务器要响应的数据类型,比如:json数据,xml数据,将这些数据向用户返回

3.1渲染模板的使用

# 在renderers.py模板模块中导入你要渲染的模板
# JSONRenderer: 返回json数据
# BrowsableAPIRenderer: 返回浏览器html页面

from rest_framework.renderers import JSONRenderer, BrowsableAPIRenderer

# 1.局部配置
# 渲染模块的局部配置
# 局部禁用就是配置空list:[]  # pytthon3.7 有问题
renderer_classes = [JSONRenderer, BrowsableAPIRenderer]

# 2.全局配置
# drf的配置,在drf中settings.py查看如何配置
REST_FRAMEWORK = {
    # 渲染模块的全局配置:开发一般只配置json
    'DEFAULT_RENDERER_CLASSES': [
        'rest_framework.renderers.JSONRenderer',
        'rest_framework.renderers.TemplateHTMLRenderer',
    ],
   
}

1574164294714

3.2渲染模板的源码解析

# 1 对请求响应进行二次封装
def dispatch(self, request, *args, **kwargs):
    ....
    ....
    # 二次处理响应
    self.response = self.finalize_response(request, response, *args, **kwargs)
    return self.response

# 2. 接续配置的渲染类
def finalize_response(self, request, response, *args, **kwargs):

    if isinstance(response, Response):
        if not getattr(request, 'accepted_renderer', None):
            # 点进去,内部解析了配置的渲染的类
            neg = self.perform_content_negotiation(request, force=True)
            # 拿到渲染类对象
            request.accepted_renderer, request.accepted_media_type = neg
            
            response.accepted_renderer = request.accepted_renderer
            response.accepted_media_type = request.accepted_media_type
            response.renderer_context = self.get_renderer_context()

# 3. 获取渲染对象的类    
def perform_content_negotiation(self, request, force=False):
    """
        Determine which renderer and media type to use render the response.
        """
    # 点进去,获取配置的渲染类
    renderers = self.get_renderers()
    conneg = self.get_content_negotiator()
    try:
        return conneg.select_renderer(request, renderers, self.format_kwarg)
    except Exception:
        if force:
            return (renderers[0], renderers[0].media_type)
        raise

# 3 renderer_classes 自己全局
 def get_renderers(self):
        """
        Instantiates and returns the list of renderers that this view can use.
        """
        # 从自己的视图类找renderer_classer类属性(局部配置)APIView的类属性(从自己配置文件中找)> 自己的项目配置文件中找(全局配置), drf默认配置问价中找(默认配置)
        return [renderer() for renderer in self.renderer_classes]
    
class BaseRenderer:
    """
    All renderers should extend this class, setting the `media_type`
    and `format` attributes, and override the `.render()` method.
    """
    media_type = None
    format = None
    charset = 'utf-8'
    render_style = 'text'

    def render(self, data, accepted_media_type=None, renderer_context=None):
        raise NotImplementedError('Renderer class requires .render() to be implemented')

总结:

  1. 根据流程,再次进入drf的dispatch方法,该方法对响应数据进行了二次封装,然后,进入self.finalize_response方法
  2. 在self.finalize_respons方法中perform_content_negotiation中获取渲染的对象结果,进入perform_content_negotiation方法
  3. perform_content_negotiation方法中实现了获取配置文件的渲染结果集,通过self.get_renderers()方法
  4. 在self.get_renderers()方法中self.renderer_classes读取配置的渲染对象,先从创建的视图类中(BookAPIView(APIView)(局部配置))找,然后在从自己的项目文件中找(项目中 settings.py,全局配置), 最后从drf默认配置文件中(默认配置)
  5. renderer()是从配置文件中获取到的对应类然后到 renderer.py 文件中获取类对象,创建的类对象(JSONRenderer())

四、解析模块的使用

服务器根据设置的请求头content-type接收客户端对应的数据信息

# JSONParser: 只接收json数据
# FormParser: 只接收urlencoded
# MultiPartParser:只接收form-data
from rest_framework.parsers import JSONParser, FormParser, MultiPartParser

# 1.局部配置
# 解析模块的局部配置
#局部配置禁用就是配置空list[]
parser_classes = [JSONParser, MultiPartParser, FormParser]

# 2.全局配置
# drf的配置,在drf中settings.py查看如何配置
REST_FRAMEWORK = {   
    # 解析模块的全局配置
    'DEFAULT_PARSER_CLASSES': [
        'rest_framework.parsers.JSONParser',
        'rest_framework.parsers.FormParser',
        'rest_framework.parsers.MultiPartParser'
    ]
}

1574167139160

# 1.对数据进行二次解析
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 = self.initialize_request(request, *args, **kwargs)
    ...
    
# 2 获取解析数据
def initialize_request(self, request, *args, **kwargs):
    """
        Returns the initial request object.
        """
    # 准备要解析的字典
    parser_context = self.get_parser_context(request)

    return Request(
        # 初始wigs中request
        request, 
        # 解析模块在封装原生request是,将数据一并解析
        parsers=self.get_parsers(), 
        authenticators=self.get_authenticators(),
        negotiator=self.get_content_negotiator(),
        parser_context=parser_context # 解析的内容
    )
    
# 2.1 返回要解析内容字典
def get_parser_context(self, http_request):
    """
        Returns a dict that is passed through to Parser.parse(),
        as the `parser_context` keyword argument.
        """
    # Note: Additionally `request` and `encoding` will also be added
    #       to the context by the Request object.
    return {
        'view': self,
        'args': getattr(self, 'args', ()),
        'kwargs': getattr(self, 'kwargs', {})
    }

# 3 获取要解析的对象
def get_parsers(self):
    """
     Instantiates and returns the list of parsers that this view can use.
     """
    return [parser() for parser in self.parser_classes]

class BaseParser:  
    media_type = None
    def parse(self, stream, media_type=None, parser_context=None):      
        raise NotImplementedError(".parse() must be overridden.")

总结:

  1. 根据流程,再次进入drf的dispatch方法,该方法对响应数据进行了二次封装同时也对数据进行了二次解析,然后,进入 request = self.initialize_request(request, *args, **kwargs)方法
  2. 在 self.initialize_request方法中通过self.get_parser_context(request)方法,获取要解析的数据,get_parser_context(self, http_request):方法返回解析的数据字典返回
  3. 在Request类中调用get_parsers(self)方法获取解析的对象,解析的随想先从创建的视图类中(BookAPIView(APIView)(局部配置))找,然后在从自己的项目文件中找(项目中 settings.py,全局配置), 最后从drf默认配置文件中(默认配置),实现数据的解析
  4. 只有在后台设置了解析的数据,才会给前台正确的响应否则报错

五、异常模块的使用

重写异常模块的目的是记录异常信息(日志记录)

5.1异常模块的使用

# 1. 配置异常模块,通过settings.py获取
REST_FRAMEWORK = {  
    # 异常模块配置
    # Exception handling
    # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler', # 默认
    'EXCEPTION_HANDLER': 'api.utils.exception_handler', # 自己重写的路径
    'NON_FIELD_ERRORS_KEY': 'non_field_errors',

}

# 2.编写异常模块,创建一个新的文件.py重写exception_handler方法
from rest_framework.response import Response
def exception_handler(exc, context):
    # 在exception_handler函数完成异常信息的返回以及异常信息的logging日志
    print(exc)
    print(context)
    print(type(exc))
    # exc.detail 携带错误的信息
    return Response(f'{context["view"].__class__.__name__}{exc}')

# 2.2升级版
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler

def exception_handler(exc, context):
    response = drf_exception_handler(exc, context)
    if response is None:  # drf没有处理的异常

        response = Response({"detail": f'{context["view"].__class__.__name__}{exc}'})
    # 项目阶段,将日志记录保存到文件中
    return response

# 2.3终极版
from rest_framework.response import Response
from rest_framework.views import exception_handler as drf_exception_handler
from rest_framework import status


def exception_handler(exc, context):
    response = drf_exception_handler(exc, context)
    if response is None:  # drf没有处理的异常

        response = Response(data={
            'status': 7,
            "detail": f'{context["view"].__class__.__name__}{exc}',
        },
                            status=status.HTTP_500_INTERNAL_SERVER_ERROR)
    response = Response(status=response.status_code, data={
        'status': 7,
        "detail": f'{response.data.get("detail")}',
    })
    # 项目阶段,将日志记录保存到文件中
    return response

5.2异常源码分析

 # 1. 异常出错
    def dispatch(self, request, *args, **kwargs):      
        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

# 2 异常处理
def handle_exception(self, exc):
    """
        Handle any exception that occurs, by returning an appropriate response,
        or re-raising the error.
        """
    if isinstance(exc, (exceptions.NotAuthenticated,
                        exceptions.AuthenticationFailed)):
        # WWW-Authenticate header for 401 responses, else coerce to 403
        auth_header = self.get_authenticate_header(self.request)

        if auth_header:
            exc.auth_header = auth_header
        else:
            exc.status_code = status.HTTP_403_FORBIDDEN
        # 都会走,获取异常处理函数
        exception_handler = self.get_exception_handler()
        # 获取请求数据内容字典
        context = self.get_exception_handler_context()
        # 异常函数:接收exc,context,返回response对象
        response = exception_handler(exc, context)

        if response is None:
            # 异常函数如果为空交给原生django处理
            self.raise_uncaught_exception(exc)
            # 异常返回
            response.exception = True
            return response
    # 2.1获取异常处理函数具体函数,可以自己配置
 def get_exception_handler(self):
        """
        Returns the exception handler that this view uses.
        """
        return self.settings.EXCEPTION_HANDLER

总结:

  1. 在APIView的dispatch方法中,有一个try...except...异常,将代码运行的异常都交给异常处理模块进行处理: response = self.handle_exception(exc)
  2. 在handle_exception()中从配置中映射处理异常的函数(自定义异常模块就是自定义配置函数指向自己的函数),通过self.get_exception_handler()去获取配置文件中异常函数对象,然后将数据给自己写的函数进行处理,如果没有配置则是框架中默认的
  3. 异常函数exception_handler(exe,content)处理异常,就会走自己重写的异常函数,先交给系统处理(客户端的异常),系统没处理(服务器异常),再自己处理

5.3.状态码响应模块

Response类生成对象需要的参数,以及Response类的对象可以使用的属性

  1. 参数:Response(data=响应的数据, status=响应的网络状态码, headers=想通过响应头再携带部分信息给前端)

  2. 属性:response.data response.status_code response.status_text
  3. 出典:__init__メソッドのレスポンスクラス

概要

おすすめ

転載: www.cnblogs.com/randysun/p/12159493.html