zoukankan      html  css  js  c++  java
  • django rest framwork教程之外键关系和超链接

    此时,我们的API中的关系通过使用主键来表示。在本教程的这一部分中,我们将通过使用超链接来改善关系的内聚性和可发现性

    为我们的API的根创建一个端点

    现在我们有“snippets”和“users”的端点,但我们没有到我们的API的单个入口点。要创建一个,我们将使用一个常规的基于函数的视图和我们前面介绍的@api_view装饰器,在views.py中添加如下代码:

    from rest_framework.decorators import api_view
    from rest_framework.response import Response
    from rest_framework.reverse import reverse
    @api_view(['GET'])
    def api_root(request, format=None):
        return Response({
            'users': reverse('user-list', request=request, format=format),
            'snippets': reverse('snippet-list', request=request, format=format)
        })
    

    这里需注意两件事,首先我们使用rest框架的reverse函数来返回完全限定的URL,其次,URL模式由方便名称标示,我们将在后面的代码片段urls.py中声明

    为高亮显示的代码段创建端点

    我们还需要提供高亮snippet的路径. 当然这一路径与其他不同, 我们希望使用HTML而不是JSON来呈现. Django-rest_framework为我们提供了两种方式呈现HTML, 一种是使用模板, 另一种则是已构建好的HTML文本. 由于在创建snippet时, 我们已经使用pygments将高亮的snippet转化为HTML文本储存在数据库中, 我们使用第二种方式.

    由于我们返回的并不是一个object实例, 而是一个实例的某个属性, django-rest-framework没有提供该generic class based view. 因此我们需要使用基本的view, 并创建get()方法:

    from rest_framework import renderers
    from rest_framework.response import Response
    
    class SnippetHighlight(generics.GenericAPIView):
        queryset = Snippet.objects.all()
        renderer_classes = (renderers.StaticHTMLRenderer,)
    
        def get(self, request, *args, **kwargs):
            snippet = self.get_object()
            return Response(snippet.highlighted)
    

    在urls.py中添加对应的路径:

    url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
    

    测试:curl 结果为html

    curl  -X GET  -s -u test:1234.com  http://127.0.0.1:8000/snippets/1/highlight/
    <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN"
       "http://www.w3.org/TR/html4/strict.dtd">
    
    <html>
    <head>
      <title>first test</title>
      <meta http-equiv="content-type" content="text/html; charset=None">
      <style type="text/css">
    td.linenos { background-color: #f0f0f0; padding-right: 10px; }
    span.lineno { background-color: #f0f0f0; padding: 0 5px 0 5px; }
    pre { line-height: 125%; }
    body .hll { background-color: #222222 }
    body  { background: #000000; color: #cccccc }
    body .c { color: #000080 } /* Comment */
    body .err { color: #cccccc; border: 1px solid #FF0000 } /* Error */
    body .esc { color: #cccccc } /* Escape */
    body .g { color: #cccccc } /* Generic */
    body .k { color: #cdcd00 } /* Keyword */
    body .l { color: #cccccc } /* Literal */
    body .n { color: #cccccc } /* Name */
    body .o { color: #3399cc } /* Operator */
    body .x { color: #cccccc } /* Other */
    body .p { color: #cccccc } /* Punctuation */
    body .ch { color: #000080 } /* Comment.Hashbang */
    body .cm { color: #000080 } /* Comment.Multiline */
    body .cp { color: #000080 } /* Comment.Preproc */
    body .cpf { color: #000080 } /* Comment.PreprocFile */
    body .c1 { color: #000080 } /* Comment.Single */
    body .cs { color: #cd0000; font-weight: bold } /* Comment.Special */
    body .gd { color: #cd0000 } /* Generic.Deleted */
    body .ge { color: #cccccc; font-style: italic } /* Generic.Emph */
    body .gr { color: #FF0000 } /* Generic.Error */
    body .gh { color: #000080; font-weight: bold } /* Generic.Heading */
    body .gi { color: #00cd00 } /* Generic.Inserted */
    body .go { color: #888888 } /* Generic.Output */
    body .gp { color: #000080; font-weight: bold } /* Generic.Prompt */
    body .gs { color: #cccccc; font-weight: bold } /* Generic.Strong */
    body .gu { color: #800080; font-weight: bold } /* Generic.Subheading */
    body .gt { color: #0044DD } /* Generic.Traceback */
    body .kc { color: #cdcd00 } /* Keyword.Constant */
    body .kd { color: #00cd00 } /* Keyword.Declaration */
    body .kn { color: #cd00cd } /* Keyword.Namespace */
    body .kp { color: #cdcd00 } /* Keyword.Pseudo */
    body .kr { color: #cdcd00 } /* Keyword.Reserved */
    body .kt { color: #00cd00 } /* Keyword.Type */
    body .ld { color: #cccccc } /* Literal.Date */
    body .m { color: #cd00cd } /* Literal.Number */
    body .s { color: #cd0000 } /* Literal.String */
    body .na { color: #cccccc } /* Name.Attribute */
    body .nb { color: #cd00cd } /* Name.Builtin */
    body .nc { color: #00cdcd } /* Name.Class */
    body .no { color: #cccccc } /* Name.Constant */
    body .nd { color: #cccccc } /* Name.Decorator */
    body .ni { color: #cccccc } /* Name.Entity */
    body .ne { color: #666699; font-weight: bold } /* Name.Exception */
    body .nf { color: #cccccc } /* Name.Function */
    body .nl { color: #cccccc } /* Name.Label */
    body .nn { color: #cccccc } /* Name.Namespace */
    body .nx { color: #cccccc } /* Name.Other */
    body .py { color: #cccccc } /* Name.Property */
    body .nt { color: #cccccc } /* Name.Tag */
    body .nv { color: #00cdcd } /* Name.Variable */
    body .ow { color: #cdcd00 } /* Operator.Word */
    body .w { color: #cccccc } /* Text.Whitespace */
    body .mb { color: #cd00cd } /* Literal.Number.Bin */
    body .mf { color: #cd00cd } /* Literal.Number.Float */
    body .mh { color: #cd00cd } /* Literal.Number.Hex */
    body .mi { color: #cd00cd } /* Literal.Number.Integer */
    body .mo { color: #cd00cd } /* Literal.Number.Oct */
    body .sa { color: #cd0000 } /* Literal.String.Affix */
    body .sb { color: #cd0000 } /* Literal.String.Backtick */
    body .sc { color: #cd0000 } /* Literal.String.Char */
    body .dl { color: #cd0000 } /* Literal.String.Delimiter */
    body .sd { color: #cd0000 } /* Literal.String.Doc */
    body .s2 { color: #cd0000 } /* Literal.String.Double */
    body .se { color: #cd0000 } /* Literal.String.Escape */
    body .sh { color: #cd0000 } /* Literal.String.Heredoc */
    body .si { color: #cd0000 } /* Literal.String.Interpol */
    body .sx { color: #cd0000 } /* Literal.String.Other */
    body .sr { color: #cd0000 } /* Literal.String.Regex */
    body .s1 { color: #cd0000 } /* Literal.String.Single */
    body .ss { color: #cd0000 } /* Literal.String.Symbol */
    body .bp { color: #cd00cd } /* Name.Builtin.Pseudo */
    body .fm { color: #cccccc } /* Name.Function.Magic */
    body .vc { color: #00cdcd } /* Name.Variable.Class */
    body .vg { color: #00cdcd } /* Name.Variable.Global */
    body .vi { color: #00cdcd } /* Name.Variable.Instance */
    body .vm { color: #00cdcd } /* Name.Variable.Magic */
    body .il { color: #cd00cd } /* Literal.Number.Integer.Long */
    
      </style>
    </head>
    <body>
    <h2>first test</h2>
    
    <div class="highlight"><pre><span></span><span class="n">python</span> <span class="n">asdasdas</span> <span class="n">manasdnasd</span>
    </pre></div>
    </body>
    </html>
    
    

    使用超链接

    处理实例之间的关系是WEB API中比较麻烦的事情,我们可以选择以下来表示关系:

    • 使用主键
    • 使用超链接
    • 使用相关项的slug field
    • 使用相关项的默认文本信息
    • 将子项显示在母项中
    • 其他自定义表现方式

    REST框架支持所有这些样式,并且可以跨前向或反向关系应用它们,或将它们应用于诸如通用外键的自定义管理器。
    现在我们在实例之间用超链接形式,我们需要修改我们的serializers,用HyperlinkedModelSerializer代替ModelSerializer, 修改后将有如下不同:

    • HyperlinkedModelSerializer不会自动包含pk field
    • HyperlinkedModelSerializer会自动包括url field
    • 关系使用的是HyperlinkedRelatedField而不是PrimaryKeyRelatedField
     class SnippetSerializer(serializers.HyperlinkedModelSerializer):
            owner = serializers.ReadOnlyField(source='owner.username')
            highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')
    
            class Meta:
                model = Snippet
                fields = ('url', 'highlight', 'owner',
                          'title', 'code', 'linenos', 'language', 'style')
    
    
        class UserSerializer(serializers.HyperlinkedModelSerializer):
            snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail')
    
            class Meta:
                model = User
                fields = ('url', 'username', 'snippets')
    

    注意, 我们同时添加了 "highlight" field, 它与url field使用的一样, 是HyperlinkedRelatedField, 但指向的是snippet-highlight url而不是snippet-detail url
    由于我们在url中包含了格式信息, 我们使用format='html'参数为highlight指定.html后缀.

    确保我们的url有name

    如果我们要有一个超链接的API,我们需要确保我们命名我们的URL模式。让我们来看看我们需要命名的网址格式。

    • 我们的API根指向user-list and snippet-list
    • 我们的snippet序列化包含一个snippet-highlight字段
    • 我们的user序列化包含一个引用snippet-detail的字段
    • Our snippet and user serializers include 'url' fields that by default will refer to '{model_name}-detail', which in this case will be 'snippet-detail' and 'user-detail'
      中文(简体)
      我们的代码段和用户序列化程序包括url字段,默认情况下将引用{model_name} -detail,在这种情况下,它将是snippet-detailuser-detail
    urlpatterns = [
        url(r'^snippets/$', views.SnippetList.as_view(),name="snippet-list"),
        url(r'^snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view(),name="snippet-detail"),
        url(r'^users/$', views.UserList.as_view(),name='user-list',name='user-detail'),
        url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),
        url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view(),name='snippet-highlight'),
    ]
    

    添加分页

    用户和代码片段的列表视图最终可能返回相当多的实例,因此,我们希望确保分页结果,并允许API客户端逐步浏览每个单独的页面。
    我们通过修改settings.py ,添加如下代码

    REST_FRAMEWORK = {
        'PAGE_SIZE': 10
    }
    

    请注意,REST框架中的设置都命名为单个字典设置,名为“REST_FRAMEWORK”,这有助于保持它们与其他项目设置分离

  • 相关阅读:
    java.net.DatagramPacket/java.net.DatagramSocket-UDP Socket编程
    新浪微博客户端(9)-实现版本新特性的ViewPager
    新浪微博客户端(8)-添加按钮到TabBar
    iOS-Auto property synthesis will not synthesize property 'delegate'; it will be implemented by its super
    新浪微博客户端(7)-通过转换坐标系来调整首页下拉菜单的位置
    新浪微博客户端(6)-创建首页下拉菜单
    TortoiseGit-创建分支、合并分支
    BZOJ2683: 简单题(cdq分治 树状数组)
    BZOJ3262: 陌上花开(cdq分治)
    BZOJ1901: Zju2112 Dynamic Rankings(整体二分 树状数组)
  • 原文地址:https://www.cnblogs.com/pycode/p/6553631.html
Copyright © 2011-2022 走看看