第二章 請(qǐng)求與響應(yīng)
寫在前面:
本文翻譯于django rest framework官方文檔巡球,由于網(wǎng)上大多數(shù)django rest framework中文翻譯文檔都有較為多的刪減行為坑傅,筆者在學(xué)習(xí)的時(shí)候就覺得不是太方便奋渔,故筆者將官方文檔較為完善的為大家翻譯下斤寇,僅供大家學(xué)習(xí)參考惩妇。由于筆者文筆有限经瓷,若有寫得不當(dāng)之處危号,敬請(qǐng)各位同仁指出;若涉及到侵權(quán)票彪,請(qǐng)聯(lián)系筆者红淡,筆者將立即刪除。
在這一部分中降铸,我們將真正的開始覆蓋到REST Framework
的核心知識(shí)在旱,我們先來介紹幾個(gè)基本的模塊。
1. 請(qǐng)求對(duì)象
REST Framework
引入了一個(gè)Request
對(duì)象推掸,它擴(kuò)展了常規(guī)的HttpRequest
對(duì)象桶蝎,并且提供了更加靈活的請(qǐng)求解析驻仅。Request
對(duì)象的核心功能是request.data
屬性,它類似于Django
常規(guī)的request.POST
登渣,但對(duì)于web API來說噪服,它更加有用。在后面的內(nèi)容中你們就會(huì)體會(huì)到這一點(diǎn)胜茧。
request.POST # 僅僅處理表單數(shù)據(jù)粘优,僅適用于‘POST’方法
request.data # 處理任意的數(shù)據(jù),適用于'POST', 'PUT' 和 'PATCH'方法
另外呻顽,使用GET
方法請(qǐng)求數(shù)據(jù)在REST Framework
里我們使用request.query_params
來獲取雹顺。
2. 響應(yīng)對(duì)象
REST Framework
引入了一個(gè)Response
對(duì)象,他啊是一種TemplateResponse
廊遍,它接受未渲染的內(nèi)容嬉愧,并且使用內(nèi)容協(xié)商來確定返回到客戶端的正確的內(nèi)容類型。
return Response(data) # 根據(jù)客戶端的請(qǐng)求來返回正確的內(nèi)容類型(content type)
3. 狀態(tài)碼
在視圖中使用HTTP
狀態(tài)碼并不很好的有利于閱讀昧碉,非常容易就會(huì)搞不清狀態(tài)碼是否寫錯(cuò)(比如該寫404的寫成了405)英染,所以,REST Framework
為每個(gè)狀態(tài)碼提供了更加明顯的標(biāo)識(shí)符被饿,但如果你英文不好的話也沒辦法了四康。比如HTTP_400_BAD_REQUEST
總比400
更好懂一些。
4. 裝飾API視圖
REST Framework
提供了兩種方法來寫API視圖
- 使用
@api_view
裝飾器來處理基于函數(shù)的視圖 - 使用
APIView
類來處理基于類的視圖
這些包裝器提供了幾個(gè)功能狭握,例如確保在您的視圖中接收Request
實(shí)例闪金,并將上下文添加到Response
對(duì)象,方便執(zhí)行內(nèi)容協(xié)商论颅。
包裝器還提供一些行為哎垦,例如在適當(dāng)時(shí)返回405 Method Not Allowed
的響應(yīng),以及處理request.data
有格式錯(cuò)誤時(shí)發(fā)生的任何ParseError
異常恃疯。
5. 用這些新的組件來寫幾個(gè)視圖
我們不再需要在views.py
文件中使用JSONResponse
類漏设,所以可以把之前寫的這個(gè)注釋掉,然后重構(gòu)我們的視圖今妄。
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
# 支持’GET‘和’POST‘方法
@api_view(['GET', 'POST'])
def snippet_list(request):
"""
列出所有的實(shí)例或者創(chuàng)建一個(gè)新的實(shí)例
"""
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)
這個(gè)視圖是對(duì)我們?cè)谏弦徽鹿?jié)的視圖的改進(jìn)郑口。這個(gè)視圖明顯更加簡(jiǎn)潔,同時(shí)我們使用帶有說明的狀態(tài)碼盾鳞,這使得響應(yīng)的意義更加明顯犬性。
下面我們?cè)賹懸粋€(gè)視圖函數(shù),來對(duì)我們單個(gè)的實(shí)例進(jìn)行操作腾仅。
# 支持‘GET’乒裆,‘PUT’和’DELETE‘方法
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
檢索,更新和刪除實(shí)例
"""
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)
其實(shí)對(duì)這樣的視圖我們應(yīng)該很熟悉推励,因?yàn)樗统R?guī)的``Django```視圖并沒有太大的區(qū)別鹤耍。
請(qǐng)注意肉迫,我們不再明確地將我們的請(qǐng)求或響應(yīng)綁定到給定的內(nèi)容類型。 request.data
可以處理傳入的json
請(qǐng)求惰蜜,但它也可以處理其他格式昂拂。 同樣抛猖,我們返回帶有數(shù)據(jù)的響應(yīng)對(duì)象鼻听,但允許REST Framework
將響應(yīng)呈現(xiàn)給我們正確的內(nèi)容類型。
6. 在我們的URL中添加可選的格式后綴
為了利用我們的響應(yīng)不再硬連接到單個(gè)內(nèi)容類型撑碴,我們可以為我們的API端點(diǎn)添加格式后綴支持撑教。 使用格式后綴為我們提供了明確引用給定格式的網(wǎng)址,這意味著我們的API可以處理像http://example.com/api/items/4.json這樣的網(wǎng)址醉拓。
首先向這兩個(gè)視圖添加format
關(guān)鍵字參數(shù)
def snippet_list(request, format=None):
def snippet_detail(request, pk, format=None):
然后我們可以稍微更新下我們的urls.py
文件,在現(xiàn)有的URL之后添加一組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模式不是必須的愤兵,但使用它我們可以用一種干凈,簡(jiǎn)單的方式來引用某個(gè)特定的格式排吴。
7. 我們?cè)摍z驗(yàn)我們的成果了
我們和第一章相比秆乳,當(dāng)我們發(fā)送一些無效的請(qǐng)求之后,我們將得到更好的錯(cuò)誤處理了钻哩。
首先,把程序跑起來扯键,然后進(jìn)入127.0.0.1:8000/snippets/珊肃,我們江看到
[
{
"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"
}
]
我們可以通過使用Accept header
來控制回傳的格式。
http://127.0.0.1:8000/snippets/ Accept:application/json # 請(qǐng)求 JSON
http://127.0.0.1:8000/snippets/ Accept:text/html # 請(qǐng)求 HTML
或者直接附加一個(gè)格式后綴
http://127.0.0.1:8000/snippets.json # JSON 后綴
http://127.0.0.1:8000/snippets.api # 可瀏覽的 API 后綴
同樣嘶摊,我們可以使用Content-Type
頭來控制我們發(fā)送的請(qǐng)求的格式。
# 使用表單POST數(shù)據(jù)
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"
}
# 使用JSON來POST數(shù)據(jù)
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"
}
如果你在上述的HTTP請(qǐng)求中加一個(gè)--debug
叶堆,你將看到請(qǐng)求的類型在請(qǐng)求頭里斥杜。
8. 可瀏覽性
因?yàn)锳PI基于客戶端請(qǐng)求選擇響應(yīng)的內(nèi)容類型,所以當(dāng)Web瀏覽器請(qǐng)求資源時(shí)忘渔,它將默認(rèn)返回資源的HTML格式表示。 這允許API返回完全可web瀏覽的HTML表示散址。
擁有一個(gè)可以瀏覽網(wǎng)頁的API在可用性方面是一個(gè)巨大的勝利宣赔,并使開發(fā)和使用您的API更容易。 它還顯著降低了想要檢查和使用您的API的其他開發(fā)人員的入口儒将。
有關(guān)可瀏覽的API功能以及如何對(duì)其進(jìn)行自定義的詳細(xì)信息,請(qǐng)參閱browsable api
主題贡翘。
9. 下一步
在第三章砰逻,我們將開始使用基于類的視圖,并且使用通用視圖來進(jìn)一步減少我們的代碼量诱渤。
謝謝各位閱讀,并歡迎各位留下寶貴意見