請求HttpRequest
提示:
- 用戶發送請求時攜帶的參數后端需要使用,而不同的發送參數的方式對應了不同的提取參數的方式
- 所以要學會如何提取參數,我們就需要先了解前端傳參數有哪些方式
回想一下,利用HTTP協議向服務器傳參有幾種途徑?
- 查詢字符串數據(query string):
- 形如:
?key1=value1&key2=value2
- 比如:
http://www.meiduo.site/list/115/1/?sort=price
中的?sort=price
- 形如:
- 請求體數據(body):
- 比如:表單數據、json、......
- URL路徑中的特定部分數據:
- 比如:
http://www.meiduo.site/detail/2/
中的/2/
- 請求地址中的該部分數據,可以在路由中使用正則表達式提取出來
- 比如:
- 請求頭數據:
- HTTP請求報文中的請求頭數據(header)
為了演示請求和響應,我們會新建一個子應用
request_response
去演示相關內容
1. 提取查詢字符串數據
提示:
- 獲取請求路徑中的查詢字符串參數,形如:
?k1=v1&k2=v2
- 可以通過
request.GET
屬性獲取,並返回QueryDict類型的對象
# 注冊總路由 urlpatterns = [ # 用戶模塊:http://127.0.0.1:8000/users/register/ path('', include('users.urls')), # 請求和響應 path('', include('request_response.urls')), ]
# 注冊子路由 urlpatterns = [ # 測試提取查詢字符串參數:http://127.0.0.1:8000/querystring/?name=zxc&age=18 path('querystring/', views.QSParamView.as_view()), ]
class QSParamView(View): """測試提取查詢字符串參數 http://127.0.0.1:8000/querystring/?name=zxc&age=18 """ def get(self, request): # 獲取查詢字符串參數name、age name = request.GET.get('name', '小明') age = request.GET.get('age', '0') return http.HttpResponse('查詢字符串參數:%s--%s' % (name, age))
重要提示:
- 提取查詢字符串參數不區分請求方式,即使客戶端進行POST方式的請求,依然可以通過request.GET獲取請求中的查詢字符串參數。
QueryDict
補充:
QueryDict
是由Django自己封裝的一個數據類型,繼承自python的字典Dict- 它被定義在
django.http.QueryDict
中 - 它專門用來存儲請求中提取的查詢字符串參數和請求體參數
- 即,HttpRequest對象中的屬性GET、POST都是QueryDict類型的數據
QueryDict
的使用:# 如果鍵不存在則返回None值,可以設置默認值進行后續處理 query_dict.get('鍵',默認值) # 可簡寫為: query_dict['鍵']
2. 提取請求體數據
提示:
- 可以發送請求體數據的請求方式有:POST、PUT、PATCH、DELETE
- 請求體數據格式不固定,常見的有:
表單類型數據和JSON字符串類型
,我們應區別對待
2.1 表單類型請求體數據(Form Data)
前端發送的表單類型的請求體數據,可以通過
request.POST
屬性獲取,並返回QueryDict對象。
# 測試提取表單類型請求體數據:http://127.0.0.1:8000/formdata/ path('formdata/', views.FormDataParamView.as_view()),
class FormDataParamView(View): """測試提取表單類型請求體參數 http://127.0.0.1:8000/formdata/ """ def post(self, request): # 獲取表單類型請求體參數中的username、password username = request.POST.get('username') password = request.POST.get('password') return http.HttpResponse('表單類型請求體參數:%s--%s' % (username, password))
重要提示:
request.POST
只能用來獲取POST表單發送的請求體數據
2.2 非表單類型請求體數據(Non-Form Data):JSON
提示:
- 非表單類型的請求體數據,Django無法自動解析,可以通過
request.body
屬性獲取最原始的請求體數據 - 然后自己按照具體請求體原始數據的格式(JSON等)進行解析
request.body
獲取的是bytes類型
的請求體原始數據
需求:
- 獲取請求體中的如下JSON數據
{
"username": "張小廚", "password": "123" }
可以進行如下方法操作:
# 測試提取非表單類型請求體參數:http://127.0.0.1:8000/json/ path('json/', views.JSONParamView.as_view()),
import json class JSONParamView(View): """測試提取非表單類型請求體參數 http://127.0.0.1:8000/json/ """ def post(self, request): # 獲取請求體中原始的JSON數據 json_str = request.body # 使用json模塊將原始的JSON數據轉字典 json_dict = json.loads(json_str) # 提取JSON數據中的參數 username = json_dict.get('username') password = json_dict.get('password') return http.HttpResponse('非表單類型請求體參數:%s--%s' % (username, password))
3. URL路徑參數:提取URL路徑中的特定部分數據
提示:
- 在定義路由時,可以從URL中獲取特定部分的路徑參數
- Django的路由系統會將提取的路徑參數傳遞到視圖的內部
- path()和re_path()都可以提取路徑參數
需求:
- 需求1:
http://127.0.0.1:8000/url_param1/18/
- 提取路徑中的數字
18
- 提取路徑中的數字
- 需求2:
http://127.0.0.1:8000/url_param2/18500001111/
- 提取路徑中的手機號
18500001111
- 提取路徑中的手機號
3.1 path()提取路徑參數
實現需求1
# 測試path()提取普通路徑參數:http://127.0.0.1:8000/url_param1/18/ path('url_param1//', views.URLParam1View.as_view()),
class URLParam1View(View): """測試path()提取普通路徑參數 http://127.0.0.1:8000/url_param1/18/ """ def get(self, request, age): """ :param age: 路由提取的關鍵字參數 """ return http.HttpResponse('測試path()提取普通路徑參數:%s' % age)
重要提示:
- 路由中提取路徑參數時,使用的關鍵字,必須跟視圖中參數名一致
思考:
- 實現需求1時提取age數字的
是什么?
結論:
- 路由轉換器
- Django默認封裝了一些正則表達式,用於在path()中要提取路徑參數時使用
默認的路由轉換器:
- 位置在
django.urls.converters.py
DEFAULT_CONVERTERS = {
'int': IntConverter(), # 匹配正整數,包含0 'path': PathConverter(), # 匹配任何非空字符串,包含了路徑分隔符 'slug': SlugConverter(), # 匹配字母、數字以及橫杠、下划線組成的字符串 'str': StringConverter(), # 匹配除了路徑分隔符(/)之外的非空字符串,這是默認的形式 'uuid': UUIDConverter(), # 匹配格式化的uuid,如 075194d3-6885-417e-a8a8-6c931e272f00 }
實現需求2
http://127.0.0.1:8000/url_param2/18500001111/
- 提取路徑中的手機號
18500001111
- 提取路徑中的手機號
問題:
- 默認的路由轉換器中,沒有專門用來匹配手機號的路由轉換器
- 所以在使用path()實現需求2時,就無法直接使用默認的路由轉換器
解決方案:
- 如果默認的路由轉換器無法滿足需求時,我們就需要自定義路由轉換器
實現需求2:自定義路由轉換器
- 在任意可以被導入的python文件中,都可以自定義路由轉換器
-
比如:在工程根目錄下,新建
converters.py
文件,用於自定義路由轉換器class MobileConverter: """自定義路由轉換器:匹配手機號""" # 匹配手機號碼的正則 regex = '1[3-9]\d{9}' def to_python(self, value): # 將匹配結果傳遞到視圖內部時使用 return int(value) def to_url(self, value): # 將匹配結果用於反向解析傳值時使用 return str(value)
-
注冊自定義路由轉換器
-
在總路由中,注冊自定義路由轉換器
from django.urls import register_converter from converters import MobileConverter # 注冊自定義路由轉換器 # register_converter(自定義路由轉換器, '別名') register_converter(MobileConverter, 'mobile') urlpatterns = []
-
-
使用自定義路由轉換器
# 測試path()中自定義路由轉換器提取路徑參數:手機號 http://127.0.0.1:8000/url_param2/18500001111/ path('url_param2/<mobile:phone_num>/', views.URLParam2View.as_view()),
class URLParam2View(View): """測試path()中自定義路由轉換器提取路徑參數:手機號 http://127.0.0.1:8000/url_param2/18500001111/ """ def get(self, request, phone_num): """ :param phone_num: 路由提取的關鍵字參數 """ return http.HttpResponse('測試path()提取路徑參數手機號:%s' % phone_num)
3.2 re_path()提取路徑參數
# 測試re_path()提取路徑參數:http://127.0.0.1:8000/url_param3/18500001111/ re_path(r'^url_param3/(?P<phone_num>1[3-9]\d{9})/$', views.URLParam3View.as_view()),
class URLParam3View(View): """測試re_path()提取路徑參數 http://127.0.0.1:8000/url_param3/18500001111/ """ def get(self, request, phone_num): """ :param phone_num: 路由提取的關鍵字參數 """ return http.HttpResponse('測試re_path()提取路徑參數:%s' % phone_num)
3.3 path()和re_path()如何選擇?
- path()語法相對簡潔一些,如果沒有路徑參數要提取或者要提取的路徑參數可以使用默認的路由轉換器實現時,就選擇path()。
- re_path()語法相對復雜一些,但是,如果希望在匹配路由時,由自己編寫所有的正則表達式,就選擇re_path()。
- 需要注意的是,在使用re_path()時,網絡地址正則表達式一定要寫完整,要有嚴格的開頭和結尾
4. 請求頭
可以通過request.META
屬性獲取請求頭headers中的數據,request.META
為字典類型。
常見的請求頭如:
CONTENT_LENGTH
– The length of the request body (as a string).CONTENT_TYPE
– The MIME type of the request body.HTTP_ACCEPT
– Acceptable content types for the response.HTTP_ACCEPT_ENCODING
– Acceptable encodings for the response.HTTP_ACCEPT_LANGUAGE
– Acceptable languages for the response.HTTP_HOST
– The HTTP Host header sent by the client.HTTP_REFERER
– The referring page, if any.HTTP_USER_AGENT
– The client’s user-agent string.QUERY_STRING
– The query string, as a single (unparsed) string.REMOTE_ADDR
– The IP address of the client.REMOTE_HOST
– The hostname of the client.REMOTE_USER
– The user authenticated by the Web server, if any.REQUEST_METHOD
– A string such as"GET"
or"POST"
.SERVER_NAME
– The hostname of the server.SERVER_PORT
– The port of the server (as a string).
具體使用如:
class HeadersParamView(View): """測試提取請求頭參數""" def get(self, request): # 獲取請求頭中文件的類型 ret = request.META.get('CONTENT_TYPE') return http.HttpResponse('OK')
5. 其他常用HttpRequest對象屬性
- method:一個字符串,表示請求使用的HTTP方法,常用值包括:'GET'、'POST'。
- FILES:一個類似於字典的對象,包含所有的上傳文件。
- COOKIES:一個字符串,包含了瀏覽器自動發送的cookie緩存數據。
- user:請求中認證出來的用戶對象。