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
。
HyperlinkedModelSerializer
和ModelSerializer
有以下區別:
- 預設沒有
id
欄位;- 有
url
欄位,要用HyperlinkedIdentityField
代表;- 關聯關係用
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
}