Django REST框架——教程2:請求和響應

教程2:請求和響應

從這一點來說堤舒,我們將真正開始覆蓋REST框架的核心。我們來介紹一些基本的構建塊誉碴。

請求對象

REST框架引入了一個Request擴展常規(guī)的對象HttpRequest隆圆,并提供更靈活的請求解析。Request對象的核心功能是與Web API request.data類似的屬性request.POST翔烁,但更為有用渺氧。

request.POST  # Only handles form data.  Only works for 'POST' method.
request.data  # Handles arbitrary data.  Works for 'POST', 'PUT' and 'PATCH' methods.

響應對象

REST框架還引入了一個Response對象,它是一種類型的對象蹬屹,它TemplateResponse使用未呈現(xiàn)的內容并使用內容協(xié)商來確定返回給客戶端的正確內容類型侣背。

return Response(data)  # Renders to content type as requested by the client.

狀態(tài)碼

在視圖中使用數(shù)字HTTP狀態(tài)代碼并不總是顯而易見的閱讀,并且如果錯誤代碼錯誤慨默,很容易不注意贩耐。REST框架為每個狀態(tài)代碼提供更明確的標識符,例如HTTP_400_BAD_REQUESTstatus模塊中厦取。這是一個好主意潮太,而不是使用數(shù)字標識符。

包裝API視圖

REST框架提供了兩個可用于編寫API視圖的包裝器。

  1. @api_view用于處理基于函數(shù)的視圖的裝飾器铡买。
  2. APIView班與基于類的視圖工作更鲁。

這些包裝提供了一些功能,例如確保Request在視圖中接收實例奇钞,并向Response對象添加上下文澡为,以便可以執(zhí)行內容協(xié)商。

這些包裝器還提供了一些行為景埃,例如405 Method Not Allowed在適當時返回響應媒至,以及處理ParseErrorrequest.data格式錯誤的輸入中訪問時發(fā)生的任何異常。

把它們結合在一起

好的谷徙,讓我們繼續(xù)拒啰,開始使用這些新的組件來寫幾個意見。

我們不再需要我們的JSONResponse類完慧,在views.py中谋旦,所以繼續(xù)刪除。一旦完成骗随,我們可以開始重構我們的視圖。

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):
    """
    List all code snippets, or create a new 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)碼乞巧,這使得響應的含義更加明顯涨椒。

以下是views.py模塊中單個片段的視圖。

@api_view(['GET', 'PUT', 'DELETE'])
def snippet_detail(request, pk):
    """
    Retrieve, update or delete a code 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)

這應該都感到非常熟悉 - 這與使用常規(guī)Django視圖沒有多大區(qū)別绽媒。

請注意蚕冬,我們不再明確地將我們的請求或響應綁定到給定的內容類型。 request.data可以處理傳入的json請求是辕,但也可以處理其他格式囤热。同樣,我們使用數(shù)據(jù)返回響應對象获三,但允許REST框架將響應呈現(xiàn)給我們正確的內容類型旁蔼。

添加可選的格式后綴到我們的網(wǎng)址

為了利用我們的響應不再被硬連接到單個內容類型的事實,讓我們添加對格式后綴的支持到我們的API端點疙教。使用格式后綴給了我們明確引用給定格式的URL棺聊,并且意味著我們的API將能夠處理諸如http://example.com/api/items/4.json之類的 URL 。

通過向format兩個視圖添加關鍵字參數(shù)開始贞谓,就像這樣限佩。

def snippet_list(request, format=None):

def snippet_detail(request, pk, format=None):

現(xiàn)在snippets/urls.py稍微更新文件,以附加一組format_suffix_patterns現(xiàn)有的URL。

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模式祟同,但它給了我們一個簡單作喘,干凈的方式來引用一個特定的格式。

它看起來如何耐亏?

繼續(xù)從命令行測試API徊都,就像我們在教程第一部分中所做的那樣。一切工作都非常類似广辰,盡管如果我們發(fā)送無效的請求暇矫,我們已經(jīng)有了更好的錯誤處理。

和以前一樣择吊,我們可以得到所有片段的列表李根。

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頭來控制返回的響應的格式:

http http://127.0.0.1:8000/snippets/ Accept:application/json  # Request JSON
http http://127.0.0.1:8000/snippets/ Accept:text/html         # Request HTML

或者通過附加格式后綴:

http http://127.0.0.1:8000/snippets.json  # JSON suffix
http http://127.0.0.1:8000/snippets.api   # Browsable API suffix

同樣几睛,我們可以使用Content-Type標題來控制我們發(fā)送的請求的格式房轿。

# POST using form data
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 using 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"
}

如果您將--debug開關添加到上述http請求中,您將能夠在請求標頭中看到請求類型所森。

(blog) [root@centos7-01 django_auth_example]# http --form --debug POST http://192.168.152.131:5000/snippets/ code="import sys"
HTTPie 0.9.9
Requests 2.18.4
Pygments 2.2.0
Python 3.6.2 (default, Sep 12 2017, 18:57:38) 
[GCC 4.8.5 20150623 (Red Hat 4.8.5-11)]
/root/.pyenv/versions/3.6.2/envs/blog/bin/python
Linux 3.10.0-693.2.2.el7.x86_64

