Django 之REST framework学习5:关联性和超链接API(Relationships & Hyperlinked APIs)

当前我们API的内部关联性都是通过主键来代表的,接下来我们要通过超链接的方式来提高内聚和可发现性,意思就是提高关联性!

给我们API的根目录创建一个endpoint

找到了endpoint源码贴一下:

@property
def endpoint(self):
    """The endpoint that matched the request.  This in combination with
    :attr:`view_args` can be used to reconstruct the same or a
    modified URL.  If an exception happened when matching, this will
    be ``None``.
    """
    if self.url_rule is not None:
        return self.url_rule.endpoint

理解下endpoint先:
    实际上这个endpoint就是一个Identifier,每个视图函数都有一个endpoint,当有请求来到的时候,用它来知道到底使用哪一个视图函数;现在我们需要在snippets/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)
    })
为高亮的snippets创建endpoint:

不像其他API的endpoint,我们不想用JSON,只是为了呈现HTML,REST framework提供了两种HTML渲染形式,
一种使用模板处理html的渲染,另一种使用预渲染的HTML,下面我们会使用第二种方法:
我们还要考虑,现在没有现成的模板去创建代码高亮的视图函数,这里也不需要返回对象实例,返回实例的属性即可。
现在我们使用代表实例的基类去创建我们自己的.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)

snippets/urls.py中添加:

url(r'^$', views.api_root),

接着添加:

url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
超链接化我们的API

处理实体间的关系是Web API设计的难点之一,这里有很多种方法去表示一种关系(不一一翻译了):


  • Using primary keys.
  • Using hyperlinking between entities.
  • Using a unique identifying slug field on the related entity.
  • Using the default string representation of the related entity.
  • Nesting the related entity inside the parent representation.
  • Some other custom representation.

REST framework以上形式都支持,而且可以将它们应用于正向或者反向关联当中,当然也适用于外键这样的关系:
这次我们在实体间使用超链接的方式,那么我们要在我们的serializers 中把ModelSerializer换成
HyperlinkedModelSerializer
HyperlinkedModelSerializerModelSerializer有以下区别:

  1. 默认没有id字段;
  2. url字段,要用HyperlinkedIdentityField代表;
  3. 关联关系用HyperlinkedRelatedField表示,而不是PrimaryKeyRelatedField

snippets/serializers.py中重写我们的serializers :

class SnippetSerializer(serializers.HyperlinkedModelSerializer):
    owner = serializers.ReadOnlyField(source='owner.username')
    #这里我们增加了highlight 字段,类型和url 字段是一样的,只是它指向了<code>'snippet-highlight'</code>而不是
    #<code>'snippet-detail'</code>的url pattern
    highlight = serializers.HyperlinkedIdentityField(view_name='snippet-highlight', format='html')

    class Meta:
        model = Snippet
        fields = ('url', 'id', 'highlight', 'owner',
                  'title', 'code', 'linenos', 'language', 'style')


class UserSerializer(serializers.HyperlinkedModelSerializer):
    snippets = serializers.HyperlinkedRelatedField(many=True, view_name='snippet-detail', read_only=True)

    class Meta:
        model = User
        fields = ('url', 'id', 'username', 'snippets')

现在有了'.json'这样的格式化后缀的URLs,
我们还需要给highlight指定'.html'格式的后缀。

确保我们的URL patterns有自己的名字

如果我们想拥有一个超链接形式的API,我们需要给URL patterns指定名字:
snippets/urls.py中:

from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views

# API endpoints
urlpatterns = format_suffix_patterns([
    url(r'^$', views.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')
])
增加分页

用户 and code snippets 可能会返回很多实例,我们就需要对返回的结果进行分页处理,
稍微改下tutorial/settings.py,我们就能改变结果的默认展示形式:

#REST_FRAMEWORK 可以与项目的其他设置很好的进行区分
REST_FRAMEWORK = {
    'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
    'PAGE_SIZE': 10
}

测试~

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值