Django Rest Framework(第五天)-关系和超链API

一、关系和超链接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页面。


评论(0 ) 点赞(15)


暂未登录,请登录之后发表评论。 QQ