到目前为止, API之间的关系是以主键形式体现的, (比如打开/users/1/, 可以看到snippets中为snippet的主键). 在本篇中, 我们将使用超链接的形式, 进一步提高API的关联程度和可发现性. 首先我们补充一些路径, 是整个API结构更为完整.
1. 根路径
现在, 我们已经有了users和snippets的路径, 但对于API本身却没有一个根路径. 我们使用@api_view修饰器来创建一个function based view作为根路径:
# snippets/views.py from rest_framework import renderers 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) })
注意, 我们使用了django-rest-framework的reverse(), 而不是django自带的reverse(), 此时如果打开http://127.0.0.1/8000, 会报错, 因为我们还没有为url添加name, 稍后我们会添加.
在urls.py中添加对应的路径:
# snippets/urls.py url(r‘^$‘, views.api_root),
2. 高亮snippet路径
我们还需要提供高亮snippet的路径. 当然这一路径与其他不同, 我们希望使用HTML而不是JSON来呈现. Django-rest_framework为我们提供了两种方式呈现HTML, 一种是使用模板, 另一种则是已构建好的HTML文本. 由于在创建snippet时, 我们已经使用pygments将高亮的snippet转化为HTML文本储存在数据库中, 我们使用第二种方式.
由于我们返回的并不是一个object实例, 而是一个实例的某个属性, django-rest-framework没有提供该generic class based view. 因此我们需要使用基本的view, 并创建get()方法:
# snippets/views.py 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中添加对应的路径:
# snippets/urls.py url(r‘^snippets/(?P<pk>[0-9]+)/highlight/$‘, views.SnippetHighlight.as_view()),
3. 使用超链接
处理各部件API之间的关系是一件头痛的事. django-rest_framework为我们提供了以下这些方法来表现关系:
- 使用主键
- 使用超链接
- 使用相关项的slug field
- 使用相关项的默认文本信息
- 将子项显示在母项中
- 其他表现方式
这次, 我们使用超链接的方式来体现user和snippet的关系. 为了实现这一方式, 我们需要改写序列器(serializers), 使用HyperlinkedModelSerializer代替原本的ModelSerializer. HyperlinkedModelSerializer相对于ModelSerializer具有以下不同:
- HyperlinkedModelSerializer不会自动包含pk field
- HyperlinkedModelSerializer会自动包括url field
- 关系使用的是HyperlinkedRelatedField而不是PrimaryKeyRelatedField
# snippets/serializers.py class SnippetSerializer(serializers.HyperlinkedModelSerializer): owner = serializers.Field(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后缀.
4. 为url添加name
编辑snippets/urls.py如下:
# snippets/urls.py # API 路径 urlpatterns = format_suffix_patterns(patterns(‘snippets.views‘, url(r‘^$‘, ‘api_root‘), 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‘^snippets/(?P<pk>[0-9]+)/highlight/$‘, views.SnippetHighlight.as_view(), name=‘snippet-highlight‘), url(r‘^users/$‘, views.UserList.as_view(), name=‘user-list‘), url(r‘^users/(?P<pk>[0-9]+)/$‘, views.UserDetail.as_view(), name=‘user-detail‘) )) # 可浏览式登录API urlpatterns += patterns(‘‘, url(r‘^api-auth/‘, include(‘rest_framework.urls‘, namespace=‘rest_framework‘)), )
5. 分页
如果数据库中的数据达到一定程度, 那么用户使用api时可能会返回大量数据, 因此, 我们最好使用分页功能:
我们可以使用django-rest-framework自带的设置选项, 使list自动使用分页:
# tutorial/settings.py REST_FRAMEWORK = { ‘PAGINATE_BY‘: 10 }
6. 测试
现在可以使用之前提到的方法测试我们的API了, 可以在/snippets/中看到, 原先的id已经被url代替, url和highlight field都采用超链接的形式.
原文链接: http://www.weiguda.com/blog/23/