django rest framwork教程之外键关系和超链接
2017-03-15 12:51
471 查看
此时,我们的API中的关系通过使用主键来表示。在本教程的这一部分中,我们将通过使用超链接来改善关系的内聚性和可发现性
这里需注意两件事,首先我们使用rest框架的
由于我们返回的并不是一个object实例, 而是一个实例的某个属性, django-rest-framework没有提供该generic class based view. 因此我们需要使用基本的view, 并创建get()方法:
在urls.py中添加对应的路径:
测试:curl 结果为html
使用主键
使用超链接
使用相关项的slug field
使用相关项的默认文本信息
将子项显示在母项中
其他自定义表现方式
REST框架支持所有这些样式,并且可以跨前向或反向关系应用它们,或将它们应用于诸如通用外键的自定义管理器。
现在我们在实例之间用超链接形式,我们需要修改我们的serializers,用
HyperlinkedModelSerializer不会自动包含pk field
HyperlinkedModelSerializer会自动包括url field
关系使用的是HyperlinkedRelatedField而不是PrimaryKeyRelatedField
注意, 我们同时添加了 "highlight" field, 它与url field使用的一样, 是HyperlinkedRelatedField, 但指向的是snippet-highlight url而不是snippet-detail url
由于我们在url中包含了格式信息, 我们使用format='html'参数为highlight指定.html后缀.
我们的API根指向
我们的snippet序列化包含一个
我们的user序列化包含一个引用
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'
中文(简体)
我们的代码段和用户序列化程序包括
我们通过修改settings.py ,添加如下代码
请注意,REST框架中的设置都命名为单个字典设置,名为“REST_FRAMEWORK”,这有助于保持它们与其他项目设置分离
为我们的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-listand
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-detail和
user-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”,这有助于保持它们与其他项目设置分离
相关文章推荐
- Django REST Framework Tutorial 5:关系与超链接API(中文版教程)by hillfree
- Django-Rest-Framework 教程: 5. 提高关联性和超链接API
- Django restframwork教程之类视图(class-based views)
- django rest framwork教程之 viewsets和routers
- Django REST FrameWork中文教程5:关系和超链接API
- django restframwork 教程之authentication权限
- django restframwork教程之Request和Response
- django rest_framework--入门教程2
- Django-REST-framework教程中文版
- django数据库操作-增删改查-多对多关系以及一对多(外键)关系
- Django-Rest-Framework 教程: 4. 验证和权限
- Django REST Framework v.3官方中文教程 索引
- django rest_framework--入门教程3
- 表间关系和外键约束 SQL Server系列教程(七)
- django数据库操作-增删改查-多对多关系以及一对多(外键)关系
- Django-Rest-Framework 教程
- Django-Rest-Framework 教程: 2. Requests 和 Responses
- Django REST framework(官方教程-六)
- Django REST Framework Tutorial 4:认证与权限(中文版教程)by hillfree
- Python开发WebService系列教程之REST,web.py,eurasia,Django