<Environment {
    "colors": 8,
    "config": {
        "__meta__": {
            "about": "HTTPie configuration file",
            "help": "https://httpie.org/docs#config",
            "httpie": "0.9.9"
        },
        "default_options": "[]"
    },
    "config_dir": "/root/.httpie",
    "is_windows": false,
    "stderr": "<_io.TextIOWrapper name='<stderr>' mode='w' encoding='UTF-8'>",
    "stderr_isatty": true,
    "stdin": "<_io.TextIOWrapper name='<stdin>' mode='r' encoding='UTF-8'>",
    "stdin_encoding": "UTF-8",
    "stdin_isatty": true,
    "stdout": "<_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>",
    "stdout_encoding": "UTF-8",
    "stdout_isatty": true
}>

>>> requests.request(**{
    "allow_redirects": false,
    "auth": "None",
    "cert": "None",
    "data": {
        "code": "import sys"
    },
    "files": {},
    "headers": {
        "Content-Type": "application/x-www-form-urlencoded; charset=utf-8",
        "User-Agent": "HTTPie/0.9.9"
    },
    "method": "post",
    "params": {},
    "proxies": {},
    "stream": true,
    "timeout": 30,
    "url": "http://192.168.152.131:5000/snippets/",
    "verify": true
})

HTTP/1.0 201 Created
Allow: OPTIONS, POST, GET
Content-Type: application/json
Date: Tue, 30 Jan 2018 09:14:17 GMT
Server: WSGIServer/0.2 CPython/3.6.2
Vary: Accept, Cookie
X-Frame-Options: SAMEORIGIN

{
    "code": "import sys",
    "id": 5,
    "language": "python",
    "linenos": false,
    "style": "friendly",
    "title": ""
}

現(xiàn)在囱持,通過訪問http://127.0.0.1:8000/snippets/,在Web瀏覽器中打開API 焕济。

瀏覽功能

由于API根據(jù)客戶端請求選擇響應的內容類型纷妆,因此默認情況下,當Web瀏覽器請求資源時晴弃,將返回HTML格式的資源表示形式掩幢。這允許API返回完全的可瀏覽網(wǎng)頁的HTML表示。

擁有一個可瀏覽網(wǎng)頁的API是一個巨大的可用性的勝利上鞠,使開發(fā)和使用您的API更容易际邻。它也大大降低了想要檢查和使用您的API的其他開發(fā)人員的進入門檻。

有關瀏覽的API功能以及如何對其進行定制的更多信息芍阎,請參閱可瀏覽的API主題世曾。

下一步是什么?

教程第3部分中谴咸,我們將開始使用基于類的視圖度硝,并查看通用視圖如何減少我們需要編寫的代碼量。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末寿冕,一起剝皮案震驚了整個濱河市蕊程,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驼唱,老刑警劉巖藻茂,帶你破解...
    沈念sama閱讀 207,113評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異,居然都是意外死亡辨赐,警方通過查閱死者的電腦和手機优俘,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,644評論 2 381
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掀序,“玉大人帆焕,你說我怎么就攤上這事〔还В” “怎么了叶雹?”我有些...
    開封第一講書人閱讀 153,340評論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長换吧。 經(jīng)常有香客問我折晦,道長,這世上最難降的妖魔是什么沾瓦? 我笑而不...
    開封第一講書人閱讀 55,449評論 1 279
  • 正文 為了忘掉前任满着,我火速辦了婚禮贯莺,結果婚禮上,老公的妹妹穿的比我還像新娘缕探。我一直安慰自己,他們只是感情好撕蔼,可當我...
    茶點故事閱讀 64,445評論 5 374
  • 文/花漫 我一把揭開白布鲸沮。 她就那樣靜靜地躺著讼溺,像睡著了一般最易。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上藻懒,一...
    開封第一講書人閱讀 49,166評論 1 284
  • 那天归敬,我揣著相機與錄音,去河邊找鬼汪茧。 笑死,一個胖子當著我的面吹牛呀舔,可吹牛的內容都是我干的媚赖。 我是一名探鬼主播驴剔,決...
    沈念sama閱讀 38,442評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼豺妓!你這毒婦竟也來了布讹?” 一聲冷哼從身側響起描验,我...
    開封第一講書人閱讀 37,105評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎絮缅,沒想到半個月后呼股,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體彭谁,經(jīng)...
    沈念sama閱讀 43,601評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 36,066評論 2 325
  • 正文 我和宋清朗相戀三年则奥,在試婚紗的時候發(fā)現(xiàn)自己被綠了读处。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片罚舱。...
    茶點故事閱讀 38,161評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖馆匿,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情阿逃,我是刑警寧澤恃锉,帶...
    沈念sama閱讀 33,792評論 4 323
  • 正文 年R本政府宣布破托,位于F島的核電站,受9級特大地震影響土砂,放射性物質發(fā)生泄漏谜洽。R本人自食惡果不足惜阐虚,卻給世界環(huán)境...
    茶點故事閱讀 39,351評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望奥秆。 院中可真熱鬧咸灿,春花似錦、人聲如沸析显。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,352評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至孔庭,卻和暖如春材蛛,著一層夾襖步出監(jiān)牢的瞬間卑吭,已是汗流浹背马绝。 一陣腳步聲響...
    開封第一講書人閱讀 31,584評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留掷邦,地道東北人抚岗。 一個月前我還...
    沈念sama閱讀 45,618評論 2 355
  • 正文 我出身青樓宣蔚,卻偏偏與公主長得像认境,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子篷扩,可洞房花燭夜當晚...
    茶點故事閱讀 42,916評論 2 344

推薦閱讀更多精彩內容