Django HttpRequest 常用屬性介紹
文章目錄
Let's Django!
這是 Django Tutorial 系列連載的第 4 篇。
範例程式碼可參考我的 GitHub 專案。
如〈Django Tutorial:系列介紹與導讀〉所言,這個系列主要是圍繞著「Django API」教學展開的。
但無論是用 Django 建立全端網站,還是開發 API,Django 的 HttpRequest——也就是我們熟悉的request
參數——都是必不可少的元素。
HttpRequest
封裝了來自前端的 HTTP 請求,而 Django 會將HttpRequest
物件自動帶入 view 函式的第一位置參數(通常就叫request
),讓我們可以直接使用。
為何需要了解 HttpRequest
物件
在我剛開始寫 Django 的時候,根本不太清楚HttpRequest
具體有哪些屬性。
通常是看教學或為了實作某個功能而 Google 的時候,看到範例程式碼使用某個屬性,然後才知道這個屬性的存在。比如:
1 | if request.method == "GET": |
看到這段,才知道request
有一個method
屬性。
這樣學當然可以,但如果一開始就對常用的HttpRequest
屬性有基本了解,會讓你在學習 Django 的路上更加踏實。
本文主旨與目標讀者
基於上述考量,我覺得還是有必要整理一下,對於 Django 初學者而言,最常用或需要了解的HttpRequest
屬性。
不求多深,或知悉所有屬性的具體用法。面對HttpRequest
這樣內容豐富的物件,我們掌握 80/20 法則,了解其中最重要的幾個,往往就能很有收獲。
至少,如果讓我重來,我會希望自己一開始就對這些屬性有一定認識。
目標讀者
本文的目標讀者,是 Django 初學者。
無論想寫 Django 全端網站(也就是會用到 Django Form 與 Template),還是開發 API。這些屬性都相對重要,或至少要知道它有何「替代品」。
因此,我還會適時補充,使用框架(DRF、Django Ninja)開發 API 時,這些屬性是否被框架提供的新屬性取代。
開始前的小提醒
本文對HttpRequest
屬性與介紹內容,主要整理自官方文件,我會適度引用原文,並加上我的經驗、看法。
提醒你:
- 看完之後,如果依舊覺得不熟悉這些屬性,那也無妨,有基本的認識就很好了!
- 所有的例示以 FBV(function-based view)為主,這是 Django 初學者最常接觸的 view 寫法。
以下依各個屬性在文件中出現的順序,一一介紹。
一、HttpRequest.method
A string representing the HTTP method used in the request. This is guaranteed to be uppercase.
表示請求所使用的 HTTP 方法,有兩個重點:
- 型別為字串。
- 而且字串值一定是全大寫。比如
"GET"
、"POST"
等。
這或許是新手一開始最常呼叫的屬性XD。當然,前提是你寫的是 FBV(function-based view)。
在 view 函式中的用法前面已經提過:
1 | if request.method == "GET": |
二、HttpRequest.GET
A dictionary-like object containing all given HTTP GET parameters. See the
QueryDict
documentation below.
用來獲得 HTTP request 的「URL 參數」內容,比如你透過 GET 方法存取下列網址:
1 | https://www.books.com/search?category=novel&author=Asimov |
這個屬性可取得?
後面的「category=novel&author=Asimov
」這段資訊。
而且屬性值的資料型別,是一個QueryDict
。
關於QueryDict
,你目前只需要知道,它是一個類似字典的物件,而值主要是字串,或元素為字串的 Python list——如果一個 key 有多個值。
以下是用法:
1 | def search_books(request): |
不限於 GET 方法
雖然叫做GET
,但實際上這個屬性不限於 GET 方法,只要是 URL 參數,都可以透過這個屬性取得。
畢竟除了 GET 方法,還有 DELETE、PATCH 等方法,也都可以透過 URL 參數傳遞資訊。只是因為 GET 方法最常見,所以這個屬性叫做GET
。
我覺得這個命名多少有點誤導性,但不算是大問題。
使用 DRF 框架
在 DRF(Django REST framework)的 request 中,官方推薦你使用 query_params 屬性代替GET
屬性:
For clarity inside your code, we recommend using
request.query_params
instead of the Django’s standardrequest.GET
.
如前所述,GET
屬性名稱有點誤導性,而 DRF 的query_params
確實比較合理。
至於是不是要遵守這個建議,我覺得最大的重點是「整個專案的一致性」——不要有人寫query_params
、有人寫GET
。
而 Django Ninja 則沒有這個問題(不需要用到GET
屬性),以後介紹 Django Ninja 再詳談。
三、HttpRequest.POST
A dictionary-like object containing all given HTTP POST parameters, providing that the request contains form data.
See the
QueryDict
documentation below.
If you need to access raw or non-form data posted in the request, access this through the
HttpRequest.body
attribute instead.
POST
does not include file-upload information. SeeFILES
.
我故意把一段原文分 4 段引用,因為它有下列重點:
- 這個
POST
屬性,必須你的 HTTP 請求是 POST 方法。(對應第一段) - 內容是 POST 請求中附帶的「表單資訊(form data)」。(對應第一段,這是最重要的一點!)
- 值的型別也是
QueryDict
。如前所述,值必為字串。(對應第二段) - 如果想取得 form data 以外的內容,要使用
HttpRequest.body
。(對應第三段) - 不包含上傳的檔案。因為已經有
FILES
屬性。(對應第四段)
只限 form data
簡單來說,這個屬性值對應 POST 請求中的 body,但 header 的Content-Type
必須為application/x-www-form-urlencoded
才行。
即 body 必須是 form data,否則POST
屬性不會有值。
不得不說,這屬性名稱也一樣有點誤導,因為它只限於 form data。
當Content-Type
是application/json
或其他非表單的類型時,HttpRequest.POST
將會是空的,因為 Django 不會自動解析這些類型的資訊到 POST
屬性中。
只限 POST 方法
和GET
屬性不同,POST
屬性「只限」使用 POST 方法,這點要特別注意。
可是,其餘帶有 body 的方法,比如 PUT、PATCH、DELETE,也可能有 form data,但 Django 也不會自動解析到POST
屬性中。此時該怎麼辦?
答案是:使用request.body
屬性,自行解析。
HttpRequest.body
上述的request.POST
有一定的限制,而body
屬性更加全面。它也是代表 HTTP 請求 body 資料,不限於 POST 方法,且不限於 form data。
不過,它的屬性值型別是 bytestring:
The raw HTTP request body as a bytestring.
你需要手動處理這個 bytestring,比如使用json.loads()
解析 JSON body:
1 | import json |
有點麻煩!
因此,實際上我們比較少用到request.body
,而是用 DRF 的 request.data 屬性,或 Django Ninja 的 Schema。
它們會自動解析 body 資料,並轉換成 Python 物件。
程式碼實例
想像一個申請表單:
1 | def submit_form(request): |
其中要注意的是,HTTP POST 方法才會有request.POST
屬性值,所以一定要先檢查方法:if request.method == 'POST'
。
並且如上所述,即使是 POST 方法,如果請求 body 不是 form data,request.POST
依舊是空的。
實務使用建議
上述細節可能會新手有點眼花撩亂,不過別擔心,我們從一個更 high level 的角度看。
如果你寫的是「全端」Django,也就是包括了 Django Form 和模板,那這個POST
屬性應該會很常用。因為前端(也就是 Django 模板)會傳來大量的 form data。
但如果你是寫 API,則這個屬性基本上不會用到。因為 API 的前端請求,往往是 JSON 格式,即Content-Type
為application/json
,而不會是 form data。
簡言之:
- 寫全端 Django 用
request.POST
屬性。 - 寫 API 則是用別的屬性,比如 DRF 的
request.data
。
四、HttpRequest.FILES
A dictionary-like object containing all uploaded files. Each key in
FILES
is thename
from the<input type="file" name="">
. Each value inFILES
is anUploadedFile
.
上傳檔案必備!
注意,這個FILES
只是一個類字典,字典的每一個 key 的值才是你上傳的檔案。
FILES
will only contain data if the request method was POST and the<form>
that posted to the request hadenctype="multipart/form-data"
. Otherwise,FILES
will be a blank dictionary-like object.
重點:
- 必須使用 POST 方法。
- 而且
Content-Type
為multipart/form-data
。
至於在 view 函式中的操作與使用,較為複雜(牽涉到 FileField),可自行參考文件,在此先略不介紹。
五、關於 Headers
HttpRequest.META
¶
A dictionary containing all available HTTP headers.
HttpRequest.headers
¶
A case insensitive, dict-like object that provides access to all HTTP-prefixed headers (plus
Content-Length
andContent-Type
) from the request.
這部分我們已經有過專文介紹,可直接參考:
六、Attributes set by middleware
從 Django 的 middleware 整合而獲得的屬性,這些屬性的值「不屬於」HTTP 請求中的資料,而是 Django 基於方便開發,自動幫你加上去的。
比較重要且常用的是這兩個:
HttpRequest.session
HttpRequest.user
這些可以等用到相關 Django 模組時,再深入了解即可。