Django REST framework教程二: 請求和響應
教程索引目錄
Django REST framework的系列教程
對於需要通篇瞭解的同學,可以點選教程索引目錄。
從現在開始,我們要開始,真正接觸到REST framework的核心部分了。當然,我們需要先認識一些重要的基本元素。
請求物件(Request object)
REST framework引入了一個 Request
物件, 它繼承自普通的 HttpRequest
,但能夠更加靈活的解析收到的請求。Request
物件的核心功能,就是其中的 request.data
屬性。這個屬性跟 request.POST
相似,但對我們的Web API來說,更加的有用。
request.POST # 只能處理表單(form)資料,只能處理“POST”方法.
request.data # 處理任意資料.可以處理'POST', 'PUT' 和 'PATCH'方法.
響應物件(Response object)
REST framework 同時引入了 Response
物件,是一種 TemplateResponse
,它攜帶著純粹的內容,通過內容協商(Content Negotiation)來決定,將以何種形式,返回給客戶端。
return Response(data) # 根據客戶端的要求,把內容,生成對應的形式.
狀態碼(Status codes)
在你的視圖裡,使用純數字的狀態碼,並不利於程式碼閱讀,如果你寫錯了狀態碼,也不會很容易的察覺。REST framework為每個狀態碼提供了更加明確的標識,比如 HTTP_400_BAD_REQUEST
status
模組中。我們在各處,使用這種識別符號,而不是純數字的狀態碼,這是個很好的想法。
包裝API檢視(wrapping API views)
REST framework提供了兩種編寫API view的封裝。
- 使用
@api_view
裝飾器,基於方法的檢視 - 繼承
APIView
類,基於類的檢視
這些檢視封裝,提供了些許的功能,比如:確保你的檢視能夠收到 Request
例項;還有,將內容賦予 Response
物件,使得 內容協商(content negotiation) 可以正常的運作。
檢視封裝,也內建了一些行為,比如:在遇到錯誤請求時,自動響應 405 Method Not Allowed
request.data
時,因為輸入的格式不恰當,而發生的任何 ParseError
異常(exception),檢視封裝都會處理。
將所有元素 合起來
現在,讓我們繼續,用這些新的元素來寫幾個檢視。
我們不再需要 view.py
檔案中 JSONResponse
類了,所以儘管刪掉它吧。然後,我們可以開始有一點,細微的重構了。
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer
@api_view(['GET', 'POST'])
def snippet_list(request):
"""
列出所有的程式碼片段(snippets),或者建立一個程式碼片段(snippet)
"""
if request.method == 'GET':
snippets = Snippet.objects.all()
serializer = SnippetSerializer(snippets, many=True)
return Response(serializer.data)
elif request.method == 'POST':
serializer = SnippetSerializer(data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data, status=status.HTTP_201_CREATED)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
當前的例項,相比之前的例子,有了改進:它變得,簡潔了一點,並且,如果你曾經使用過Forms API,你會發現,它們非常的相識。我們也用了命名式的狀態碼,這讓響應的狀態,易於閱讀。
下面是snippet的詳細檢視,它在 views.py
模組中。
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
讀取, 更新 或 刪除 一個程式碼片段例項(snippet instance)。
"""
try:
snippet = Snippet.objects.get(pk=pk)
except Snippet.DoesNotExist:
return Response(status=status.HTTP_404_NOT_FOUND)
if request.method == 'GET':
serializer = SnippetSerializer(snippet)
return Response(serializer.data)
elif request.method == 'PUT':
serializer = SnippetSerializer(snippet, data=request.data)
if serializer.is_valid():
serializer.save()
return Response(serializer.data)
return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
elif request.method == 'DELETE':
snippet.delete()
return Response(status=status.HTTP_204_NO_CONTENT)
目前為止,你應該感覺到很熟悉——它跟一般的Django檢視,沒多大的區別。
值得一提的是,我們已經不再明確地,解析/定義檢視中 Request/Response的內容型別。request.data
會自行處理輸入的json
請求,當然,也能處理別的格式。同樣的,我們只需返回響應物件以及資料,REST framework會幫我們,將響應內容,渲染(render)成正確的格式。
為我們的URLs新增可選的格式字尾
現在,我們的響應,不再硬性繫結在,某一種返回格式上,利用這點優勢,我們可以為API端,新增格式的字尾。使用格式字尾,可以定製我們的URLs,使它明確的指向指定的格式,這意味著,我們的API可以處理一些URLs,類似這樣的格式 http://example.com/api/items/4/.json
。
首先,需要新增一個 format
關鍵字引數,如下所示:
def snippet_list(request, format=None):
還有:
def snippet_detail(request, pk, format=None):
然後對 urls.py
檔案,做些小改。在現有的URLs基礎上,追加一套 format_suffix_patterns
:
from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from snippets import views
urlpatterns = [
url(r'^snippets/$', views.snippet_list),
url(r'^snippets/(?P<pk>[0-9]+)$', views.snippet_detail),
]
urlpatterns = format_suffix_patterns(urlpatterns)
我們不需要逐一地,新增對格式支援的 url 樣式(patterns),這是一個簡潔的方法,來快速支援特定的格式。
效果如何?
接著,我們可以從命令列中測試我們的API,跟教程一(tutorial part 1)中的操作一樣。儘管我們對一些無效的請求,提供了很好的處理,但仍然沒有太大的改變。
我們可以獲取所有snippet的列表,就跟之前一樣。
http http://127.0.0.1:8000/snippets/
HTTP/1.1 200 OK
...
[
{
"id": 1,
"title": "",
"code": "foo = \"bar\"\n",
"linenos": false,
"language": "python",
"style": "friendly"
},
{
"id": 2,
"title": "",
"code": "print \"hello, world\"\n",
"linenos": false,
"language": "python",
"style": "friendly"
}
]
我們也可以控制響應內容的格式,通過Http中的 Accept
頭(header):
http http://127.0.0.1:8000/snippets/ Accept:application/json # 請求 JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html # 請求 HTML
或通過追加格式字尾(format suffix):
http http://127.0.0.1:8000/snippets.json # JSON 字尾
http http://127.0.0.1:8000/snippets.api # 視覺化 API 字尾
同樣的,我們可以控制,傳送的請求型別,通過http中的 Content-Type
頭(header):
# POST 使用表單資料
http --form POST http://127.0.0.1:8000/snippets/ code="print 123"
{
"id": 3,
"title": "",
"code": "print 123",
"linenos": false,
"language": "python",
"style": "friendly"
}
# POST 使用 JSON
http --json POST http://127.0.0.1:8000/snippets/ code="print 456"
{
"id": 4,
"title": "",
"code": "print 456",
"linenos": false,
"language": "python",
"style": "friendly"
}
視覺化
由於 API 選擇響應格式,是基於客戶端發起的請求,因此,當接收到來著瀏覽器的請求時,會預設以HTML格式來描述資料。這讓API能夠返回,可以網頁瀏覽(web-browsable)的HTML表現。
擁有網頁瀏覽(web-browsable)的API,實在是非常的有用,使得開發和使用API,變成非常便利。這也大大降低了使用壁壘,讓其它開發者,更加容易的檢視和使用,你的API。
如需瞭解更多,有關視覺化API的特性,以及如何定製,可以查閱專題:視覺化API(browsable api)
下步做什麼?
在教程第三部(tutorial part 3),我們開始用基於類的檢視,並看看通用檢視(generic views)如何替我們省去大量的程式碼。
如果你覺得這個翻譯非常有幫助,不妨小額贊助我一下,你的認可,是我的動力!