zoukankan      html  css  js  c++  java
  • Django REST Framework API Guide 03

    本节大纲

      1、Routers

      2、Parsers

      3、Renderers

    Routers

    Usage

    from rest_framework import routers
    
    router = routers.SimpleRouter()
    router.register(r'users', UserViewSet)
    router.register(r'accounts', AccountViewSet)
    urlpatterns = router.urls

    register的两个必填参数prefix, viewset, 可选参数base_name,用于创建URL名称的基础。如果未设置,将根据视图集的queryset属性自动生成basename注意,如果视图集不包含queryset属性,那么在注册viewset时必须设置base_name。

    之前上一章关于视图集的截图里面其实就已经可以发现这一点。

    样例:

    如果都没有定义会报错

    'base_name' argument not specified, and could not automatically determine the name from the viewset, as it does not have a '.queryset' attribute.

    Using include with routers

    可以添加路由如下

    router = routers.SimpleRouter()
    router.register(r'users', UserViewSet)
    router.register(r'accounts', AccountViewSet)
    
    urlpatterns = [
        url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
    ]
    
    urlpatterns += router.urls

    另外,可以使用Django的include方法

    urlpatterns = [
        url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
        url(r'^', include(router.urls)),
    ]

    也可以使用include带上app的命名空间:

    urlpatterns = [
        url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
        url(r'^api/', include((router.urls, 'app_name'))),
    ]

    还可以带上app和实例的命名空间

    urlpatterns = [
        url(r'^forgot-password/$', ForgotPasswordFormView.as_view()),
        url(r'^api/', include((router.urls, 'app_name'), namespace='instance_name')),
    ]

    Routing for extra actions

    通过@action装饰器来标记额外的操作,这些额外的操作会被包含在生成的url里面,比如上一章给的change_age等等

    class StudentViewSet(ModelViewSet):
        queryset = PersonResource.objects.filter(job=1)
        serializer_class = PersonModelSerializer
    
        @action(methods=['get', 'put'], detail=True)
        def change_age(self, request, pk=None):
            student = self.get_object()
            student.age += 1
            student.save()
            return Response({
                'status': '%s age changed.' % student.name,
                'url': self.reverse_action('change-age', args=[pk]),
                'url1': self.reverse_action(self.change_age.url_name, args=[pk])
            })
    
        @action(detail=False)
        def ordering(self, request):
            student = PersonResource.objects.filter(job=1).order_by('modify_time')
    
            page = self.paginate_queryset(student)
            if page is not None:
                serializer = self.get_serializer(page, many=True)
                return self.get_paginated_response(serializer.data)
    
            serializer = self.get_serializer(student, many=True)
            return Response(serializer.data)

    如果想要修改客制化的action的url

    from myapp.permissions import IsAdminOrIsSelf
    from rest_framework.decorators import action
    
    class UserViewSet(ModelViewSet):
        ...
    
        @action(methods=['post'], detail=True, permission_classes=[IsAdminOrIsSelf],
                url_path='change-password', url_name='change_password')
        def set_password(self, request, pk=None):
            ...

    API Guide

    SimpleRouter

    默认ULRs通过SimpleRouter创建,添加trailing_slash参数。这个行为可以被修改通过设置trailing_slash参数为False当初始化router

    router = SimpleRouter(trailing_slash=False)

    尾随斜杠在Django中是常规的,但在某些其他框架(如Rails)中默认不使用。您选择使用哪种样式在很大程度上取决于首选项,尽管一些javascript框架可能希望使用特定的路由样式。

    路由器将匹配包含除斜线和周期字符之外的任何字符的查找值。对于更严格(或宽松)的查找模式,在VIEW集中设置lookup_value_regex属性。例如,可以将查找限制为有效UUIDs:

    class MyModelViewSet(mixins.RetrieveModelMixin, viewsets.GenericViewSet):
        lookup_field = 'my_model_id'
        lookup_value_regex = '[0-9a-f]{32}'

    DefaultRouter

    同样

    router = DefaultRouter(trailing_slash=False)

    源文档这边是讲了关于客制化路由,动态路由参数的内容,不过,从我的生产上没感觉到有这个需求,暂时就不看了,先补个链接,有空补充这一块的知识点。

    http://www.django-rest-framework.org/api-guide/routers/

    2、Parsers

    REST framework包含了很多内置的Parser类。允许接受很多种媒体类别请求。它也支持定义你自己的客制化解析。

    视图的合法解析器总是定义为一个列表类,当request.data可以访问的时候,rest framework将检查即将到来的请求头的content-type,决定用哪个解析器来解析request的内容。

    Setting the parsers

    可以通过使用DEFAULT_PARSER_CLASSES来进行全局设置。比如,下面的设定仅允许JSON内容,代替默认的JSON或者表单数据

    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework.parsers.JSONParser',
        )
    }

    你也可以为一个单独的视图或者视图集设置,使用APIView CBV格式。

    from rest_framework.parsers import JSONParser
    from rest_framework.response import Response
    from rest_framework.views import APIView
    
    class ExampleView(APIView):
        """
        A view that can accept POST requests with JSON content.
        """
        parser_classes = (JSONParser,)
    
        def post(self, request, format=None):
            return Response({'received data': request.data})

    或者如果用FBV格式的话

    from rest_framework.decorators import api_view
    from rest_framework.decorators import parser_classes
    from rest_framework.parsers import JSONParser
    
    @api_view(['POST'])
    @parser_classes((JSONParser,))
    def example_view(request, format=None):
        """
        A view that can accept POST requests with JSON content.
        """
        return Response({'received data': request.data})

    API Reference

    JSONParser  # 解析成json请求内容;.media_tyoe:application/json
    MultiPartParser  # 解析HTML表单内容,request.data返回QueryDict数据,你需要使用FormParser和MultiPartParser,来完全支持html表单数据;.media_type:application/x-www-form-urlencoded
    MultiPartParser  # 同上;.media_type:multipart/form-data
    FileUploadParser  # 解析源生的上传文件内容,request.data属性将会是一个字典,包含一个单独的键'file'对应上传文件内容。如果使用文件名url关键字参数调用FIleUploadParser使用的视图,则该参数讲用作filename。如果没有filename url关键字参数,客户端必须设置文件名在请求头的Content-Disposition里面。比如:Content-Disposition: attachment; filename=upload.jpg;.media_type:*/*

    注意:

    a、FileUploadParser是用来给可以上传文件作为源生数据请求的本地客户端使用。对于基于网络的上传,或者具有多部分上传支持的本地客户端,你需要使用MultiPartParser代替.

    b、由于这个parser的media_type匹配任何的内容类型,FileUploadParser一般是唯一的parser在API视图上

    c、FileUploadParser遵循Django标准的FILE_UPLOAD_HANDLERS设定和request.upload_handlers属性.

    # views.py
    class FileUploadView(views.APIView):
        parser_classes = (FileUploadParser,)
    
        def put(self, request, filename, format=None):
            file_obj = request.data['file']
            # ...
            # do some stuff with uploaded file
            # ...
            return Response(status=204)
    
    # urls.py
    urlpatterns = [
        # ...
        url(r'^upload/(?P<filename>[^/]+)$', FileUploadView.as_view())
    ]

    Third party packages

    YAML

    $ pip install djangorestframework-yaml
    # Django setting
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework_yaml.parsers.YAMLParser',
        ),
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework_yaml.renderers.YAMLRenderer',
        ),
    }

    XML

    $ pip install djangorestframework-xml
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework_xml.parsers.XMLParser',
        ),
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework_xml.renderers.XMLRenderer',
        ),
    }

    Renderers

    setting the renderers

    以下设置将使用JSON作为主媒体类型,还包括自描述API。全局的设定使用DEFAULT_RENDERER_CLASSES参数

    REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework.renderers.JSONRenderer',
            'rest_framework.renderers.BrowsableAPIRenderer',
        )
    }

    可以单独对一个视图或者视图集设置,使用APIView的CBV格式

    from django.contrib.auth.models import User
    from rest_framework.renderers import JSONRenderer
    from rest_framework.response import Response
    from rest_framework.views import APIView
    
    class UserCountView(APIView):
        """
        A view that returns the count of active users in JSON.
        """
        renderer_classes = (JSONRenderer, )
    
        def get(self, request, format=None):
            user_count = User.objects.filter(active=True).count()
            content = {'user_count': user_count}
            return Response(content)

    或者在FBV格式下,使用@api_view装饰器

    @api_view(['GET'])
    @renderer_classes((JSONRenderer,))
    def user_count_view(request, format=None):
        """
        A view that returns the count of active users in JSON.
        """
        user_count = User.objects.filter(active=True).count()
        content = {'user_count': user_count}
        return Response(content)

    API Reference

    JSONRenderer

    转成json,使用utf-8编码。默认是使用unicode字符,渲染响应使用紧凑型的格式,没有不必要的空格

    {"unicode black star":"","value":999}

    客户端可能会额外的包含一个indent媒体类型参数,从而让返回的json数据被缩进。比如Accept: application/json; indent=4

    {
        "unicode black star": "",
        "value": 999
    }

    默认可以选择UNICODE_JSONCOMPACT_JSON

    .media_type: application/json

    .format: '.json'

    .charset: None

    TemplateHTMLRenderer

    模板渲染传入Response跟其他的转换不一样,它不需要被序列化,你只需要包含template_name参数当创建Response实例对象的时候

    TemplateHTMLRenderer会创建一个RequestContext,使用response.data作为内容字典根据,并确定用于呈现上下文的模板名称。

    模板名称可以通过以下几种方式定义:

    1、明确的定义template_name传入response

    2、明确定义.template_name属性在类上

    3、调用view.get_template_names()方法返回结果

    class UserDetail(generics.RetrieveAPIView):
        """
        A view that returns a templated HTML representation of a given user.
        """
        queryset = User.objects.all()
        renderer_classes = (TemplateHTMLRenderer,)
    
        def get(self, request, *args, **kwargs):
            self.object = self.get_object()
            return Response({'user': self.object}, template_name='user_detail.html')

    你可以使用TemplateHTMLRenderer返回常规的使用rest框架的html,或者是从同一个终端的HTML和API响应一起

    如果您正在构建使用TemplateHTMLRenderer和其他渲染类的网站,那么应该考虑将TemplateHTMLRenderer作为renderer_classes列表中的第一个类列出,这样即使对于发送格式不佳的ACCEPT:header的浏览器,也会优先考虑它。

    StaticHTMLRenderer

    传入到response的数据是字符串类型

    @api_view(('GET',))
    @renderer_classes((StaticHTMLRenderer,))
    def simple_html_view(request):
        data = '<html><body><h1>Hello, world</h1></body></html>'
        return Response(data)

    Third party packages

    YAML

    $ pip install djangorestframework-yaml
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework_yaml.parsers.YAMLParser',
        ),
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework_yaml.renderers.YAMLRenderer',
        ),
    }

    XML

    $ pip install djangorestframework-xml
    REST_FRAMEWORK = {
        'DEFAULT_PARSER_CLASSES': (
            'rest_framework_xml.parsers.XMLParser',
        ),
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework_xml.renderers.XMLRenderer',
        ),
    }

    JSONP

    $ pip install djangorestframework-jsonp
    REST_FRAMEWORK = {
        'DEFAULT_RENDERER_CLASSES': (
            'rest_framework_jsonp.renderers.JSONPRenderer',
        ),
    }

    附上链接,至少目前感觉,这边真的不怎么用得到

    http://www.django-rest-framework.org/api-guide/renderers/

  • 相关阅读:
    递归神经网络(RNN)简介(转载)
    递归神经网络入门教程(转载)
    向量叉积的几何意义(转)
    向量点乘(内积)和叉乘(外积、向量积)概念及几何意义解读
    完全搞懂傅里叶变换和小波(6)――傅立叶级数展开之函数项级数的性质
    完全搞懂傅里叶变换和小波(5)——傅立叶级数展开之函数项级数的概念
    完全搞懂傅里叶变换和小波(4)——欧拉公式及其证明
    完全搞懂傅里叶变换和小波(3)——泰勒公式及其证明
    完全搞懂傅里叶变换和小波(2)——三个中值定理<转载>
    完全搞懂傅里叶变换和小波(1)——总纲<转载>
  • 原文地址:https://www.cnblogs.com/wuzdandz/p/9628120.html
Copyright © 2011-2022 走看看