從現(xiàn)在開始,我們將真正開始接觸REST框架的核心。 我們來介紹幾個基本的構(gòu)建模塊。
REST框架引入了一個擴展了常規(guī)HttpRequest的Request對象,并提供了更靈活的請求解析。Request對象的核心功能是request.data屬性,它與request.POST類似,但對于使用Web API更為有用。
request.POST # 只處理表單數(shù)據(jù) 只適用于'POST'方法
request.data # 處理任意數(shù)據(jù) 適用于'POST','PUT'和'PATCH'方法
REST框架還引入了一個Response對象,這是一種獲取未渲染(unrendered)內(nèi)容的TemplateResponse類型,并使用內(nèi)容協(xié)商來確定返回給客戶端的正確內(nèi)容類型。
return Response(data) # 渲染成客戶端請求的內(nèi)容類型。
在你的視圖(views)中使用純數(shù)字的HTTP 狀態(tài)碼并不總是那么容易被理解。而且如果錯誤代碼出錯,很容易被忽略。REST框架為status模塊中的每個狀態(tài)代碼(如HTTP_400_BAD_REQUEST)提供更明確的標識符。使用它們來代替純數(shù)字的HTTP狀態(tài)碼是個很好的主意。
REST框架提供了兩個可用于編寫API視圖的包裝器(wrappers)。
這些包裝器提供了一些功能,例如確保你在視圖中接收到Request實例,并將上下文添加到Response,以便可以執(zhí)行內(nèi)容協(xié)商。
包裝器還提供了諸如在適當(dāng)時候返回405 Method Not Allowed響應(yīng),并處理在使用格式錯誤的輸入來訪問request.data時發(fā)生的任何ParseError異常。
好的,我們開始使用這些新的組件來寫幾個視圖。
我們在views.py中不再需要JSONResponse類了,所以把它刪除掉。刪除之后,我們就可以開始重構(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
@api_view(['GET', 'POST'])
def snippet_list(request):
"""
列出所有的snippets,或者創(chuàng)建一個新的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)
我們的實例視圖比前面的示例有所改進。它稍微簡潔一點,現(xiàn)在的代碼與我們使用Forms API時非常相似。我們還使用了命名狀態(tài)代碼,這使得響應(yīng)意義更加明顯。
以下是views.py模塊中單個snippet的視圖。
@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
"""
獲取,更新或刪除一個snippet實例。
"""
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)
這對我們來說應(yīng)該都是非常熟悉的,-它和正常Django視圖并沒有什么不同。
注意,我們不再顯式地將請求或響應(yīng)綁定到給定的內(nèi)容類型。request.data可以處理傳入的json請求,但它也可以處理其他格式。同樣,我們返回帶有數(shù)據(jù)的響應(yīng)對象,但允許REST框架將響應(yīng)給我們渲染成正確的內(nèi)容類型。
為了充分利用我們的響應(yīng)不再與單一內(nèi)容類型連接,我們可以為API路徑添加對格式后綴的支持。使用格式后綴給我們明確指定了給定格式的URL,這意味著我們的API將能夠處理諸如http://example.com/api/items/4.json之類的URL。
像下面這樣在這兩個視圖中添加一個format關(guān)鍵字參數(shù)。
def snippet_list(request, format=None):
和
def snippet_detail(request, pk, format=None):
現(xiàn)在更新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模式,但它給了我們一個簡單,清晰的方式來引用特定的格式。
從命令行開始測試API,就像我們在教程第一部分中所做的那樣。一切操作都很相似,盡管我們發(fā)送無效的請求也會有一些更好的錯誤處理了。
我們可以像以前一樣獲取所有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"
}
]
我們可以通過使用Accept標頭來控制我們回復(fù)的響應(yīng)格式:
http http://127.0.0.1:8000/snippets/ Accept:application/json # 請求JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html # 請求HTML
或者通過附加格式后綴:
http http://127.0.0.1:8000/snippets.json # JSON后綴
http http://127.0.0.1:8000/snippets.api # 瀏覽器可瀏覽API后綴
類似地,我們可以使用Content-Type頭控制我們發(fā)送的請求的格式。
# 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"
}
# POST JSON數(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請求添加了--debug,則可以在請求標頭中查看請求類型。
現(xiàn)在可以在瀏覽器中訪問http://127.0.0.1:8000/snippets/查看API。
由于API根據(jù)客戶端請求選擇響應(yīng)的內(nèi)容類型,因此默認情況下,當(dāng)Web瀏覽器請求該資源時,它將返回資源的HTML格式表示。這允許API返回完全瀏覽器可瀏覽(web-browsable)的HTML表示。
擁有支持瀏覽器可瀏覽的API在可用性方面完勝并使開發(fā)和使用你的API更容易。它也大大降低了其他開發(fā)人員要檢查和使用API??的障礙。
更多建議: