一、关系和超链接API
目前我们的API中的关系是用主键表示的,我们将通过超链接来提高我们API的内部联系。
1.1 创建API的root节点
现在我们的有‘Snippets’和‘Users’的路径,但是我们的API没有一个入口点。我们将使用一个常规的基于函数的视图和我们前面介绍的@api_view装饰器创建一个。在我们的quickstart/views.py中添加:
from rest_framework.decorators import api_view from rest_framework.response import Response from rest_framework.reverse import reverse from rest_framework import renderers @api_view(['GET']) def api_root(request, format=None): """ API入口 :param request: :param format: :return: """ return Response({ 'users': reverse('qk:user-list', request=request, format=format), 'snippets': reverse('qk:snippet-list', request=request, format=format) })
这里有两点是我们需要注意的。第一,我们使用了REST框架的reverse函数,以返回一个全限定名的URL。第二,reverse方法的第一个参数要求填入view_name,这里我们填写的是qk:user-list和qk:snippet-list,这个来源于:quickstart/urls.py
from django.conf.urls import url, include import quickstart.views as views from rest_framework.urlpatterns import format_suffix_patterns app_name = 'qk' urlpatterns = [ url(r'api/$', views.api_root), url(r'snippets/$', views.SnippetList.as_view(), name='snippet-list'), url(r'snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()), url(r'users/$', views.UserList.as_view(), name='user-list'), url(r'users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()), ] urlpatterns = format_suffix_patterns(urlpatterns)
最终返回的结果确实为URL的全限定名:
{ "users": "http://127.0.0.1:8018/users/", "snippets": "http://127.0.0.1:8018/snippets/" }
1.2 为高亮的代码段创建一个节点
我们的API中另一个明显缺少的是代码高亮显示路径。
与所有其他API路径不同,我们不想使用JSON,而只是需要HTML表示。REST框架提供了两种HTML渲染器,一种用于处理使用模板渲染的HTML,另一种用于处理预渲染的HTML。第二个渲染器是我们要用于此路径的渲染器。
创建代码高亮视图时需要考虑的另一件事是,我们没有可用的具体通用视图。我们不是返回对象实例,而是返回对象实例的属性。
不是使用具体的通用视图,我们将使用基类来表示实例,并创建我们自己的.get()方法。在你的quickstart/views.py中添加:
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)
然后,我们需要配置quickstart/urls.py
urlpatterns = [ url(r'api/$', views.api_root), url(r'snippets/$', views.SnippetList.as_view(), name='snippet-list'), url(r'snippets/(?P<pk>[0-9]+)/$', views.SnippetDetail.as_view()), url(r'users/$', views.UserList.as_view(), name='user-list'), 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'), ] urlpatterns = format_suffix_patterns(urlpatterns)
1.3 超链接化API
处理好实体之间的关系是WEB API设计中更具挑战性的一方面。我们通常会选用一下方式来表示这种关系:
1、使用主键 2、使用实体间的超链接 3、使用唯一识别字段 4、使用默认字符串表示 5、在父级中使用嵌套相关的实体来表示关系 6、其他的自定义表示
REST框架支持上述所有的形式,并且可以将它们应用于前向或者反向关系,或者将他们应用到自定义的管理器中(如通用外键)。 这里我们选用超链接样式。为了能够达到这个效果,我们使用HyperlinkedModelSerializer来代替现有的ModelSerializer:
1、默认不包含id 2、包含url字段,使用的是HyperlinkedIdentityField 3、关系使用PrimaryKeyRelatedField代替HyperlinkedRelatedField
我们可以方便地重写现有的序列化器。在quickstart/serializers.py中添加以下代码:
class SnippetSerializer(serializers.HyperlinkedModelSerializer): """ 使用ModerSerializer类 """ owner = serializers.ReadOnlyField(source='owner.username') url = serializers.HyperlinkedIdentityField(view_name='qk:snippet-detail', lookup_field='pk') # 视图函数名:views_name,后缀为html,而不是json,因为我们需要的就是高亮的文本 highlight = serializers.HyperlinkedIdentityField(view_name='qk:snippet-highlight', format='html') class Meta: model = Snippet fields = ('url', 'id', 'highlight', 'owner', 'title', 'code', 'linenos', 'language', 'style') class UserSerializer(serializers.HyperlinkedModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='qk:user-detail', lookup_field='pk') snippets = serializers.HyperlinkedRelatedField(many=True, view_name='qk:snippet-detail', read_only=True) class Meta: model = User fields = ('url', 'id', 'username', 'snippets')
需要注意的是,我们也添加了新的highlight字段。这个字段和url是一样的类型。它是指向snippet-highlight这个url pattern的。 因为我们包含了格式后缀(例如.json),我们也需要声明highlight字段对于任何格式后缀都应该返回html格式的内容。
1.4 确保URL pattern已经被命名
如果我们打算使用hyperlinked API,我们需要确保我们的URL pattern已经被命名。让我们一起看下都有哪些URL pattern需要被命名。
我们的root api,之前提到的,需要引用到user-list和snippet-list。 SnippetSerializer引用到了snippet-highlight UserSerializer引用到了snippet-detail Snippet和User Serialzers的url字段默认引用了{model_name}-detail,在这里就是snippet-detail和user-detail了。
最终我们的quickstart/urls.py:
# -*- coding:utf-8 -*- from django.conf.urls import url import quickstart.views as views from rest_framework.urlpatterns import format_suffix_patterns app_name = 'qk' urlpatterns = [ url(r'api/$', views.api_root), # url(r'snippets/$', views.snippet_list), # url(r'snippets/(?P<pk>[0-9]+)/$', views.snippet_detail), # url(r'^index/$',views.IndexView.as_view()), 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'), url(r'users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view(), name='user-detail'), url(r'snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view(), name='snippet-highlight'), ] urlpatterns = format_suffix_patterns(urlpatterns)
1.5 添加分页
在tutorial/settings.py中添加配置:
REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 1 }
注意,REST框架的设置都放到同一个命名空间的字典里,名字为:REST_FRAMEWORK,这有助于保持它们与你的其他项目设置分离。 如果需要,你也可以自定义分页风格,但是这里我们只是用默认的。
1.6 浏览API
如果我们打开浏览器,并且浏览可被访问的API,你会发现你现在可以通过关系连接方便的浏览API了。 你也可以在snippet中看到highlight连接,点击它将会将你带到高亮代码的HTML页面。