目前咱們的API中的關係的經過主鍵來表示。咱們下面將改進API的內聚力和可現性,而不是使用超連接來進來進行關係。html
如今咱們有snippets
和users
的端點,可是咱們沒有一個指向咱們API的入口。咱們須要建立一個,咱們將使用基於函數的常規視圖和咱們前面介紹的@api_view裝飾器。在你的quickstart/view.py中添加:python
# quickstart/view.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模式經過咱們下面的quickstart/urls.py
中聲明的便利名稱進行表示。django
另外一個明顯的事情是咱們的pastebin API仍然缺乏高亮的顯示代碼端點。json
與其餘API端點不一樣,咱們不想使用JSON,而是隻呈現HTML表示。REST framework提供了兩種HTML渲染器,一種是使用模板來處理渲染HTML,另外一種渲染器是咱們要用於此端點的渲染器。api
在建立代碼高亮顯示視圖時候,咱們須要考慮的另外一件事是:不存在咱們可使用的通用視圖。咱們不是返回一個對象實例,而是返回宇哥對象實例屬性。瀏覽器
咱們將使用基類來表示實例,並建立咱們本身的.get()
方法,而不是使用具體的通用視圖。在你的quickstart/view.py中添加:服務器
# quickstart/view.py from rest_framework import permissions, renderers 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
中,咱們將在quickstart/urls.py
中添加一個新的url模式:架構
url('^$', api_root),
而後爲高亮代碼snippet添加一個url模式:app
url('^snippets/(?P<pk>[0-9]+)/highlight/$',SnippetHighlight.as_view()),
處理實體之間的關係是咱們Web API設計中更具挑戰性的方面之一,這裏有一些咱們選擇表明關係的不一樣方法:框架
REST framework支持這些樣式,而且可在正式或者反向關係中應用他們。或者經過自定義管理器(如通用外鍵)應用他們。
在這種狀況下,咱們但願在實體之間使用超連接樣式,爲了作到這一點,咱們將修改咱們的序列化器來擴展HyperlinkedModelSerializer
,而不是現有的ModelSerializer
。
HyperLinkedModelSerializer
與ModelSerializer
有一下區別:
url
字段,使用HyperlinkedIdentityField
.HyperlinkedRelatedField
,而不是PrimaryKeyRelatedField
。咱們能夠輕鬆的重寫現有的序列化器來使用超連接:
# quickstart/serialzers.py from rest_framework import serializers from .models import Snippet from django.contrib.auth.models import User 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
後綴。
若是咱們要有超連接的API,咱們須要確保命名URL模式。咱們看看咱們須要命名的URL模式。
user-list
和snippet-list
。snippet-highlight
的字段。url
字段,默認狀況下將指向{model_name}-detail
,在這個例子中就是snippet-detail
和user-detail
。咱們將全部這些名稱添加到咱們的URLconf後,咱們最後在quickstart/urls.py
文件應該以下:
quickstart/urls.py from django.conf.urls import url from rest_framework.urlpatterns import format_suffix_patterns from .views import SnippetList, SnippetDetail, UserList, UserDetail, api_root,SnippetHighlight from django.conf.urls import include urlpatterns = format_suffix_patterns([ url('^api-auth/', include('rest_framework.urls')), url('^$',api_root), url('snippets/$',SnippetList.as_view(), name='snippet-list'), url('^snippets/(?P<pk>[0-9]+)/$', SnippetDetail.as_view(), name='snippet-detail'), url('^snippets/(?P<pk>[0-9])/highlight/$', SnippetHighlight.as_view(), name='snippet-highlight'), url('^users/$', UserList.as_view(), name='user-list'), url('^users/(?P<pk>[0-9]+)/$',view=UserDetail.as_view(), name='user-detail'), ])
users和snippets的列表視圖最終會返回不少實例,因此咱們真的要確保結果進行分頁。並容許API客戶端遍歷每一個單獨頁面。
咱們能夠經過稍微修改tutorial/setting.py
,文件來更改默認列表樣式可使用分頁。添加一下設置:
# tutorial/setting.py REST_FRAMEWORK = { 'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination', 'PAGE_SIZE': 10 }
注意,REST framework中的全部設置都放在一個名爲
REST——FRMEWORK
的字典中,這有助於他們與其餘項目保持良好的分離。若是須要,咱們也能夠自定義分頁的樣式,可是這裏,咱們會一直使用默認。
啓動服務·
python manage.py runserver
在瀏覽器輸入http://127.0.0.1:8000/quickstart/snippets/
,結果以下圖所示:
你還能夠在 snippet 實例上看到 「highlight」 連接,這會帶您跳轉到代碼高亮顯示的 HTML 頁面。
還有url的連接
REST framework 包括一個用於處理ViewSets
的抽象,它容許開發人員集中精力對API的狀態和交互進行建模,並保留URL結構,根據通用的約定自動處理。
ViewSet
類與View
類幾乎相同。只是他們提供諸如read
或update
操做。而不提供諸如GET
或則PUT
等方法處理程序。
一個ViewSet
類最後時刻只能綁定一組方法處理程序,當它被實例化爲一組視圖的時候,一般經過使用一個Router
類來處理定義複雜的URL。
咱們來看看當前的一組視圖,並將它們重構爲視圖集。
首先讓咱們將UserList
和UserDetail
視圖重構爲單個UserViewSet
。咱們能夠刪除這兩個視圖,並用一個類替換它們:
# quickstart/view.py from rest_framework import viewsets #新增導入 class UserViewSet(viewsets.ReadOnlyModelViewSet): # 這個視圖集自動提供 list 和 detail 操做 queryset = User.objects.all() serializer_class = UserSerializer
這裏咱們使用了
ReadOnlyModelViewSet
類來自動提供默認的」只讀「操做。咱們仍然像咱們使用常規駛入時同樣設置queryset
和serializer_class
屬性,可是咱們不須要爲兩個單獨的類,提供相同的信息。
接下來咱們將替換SnippetList
,SnippetDetail
和SnippetHihtlight
視圖類。咱們能夠刪除這三個視圖,並再次使用一個類去替換它們。
# quickstart/view.py class SnippetViewSet(viewsets.ModelViewSet): """ 這個視圖集自動提供 'list' 'create' 'retrieve' 'update' 和 'destroy' 另外咱們還提供一個額外的'highlight'操做 """ queryset = Snippet.objects.all() serializer_class = SnippetSerializer permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,) @action(detail=True, renderers_classed = [renderers.StaticHTMLRenderer]) def highlight(self, request, *args, **kwargs): snippet = self.get_object() return Response(snippet.highlighted) def perform_create(self, serializer): serializer.save(owner=self.request.user)
此次咱們使用了
ModelViewSet
類來得到完整的默認讀寫操做集。注意,咱們還使用了
@action
裝飾器來建立一個名爲highlight
的自定義操做。這個裝飾器能夠用來添加任何不符合標準create/update/delete
樣式的自定義端點。使用
@action
裝飾器的自定義操做默認會響應GET
請求。若是咱們想要響應POST
請求的操做,咱們可使用methods
參數。自定義操做的URL默認取決於方法名稱自己。若是須要更改URL的構造方式,能夠包含
url_path
做爲裝飾器的關鍵字參數。
當咱們定義URLConf時,處理程序方法只能綁定到操做上。爲了看看到底發生了什麼,讓咱們首先從咱們的ViewSets中明確地建立一組視圖。
在quickstart/urls.py
文件中,咱們將ViewSet
類綁定到一組具體視圖中。
# quickstart/urls.py from .views import api_root, SnippetViewSet, UserViewSet from rest_framework import renderers snippet_list = SnippetViewSet.as_view({ 'get': 'list', 'post': 'create', }) snippet_detail = SnippetViewSet.as_view({ 'get': 'retrieve', 'put': 'update', 'patch': 'partial_update', 'delete': 'destroy', }) snippet_highlight = SnippetViewSet.as_view({ 'get': 'highlight' }, renderers_class=[renderers.StaticHTMLRenderer]) user_list = UserViewSet.as_view({ 'get': 'list' }) user_detail = UserViewSet.as_view({ 'get': 'retrieve' })
注意咱們是如何從每一個
ViewSet
類建立多個視圖,經過將HTTP方法綁定到每一個視圖所需的操做中。
如今咱們已經將資源綁定到具體的視圖中,咱們能夠像往常同樣在URL conf中註冊視圖。
urlpatterns = format_suffix_patterns([ url('^api-auth/', include('rest_framework.urls')), url('^$',api_root), url('snippets/$', snippet_list, name='snippet-list'), url('^snippets/(?P<pk>[0-9]+)/$', snippet_detail, name='snippet-detail'), url('^snippets/(?P<pk>[0-9])/highlight/$', snippet_highlight, name='snippet-highlight'), url('^users/$', user_list, name='user-list'), url('^users/(?P<pk>[0-9]+)/$', user_detail, name='user-detail'), ])
由於咱們使用ViewSet
類而不是View
類,因此實際上咱們不須要本身設計URL。將資源連接到視圖和URL的約定可使用Router
類自動處理,咱們須要作的就使用路由器註冊相應的視圖集,而後讓他執行其他操做。
這裏咱們重寫quickstart/urls.py文件:
# quickstart/urls.py from django.conf.urls import include, url from rest_framework.routers import DefaultRouter # 建立路由器並註冊咱們的視圖。 router = DefaultRouter() router.register('snippets', views.SnippetViewSet) router.register('users', views.UserViewSet) # API url 如今有路由器自動肯定 urlpatterns = [ url('^', include(router.urls)) ]
用路由器註冊視圖集相似於提供urlpattern.咱們包括兩個參數--視圖的URL前綴和視圖集自己。
咱們使用
DefaultRouter
類爲咱們自動建立了API根視圖,因此咱們如今能夠從views
模塊中刪除api_root
方法。
使用視圖集能夠是一個經常使用的抽象。它有助於確保URL約定在你的API中保存一致,最大限度地減小編寫所需的代碼量,並容許你專一於API提供的交互,而不是URL conf的細節。
這並不意味着它老是正確的作法。可是用基於類的視圖而不是基於函數的視圖的時候,也有相似的權衡考慮。使用視圖集不像單獨構建視圖那樣明確。
概要是一種機器可閱讀文檔,用於描述可用API路徑,器URLS以及他們支持的操做。
高腰能夠是自動生成文檔的有用工具,也能夠是用於驅動,能夠與API進行交互的動態客戶端庫。
爲了提供概要支持REST框架使用Core API.
CoreAPI是用於描述API的文檔規範,它用於提供可用路徑的內部表示形式和API公開的可能的交互。他能夠用於服務器端或者客戶端。
當使用服務端時候,Core API 容許支持API支持呈現範圍普遍的概要或者超媒體格式。
當使用客戶端時,核心API容許動態驅動的客戶端庫,它能夠與任何公開受支持的概要或者超媒體格式的API交互。
REST框架支持明肯定義的概要視圖或者自動生成概要。因爲咱們使用的是視圖集和路由,咱們能夠簡單地使用自動概要生成。
你須要安裝coreapi
,python包才能包含API概要。
pip install coreapi
如今咱們能夠經過在url配置中包含一個主動生成的概要視圖來爲API添加概要。
# quickstart/urls.py from rest_framework.schemas import get_schema_view urlpatterns = [ url('^schema/$', schema_view), #新增 url('^', include(router.urls)) ]
若是你在瀏覽器中訪問API的根路徑,那麼你如今應該就能夠看到core json
表示形式是另外一個可用選項。
咱們也能夠經過在Accept
標識頭中指定所需的內容類型從從命令行請求概要。
$ http http://127.0.0.1:8000/schema/ Accept:application/coreapi+json HTTP/1.0 200 OK Allow: GET, HEAD, OPTIONS Content-Type: application/coreapi+json { "_meta": { "title": "Pastebin API" }, "_type": "document", ...
默認輸入樣式是使用Core JSON編碼。
還支持其餘概要格式,如Open API(之前叫Swagger)。
如今咱們的API暴露了一個概要路徑,咱們可使用一個動態的客戶端庫與API進行交互,爲了演示這個,咱們使用CoreAPI命令行客戶端。
命令行客戶端做爲一個coreapi-cli
包提供:
pip install coreapi-cli
如今檢查他在命令行上是否可用...
首先咱們使用命令行客戶端加載API概要。
$ coreapi get http://127.0.0.1:8000/schema/ <Pastebin API "http://127.0.0.1:8000/schema/"> snippets: { highlight(id) list() read(id) } users: { list() read(id) }
咱們尚未認證,因此咱們如今只能看到只讀路徑,這與咱們設置的API權限是一致的。
咱們使用命令行客戶端,嘗試列出現有代碼片斷:
$ coreapi action snippets list [ { "url": "http://127.0.0.1:8000/snippets/1/", "id": 1, "highlight": "http://127.0.0.1:8000/snippets/1/highlight/", "owner": "lucy", "title": "Example", "code": "print('hello, world!')", "linenos": true, "language": "python", "style": "friendly" }, ...
一些API路徑須要命名參數。例如,要獲取特定代碼片斷的高亮HTML表示,咱們須要提供一個id。
$ coreapi action snippets highlight --param id=1 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <title>Example</title> ...
若是咱們想要建立,編輯,和刪除代碼片斷,咱們須要進行有效的用戶身份驗證,在這種狀況下,咱們只須要使用基本的auth。
請確保使用實際的用戶名和密碼替換下面的<username>
和<password>
.
$ coreapi credentials add 127.0.0.1 <username>:<password> --auth basic Added credentials 127.0.0.1 "Basic <...>"
如今,若是咱們再次提取概要,我麼應該能夠看到一組可用的交互。
$ coreapi reload Pastebin API "http://127.0.0.1:8000/schema/"> snippets: { create(code, [title], [linenos], [language], [style]) delete(id) highlight(id) list() partial_update(id, [title], [code], [linenos], [language], [style]) read(id) update(id, code, [title], [linenos], [language], [style]) } users: { list() read(id) }
咱們如今可以與這些路徑行交互。例如,要建立一個新的代碼片斷:
$ coreapi action snippets create --param title="Example" --param code="print('hello, world')" { "url": "http://127.0.0.1:8000/snippets/7/", "id": 7, "highlight": "http://127.0.0.1:8000/snippets/7/highlight/", "owner": "lucy", "title": "Example", "code": "print('hello, world')", "linenos": false, "language": "python", "style": "friendly" }
而後刪除一個代碼片斷:
$ coreapi action snippets delete --param id=7
除了命令行客戶端,開發人員還可使用客戶端庫與你的API進行交互。Python客戶端庫是第一個可用的庫,而且計劃即將發佈一個Javascript客戶端庫。
有關定製模式生成和使用Core API客戶端庫的更多詳細信息,您須要參考完整的文檔。