5 - Relationships and hyperlinked APIs
教程 5:關係和超連結 API
目前我們的 API 中的關係是通過使用主鍵來表示。在本教程的這一部分中,我們將改進 API 的內聚力和可發現性,而不是使用超連結來進行關係。
為我們的 API 的根地址建立端點
現在我們有 ‘snippets’ 和 ‘users’ 端點,但我們沒有一個指向我們 API 的入口。要建立一個,我們將使用基於函式的常規檢視和我們前面介紹的 @api_view
裝飾器。在你的 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)
})
這裡應該注意兩件事。首先,我們使用 REST framework 的 reverse 函式來返回完全限定的URL;其次,URL 模式通過我們稍後將在我們的 snippets/urls.py
中宣告的便利名稱進行標識。
為高亮顯示 snippets 建立端點
另一個明顯的事情是我們的 pastebin API 仍然缺少高亮顯示程式碼的端點。
與所有其他 API 端點不同,我們不想使用 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)
像往常一樣,我們需要將我們建立的新檢視新增到 URLconf 中。我們將在 snippets/urls.py
中為我們的新 API 根路徑新增一個 url 模式:
url(r'^$', views.api_root),
然後為高亮 snippet 新增一個 url 模式:
url(r'^snippets/(?P<pk>[0-9]+)/highlight/$', views.SnippetHighlight.as_view()),
超連結我們的 API
處理實體之間的關係是 Web API 設計中更具挑戰性的方面之一。這裡有一些我們可能會選擇代表關係的不同方法:
- 使用主鍵。
- 在實體之間使用超連結。
- 在相關實體上使用唯一的標識欄位。
- 使用預設字串代表相關實體。
- 將相關實體巢狀在父代表中。
- 一些其他自定義表示。
REST framework 支援所有這些樣式,並且可以在正向或反向關係中應用它們,或者通過自定義管理器 (如通用外來鍵) 應用它們。
在這種情況下,我們希望在實體之間使用超連結樣式。為了做到這一點,我們將修改我們的序列化器來擴充套件 HyperlinkedModelSerializer
,而不是現有的 ModelSerializer
。
HyperlinkedModelSerializer
與 ModelSerializer
有以下區別:
- 它預設不包含 id 欄位。
- 它包含一個
url
欄位,使用HyperlinkedIdentityField
。 - 關係使用
HyperlinkedRelatedField
,而不是PrimaryKeyRelatedField
。
我們可以輕鬆地重寫現有的序列化器來使用超連結。在你的 snippets/serializers.py
中新增:
class SnippetSerializer(serializers.HyperlinkedModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')
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')
請注意,我們還添加了一個新的 'highlight'
欄位。該欄位與 url
欄位型別相同,不同之處在於它指向的是 'snippet-highlight'
url 模式,而不是 'snippet-detail'
url 模式。
因為我們已經包含了格式字尾的 URL,例如 '.json'
,我們還需要在 highlight
欄位上指出任何格式字尾的超連結返回應該使用 .html'
字尾。
確保我們的 URL 模式被命名
如果我們要有超連結的 API,我們需要確保命名 URL 模式。我們來看看我們需要命名的 URL 模式。
- 我們的 API 根地址是指
'user-list'
和'snippet-list'
。 - 我們的 snippet 序列化器包含一個指向
'snippet-highlight'
的欄位。 - 我們的 user 序列化器包含一個指向
'snippet-detail'
的欄位。 - 我們的 snippet 和 user 序列化器包括
'url'
欄位,預設情況下將指向'{model_name}-detail'
,在這個例子中就是'snippet-detail'
和'user-detail'
。
將所有這些名稱新增到我們的 URLconf 後,我們最後的 snippets/urls.py
檔案應如下所示:
from django.conf.urls import url, include
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
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')
])
新增分頁
users 和 snippets 的列表檢視最終會返回很多例項,所以我們真的要確保對結果進行分頁,並允許 API 客戶端遍歷每個單獨的頁面。
我們可以通過稍微修改 tutorial/settings.py
檔案來更改預設列表樣式以使用分頁。新增以下設定:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 10
}
請注意,REST framework 中的所有設定都放在一個名為 REST_FRAMEWORK
的字典中,這有助於讓他們與其他專案設定保持良好的分離。
如果需要,我們也可以自定義分頁樣式,但在這個例子中,我們將一直使用預設設定。
瀏覽 API
如果我們開啟瀏覽器並導航到可瀏覽的 API,您會發現現在您可以通過簡單的連結訪問 API。
您還可以在 snippet 例項上看到 “highlight” 連結,這會帶您跳轉到程式碼高亮顯示的 HTML 頁面。
在本教程的第 6 部分中,我們將介紹如何使用 ViewSets 和 Routers 來減少構建 API 所需的程式碼量。