**本文深入探討了 Django 中的請求與響應處理,從 Django 請求和響應的基礎知識、生命周期,到 HttpRequest 和 HttpResponse 對象的詳細介紹。同時,討論了 Django 的視圖和請求、響應處理,以及安全性和非同步處理的考慮。最後,對比了 Django 與 Flask ...
本文深入探討了 Django 中的請求與響應處理,從 Django 請求和響應的基礎知識、生命周期,到 HttpRequest 和 HttpResponse 對象的詳細介紹。同時,討論了 Django 的視圖和請求、響應處理,以及安全性和非同步處理的考慮。最後,對比了 Django 與 Flask、FastAPI 等框架在請求響應處理上的異同。無論您是 Django 新手還是有經驗的開發者,這篇文章都能幫助您更好地理解 Django 的請求和響應處理。
1. Django 請求HttpRequest和響應HttpResponse的基礎知識
在Web應用程式中,請求和響應模式是非常重要的概念。當用戶在瀏覽器地址欄輸入一個URL或者點擊某個鏈接時,會向伺服器發送一個請求。伺服器處理完這個請求後,會返回一個響應給瀏覽器。這就是典型的HTTP請求-響應模式。
1.1 Django 的請求對象HttpRequest
在 Django 中,當一個 HTTP 請求到達 Django 應用時,它首先會被某個URLconf文件轉化為一個 HttpRequest 對象。這個對象包含了這次HTTP請求的所有相關的信息。
def view(request):
# request 是一個 HttpRequest 對象
print(request.method) # 輸出請求方法,比如 "GET" 或 "POST"
1.2 Django 的響應對象HttpResponse
Django的視圖必須返回一個 HttpResponse 對象。這個對象表示伺服器給客戶端(通常是瀏覽器)的響應。這個 HttpResponse 對象會被轉化為一個 HTTP 響應,然後被髮送到客戶端。
from django.http import HttpResponse
def view(request):
# 創建一個 HttpResponse 對象
response = HttpResponse("Hello, World!")
return response # 這個響應將會被髮送給客戶端
1.3 HTTP 方法Get/Post
HTTP 方法是客戶端可以對伺服器發出的一種 "指令"。最常見的方法包括 GET 和 POST。
- GET: 通常用於獲取(或查詢)資源信息。
- POST: 通常用於更新資源信息。
在 Django 中,你可以通過 HttpRequest 對象的 method
屬性來訪問這個請求的方法:
def view(request):
print(request.method) # 輸出請求方法,比如 "GET" 或 "POST"
2. Django 請求的生命周期
一旦Django應用收到了一個HTTP請求,它會經歷一系列的階段,這些階段共同構成了請求的生命周期。以下是這個過程的詳述:
2.1 請求到達
當一個請求到達Django應用時,它首先會被WSGI伺服器接收。Django項目被WSGI伺服器(如Gunicorn或uWSGI)作為一個Python應用程式運行。
# 這是一個簡單的WSGI應用的示例,當然,實際的Django WSGI應用更加複雜
def application(environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return [b"Hello World!"]
2.2 URL 解析
接下來,請求會被送到URL解析器,URL解析器會根據URLConf模塊中定義的URL模式列表對URL進行匹配。URL模式是使用Python的正則表達式來定義的。
# urls.py
from django.urls import path
from . import views
urlpatterns = [
path('articles/2003/', views.special_case_2003),
path('articles/<int:year>/', views.year_archive),
]
2.3 視圖處理
一旦URL解析器找到了匹配的模式,它會調用與該模式關聯的視圖函數,並將HttpRequest對象和從URL中提取的任何參數傳遞給該視圖。
# views.py
from django.http import HttpResponse
def special_case_2003(request):
return HttpResponse("Special case for 2003")
def year_archive(request, year):
return HttpResponse(f"Articles for {year}")
2.4 響應返回
視圖函數處理完請求後,會創建一個HttpResponse對象並返回。這個響應對象會經過中間件的一系列處理,最終會被轉換為一個HTTP響應,然後發送給客戶端。
# 視圖函數返回一個響應
def view(request):
response = HttpResponse("Hello, World!")
return response # 這個響應將會被髮送給客戶端
3. Django HttpRequest詳述
在 Django 中,所有的 HTTP 請求都被封裝在 HttpRequest 對象中。下麵我們將詳細介紹 HttpRequest 對象的常見屬性和方法。
3.1 HttpRequest 屬性
HttpRequest 對象有很多屬性,可以幫助我們獲取 HTTP 請求的詳細信息。以下是一些最常用的屬性:
-
path: 一個字元串,表示請求的路徑,不包括功能變數名稱或者站點根 URL 的路徑。
-
method: 一個字元串,表示 HTTP 請求的方法。常見的值有 "GET","POST" 等。
-
GET: 一個類似字典的對象,包含所有的 GET 參數。
-
POST: 一個類似字典的對象,包含所有的 POST 參數。
-
COOKIES: 一個字典,包含所有的 cookie。鍵和值都為字元串。
-
FILES: 一個類似字典的對象,包含所有的上傳文件。
-
user: 一個表示當前用戶的 User 對象。如果用戶當前未登錄,這將是一個 AnonymousUser 實例。
def view(request):
# 列印一些 HttpRequest 屬性的值
print(request.path) # 輸出請求路徑,比如 "/my-path/"
print(request.method) # 輸出請求方法,比如 "GET"
print(request.GET) # 輸出 GET 參數,比如 <QueryDict: {'key': ['value']}>
print(request.user) # 輸出當前用戶,如果用戶未登錄,將輸出 AnonymousUser
3.2 HttpRequest 方法
除了屬性,HttpRequest 對象還有一些有用的方法:
-
is_ajax(): 如果請求是通過 XMLHttpRequest 發出的,返回 True。
-
is_secure(): 如果請求是通過 HTTPS 發出的,返回 True。
-
is_authenticated(): 如果當前用戶已經登錄,返回 True。
def view(request):
# 列印一些 HttpRequest 方法的返回值
print(request.is_ajax()) # 如果請求是 AJAX 請求,輸出 True
print(request.is_secure()) # 如果請求是 HTTPS 請求,輸出 True
print(request.is_authenticated()) # 如果當前用戶已登錄,輸出 True
4. Django 視圖View和請求HttpRequest處理
在 Django 中,視圖是一個 Python 函數,用於接收一個 Web 請求並返回一個 Web 響應。這個響應可以是 Web 頁面的 HTML 內容,重定向,404 錯誤,XML 文檔,圖像,或者任何其他類型的內容。簡單來說,Django 視圖的任務就是接受一個 Web 請求並返回一個 Web 響應。
4.1 創建視圖
在 Django 中,創建一個視圖只需要定義一個 Python 函數,這個函數需要接受一個 HttpRequest
對象作為第一個參數,然後返回一個 HttpResponse
對象。如下所示:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello, World!")
在這個例子中,hello
函數就是一個視圖,它接收一個 HttpRequest
對象,然後返回一個包含 "Hello, World!" 的 HttpResponse
對象。
4.2 視圖參數
視圖函數的第一個參數總是 HttpRequest
對象,而從 URL 中捕獲的參數將作為額外的參數傳遞給視圖函數。例如:
from django.http import HttpResponse
def hello(request, name):
return HttpResponse(f"Hello, {name}!")
在這個例子中,hello
視圖接受兩個參數:一個 HttpRequest
對象和一個 name
字元串。你可以在 URLConf 中定義如何從 URL 中提取這個 name
參數。
4.3 HttpResponse 對象
視圖必須返回一個 HttpResponse
對象。HttpResponse
類在 django.http
模塊中定義,表示一個 HTTP 響應,或者說是一個伺服器給客戶端的回應。
HttpResponse
對象通常包含文本內容,可以是 HTML,也可以是 JSON。除了文本內容,你還可以通過設置 HttpResponse
的不同屬性(比如 content_type
和 status
)來控制其他 HTTP 響應的參數。
from django.http import HttpResponse
def hello(request):
response = HttpResponse("Hello, World!", content_type="text/plain", status=200)
return response
5. Django HttpResponse詳述
HttpResponse 對象是 Django 視圖中返回的結果對象,它是由 Django 視圖返回並通過 Django 框架傳送給客戶端的。
5.1 HttpResponse 屬性
HttpResponse 對象有一些常用的屬性,我們可以使用它們來定義我們的響應。以下是一些常見的屬性:
-
content: 響應的主體內容,通常為一個字元串或位元組串。
-
status_code: HTTP 狀態碼,如 200、404 等。
-
content_type: 響應的 MIME 類型,預設為 'text/html'。
from django.http import HttpResponse
def view(request):
response = HttpResponse()
response.content = "Hello, World!"
response.status_code = 200
response.content_type = 'text/plain'
return response
5.2 HttpResponse 方法
除了屬性,HttpResponse 對象還有一些有用的方法:
-
set_cookie(key, value, max_age=None, expires=None): 設置一個 Cookie。key 是 Cookie 的名字,value 是 Cookie 的值。max_age 是 Cookie 的最大生存時間,單位是秒。expires 是 Cookie 的過期時間,是一個 datetime 對象或 UNIX 時間戳。
-
delete_cookie(key): 刪除一個 Cookie。
from django.http import HttpResponse
def view(request):
response = HttpResponse("Hello, World!")
response.set_cookie('my_cookie', 'cookie_value', max_age=60*60*24) # 設置一個一天後過期的 Cookie
return response
5.3 特殊的 HttpResponse 對象
除了普通的 HttpResponse 對象,Django 還提供了一些特殊的 HttpResponse 對象,用於生成特定的響應。例如:
-
JsonResponse: 這個響應對象接收一個字典或列表,並返回一個 application/json 類型的響應。
-
HttpResponseRedirect: 這個響應對象用於生成一個重定向響應。
-
HttpResponseNotFound: 這個響應對象用於生成一個 404 錯誤響應。
from django.http import JsonResponse, HttpResponseRedirect, HttpResponseNotFound
def view_json(request):
return JsonResponse({'key': 'value'}) # 返回一個 JSON 響應
def view_redirect(request):
return HttpResponseRedirect('/another-url/') # 重定向到另一個 URL
def view_404(request):
return HttpResponseNotFound('<h1>Page not found</h1>') # 返回一個 404 錯誤
6. Django 視圖View和HttpResponse響應處理
在 Django 中,視圖是 Web 請求的主要處理者,同時也負責構建和返迴響應。視圖接收 HttpRequest 對象作為參數,生成 HttpResponse 對象作為返回值。我們已經詳細討論了 HttpRequest 和 HttpResponse,現在我們來看看如何在視圖中處理它們。
6.1 處理請求
處理請求主要是提取 HttpRequest 對象的數據,然後根據這些數據執行相應的邏輯。
def view(request):
# 獲取 GET 請求的參數
name = request.GET.get('name', 'Guest')
# 根據請求參數執行邏輯
message = f"Hello, {name}!"
return HttpResponse(message)
在這個例子中,我們從 GET 請求中獲取 'name' 參數,然後用它來生成一條歡迎消息。
6.2 構建響應
構建響應主要是創建 HttpResponse 對象,然後填充其內容。
def view(request):
# 創建 HttpResponse 對象
response = HttpResponse()
# 填充響應內容
response.content = "Hello, World!"
response.status_code = 200
response['Content-Type'] = 'text/plain'
return response
在這個例子中,我們創建了一個 HttpResponse 對象,然後設置了其內容、狀態碼和 Content-Type 頭。
6.3 快捷方式
在 Django 視圖中,我們經常需要做一些常見的操作,比如渲染一個模板,重定向到另一個 URL,或者返回一個 404 錯誤。為了簡化這些操作,Django 提供了一些快捷方式。
from django.shortcuts import render, redirect, get_object_or_404
from .models import MyModel
def view(request):
# 渲染一個模板
context = {'key': 'value'}
return render(request, 'my_template.html', context)
def redirect_view(request):
# 重定向到另一個 URL
return redirect('/another-url/')
def detail_view(request, pk):
# 獲取一個對象或返回 404 錯誤
obj = get_object_or_404(MyModel, pk=pk)
return render(request, 'detail.html', {'obj': obj})
7. Django 請求和響應的安全性考慮
在處理 Web 請求和生成響應時,安全性是一個非常重要的考慮因素。幸運的是,Django 提供了一些內置的工具和技術來幫助我們增加應用程式的安全性。
7.1 CSRF 保護
跨站請求偽造(CSRF)是一種攻擊方式,攻擊者可以偽造用戶的請求。Django 提供了 CSRF 保護機制,可以在處理 POST 請求時自動檢查 CSRF 令牌。
from django.views.decorators.csrf import csrf_exempt
@csrf_exempt # 用這個裝飾器來禁用 CSRF 保護
def my_view(request):
# view code here...
在大多數情況下,你應該讓 Django 自動處理 CSRF 保護。但是在某些情況下,你可能需要禁用它,比如上面的例子。
7.2 安全的數據存儲
當你在處理請求時接收到敏感信息,如密碼,你應該使用 Django 提供的安全方法來存儲這些信息。
from django.contrib.auth.hashers import make_password
def register(request):
password = request.POST['password']
hashed_password = make_password(password) # 使用哈希函數來安全存儲密碼
# save hashed_password to database...
7.3 HTTP 響應頭的安全設置
Django 提供了一些設置,你可以使用它們來增加 HTTP 響應頭的安全性,如 SECURE_CONTENT_TYPE_NOSNIFF
和 SECURE_BROWSER_XSS_FILTER
。你可以在你的 Django 設置中配置它們。
# settings.py
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
7.4 用戶輸入的安全處理
永遠不要信任用戶輸入的數據。你應該始終對用戶輸入的數據進行清洗和驗證。
from django.core.exceptions import ValidationError
def view(request):
comment = request.POST['comment']
if len(comment) > 100:
raise ValidationError("Comment is too long!")
# save comment to database...
8. Django 非同步請求和響應
Django 3.1 引入了非同步視圖和中間件支持,這意味著你可以使用 Python 的 async
和 await
關鍵字來處理非同步任務。這對於處理 I/O 綁定任務或其他可以從併發執行中受益的任務非常有用。
8.1 非同步視圖
創建非同步視圖的方式與創建同步視圖非常相似,但是你需要將視圖函數定義為 async def
函數,然後在函數體中使用 await
關鍵字。
from django.http import JsonResponse
async def async_view(request):
data = await get_data() # 假設 get_data 是一個非同步函數
return JsonResponse(data)
在這個例子中,get_data
是一個非同步函數,我們使用 await
關鍵字來調用它。當 Django 等待 get_data
完成時,它可以釋放伺服器資源來處理其他請求。
8.2 非同步中間件
你也可以創建非同步中間件,它可以處理進入視圖之前或離開視圖之後的請求和響應。
class SimpleMiddleware:
async def __call__(self, request, get_response):
response = await get_response(request)
return response
在這個例子中,SimpleMiddleware
是一個非同步中間件,它在處理請求之前和之後沒有做任何事情,只是簡單地將請求傳遞給下一個中間件或視圖。
8.3 資料庫操作
在 Django 的非同步視圖或中間件中,你不應該執行同步的資料庫操作,因為這可能會阻塞事件迴圈。你應該使用 Django 提供的 asgiref.sync.sync_to_async
函數將同步的資料庫操作包裝到一個線程中。
from asgiref.sync import sync_to_async
from django.contrib.auth.models import User
async def async_view(request):
get_user = sync_to_async(User.objects.get)
user = await get_user(id=1)
return JsonResponse({'username': user.username})
在這個例子中,我們使用 sync_to_async
函數將 User.objects.get
包裝到一個線程中,然後在非同步視圖中使用 await
關鍵字來調用它。
當然,接下來我們就來比較一下 Django 與其他主流 Python 框架(如 Flask 和 FastAPI)在請求和響應處理上的異同。
總結. Django 與其他主流 Python 框架在請求響應部分的比較
9.1 Django vs Flask
Flask 是另一個流行的 Python web 框架,相比 Django,Flask 是一個更為輕量級的框架,具有更高的定製性。
-
請求對象: Flask 的
request
對象和 Django 的HttpRequest
對象在許多方面是相似的,但 Flask 的request
對象在語法上更為簡潔。在 Flask 中,你可以直接通過request.form['key']
來訪問 POST 參數,而在 Django 中,你需要使用request.POST.get('key')
。 -
響應對象: Flask 允許你直接從視圖返回字元串,然後自動將其轉化為
Response
對象,而 Django 則需要你顯式地創建一個HttpResponse
對象。 -
URL 參數: Flask 提供了一種簡潔的方式來在 URL 中定義參數,如
@app.route('/user/<username>')
,而在 Django 中,你需要在 urls.py 中使用正則表達式來定義 URL 參數。
# Flask
@app.route('/user/<username>')
def show_user_profile(username):
# show the user profile for that user
return 'User %s' % username
# Django
from django.urls import path
def show_user_profile(request, username):
# show the user profile for that user
return HttpResponse('User %s' % username)
urlpatterns = [
path('user/<str:username>/', show_user_profile),
]
9.2 Django vs FastAPI
FastAPI 是一個新興的 Python web 框架,它的特色是快速、簡單和高性能,而且內建對非同步編程的支持。
-
類型檢查: FastAPI 支持 Python 的類型檢查,你可以在參數中直接定義類型,FastAPI 會自動進行數據驗證。而在 Django 中,你需要自己驗證數據並處理錯誤。
-
非同步編程: 雖然 Django 3.1 開始支持非同步視圖和中間件,但是 FastAPI 在非同步編程方面的支持更為完善。你可以在 FastAPI 中使用
async
和await
關鍵字來定義非同步的路徑操作函數,而在 Django 中,你可能需要使用asgiref.sync.sync_to_async
來包裝資料庫操作。 -
自動文檔: FastAPI 可以根據你的代碼自動生成 API 文檔,這可以幫助你更好地測試和調試你的 API。而在 Django 中,你需要使用如 DRF 的第三方庫或手動編寫 API 文檔。
# FastAPI
from fastapi import FastAPI
app = FastAPI()
@app.get("/items/{item_id}")
async def read_item(item_id: int):
return {"item_id": item_id}
總的來說,Django、Flask 和 FastAPI 都是優秀的 Python web 框架,它們各有各的優點。選擇哪一個取決於你的項目需求,以及你更傾向於使用哪種編程範式。
如有幫助,請多關註
個人微信公眾號:【Python全視角】
TeahLead_KrisChang,10+年的互聯網和人工智慧從業經驗,10年+技術和業務團隊管理經驗,同濟軟體工程本科,復旦工程管理碩士,阿裡雲認證雲服務資深架構師,上億營收AI產品業務負責人。