本文深入探討了 Django 中的請求與響應處理,從 Django 請求和響應的基礎知識、生命週期,到 HttpRequest 和 HttpResponse 物件的詳細介紹。同時,討論了 Django 的檢視和請求、響應處理,以及安全性和非同步處理的考慮。最後,對比了 Django 與 Flask、FastAPI 等框架在請求響應處理上的異同。無論您是 Django 新手還是有經驗的開發者,這篇文章都能幫助您更好地理解 Django 的請求和響應處理。
在Web應用程式中,請求和響應模式是非常重要的概念。當用戶在瀏覽器位址列輸入一個URL或者點選某個連結時,會向伺服器傳送一個請求。伺服器處理完這個請求後,會返回一個響應給瀏覽器。這就是典型的HTTP請求-響應模式。
在 Django 中,當一個 HTTP 請求到達 Django 應用時,它首先會被某個URLconf檔案轉化為一個 HttpRequest 物件。這個物件包含了這次HTTP請求的所有相關的資訊。
def view(request):
# request 是一個 HttpRequest 物件
print(request.method) # 輸出請求方法,比如 "GET" 或 "POST"
Django的檢視必須返回一個 HttpResponse 物件。這個物件表示伺服器給使用者端(通常是瀏覽器)的響應。這個 HttpResponse 物件會被轉化為一個 HTTP 響應,然後被傳送到使用者端。
from django.http import HttpResponse
def view(request):
# 建立一個 HttpResponse 物件
response = HttpResponse("Hello, World!")
return response # 這個響應將會被傳送給使用者端
HTTP 方法是使用者端可以對伺服器發出的一種 "指令"。最常見的方法包括 GET 和 POST。
在 Django 中,你可以通過 HttpRequest 物件的 method
屬性來存取這個請求的方法:
def view(request):
print(request.method) # 輸出請求方法,比如 "GET" 或 "POST"
一旦Django應用收到了一個HTTP請求,它會經歷一系列的階段,這些階段共同構成了請求的生命週期。以下是這個過程的詳述:
當一個請求到達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!"]
接下來,請求會被送到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),
]
一旦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}")
檢視函數處理完請求後,會建立一個HttpResponse物件並返回。這個響應物件會經過中介軟體的一系列處理,最終會被轉換為一個HTTP響應,然後傳送給使用者端。
# 檢視函數返回一個響應
def view(request):
response = HttpResponse("Hello, World!")
return response # 這個響應將會被傳送給使用者端
在 Django 中,所有的 HTTP 請求都被封裝在 HttpRequest 物件中。下面我們將詳細介紹 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
除了屬性,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
在 Django 中,檢視是一個 Python 函數,用於接收一個 Web 請求並返回一個 Web 響應。這個響應可以是 Web 頁面的 HTML 內容,重定向,404 錯誤,XML 檔案,影象,或者任何其他型別的內容。簡單來說,Django 檢視的任務就是接受一個 Web 請求並返回一個 Web 響應。
在 Django 中,建立一個檢視只需要定義一個 Python 函數,這個函數需要接受一個 HttpRequest
物件作為第一個引數,然後返回一個 HttpResponse
物件。如下所示:
from django.http import HttpResponse
def hello(request):
return HttpResponse("Hello, World!")
在這個例子中,hello
函數就是一個檢視,它接收一個 HttpRequest
物件,然後返回一個包含 "Hello, World!" 的 HttpResponse
物件。
檢視函數的第一個引數總是 HttpRequest
物件,而從 URL 中捕獲的引數將作為額外的引數傳遞給檢視函數。例如:
from django.http import HttpResponse
def hello(request, name):
return HttpResponse(f"Hello, {name}!")
在這個例子中,hello
檢視接受兩個引數:一個 HttpRequest
物件和一個 name
字串。你可以在 URLConf 中定義如何從 URL 中提取這個 name
引數。
檢視必須返回一個 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
HttpResponse 物件是 Django 檢視中返回的結果物件,它是由 Django 檢視返回並通過 Django 框架傳送給使用者端的。
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
除了屬性,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
除了普通的 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 錯誤
在 Django 中,檢視是 Web 請求的主要處理者,同時也負責構建和返回響應。檢視接收 HttpRequest 物件作為引數,生成 HttpResponse 物件作為返回值。我們已經詳細討論了 HttpRequest 和 HttpResponse,現在我們來看看如何在檢視中處理它們。
處理請求主要是提取 HttpRequest 物件的資料,然後根據這些資料執行相應的邏輯。
def view(request):
# 獲取 GET 請求的引數
name = request.GET.get('name', 'Guest')
# 根據請求引數執行邏輯
message = f"Hello, {name}!"
return HttpResponse(message)
在這個例子中,我們從 GET 請求中獲取 'name' 引數,然後用它來生成一條歡迎訊息。
構建響應主要是建立 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 頭。
在 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})
在處理 Web 請求和生成響應時,安全性是一個非常重要的考慮因素。幸運的是,Django 提供了一些內建的工具和技術來幫助我們增加應用程式的安全性。
跨站請求偽造(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 保護。但是在某些情況下,你可能需要禁用它,比如上面的例子。
當你在處理請求時接收到敏感資訊,如密碼,你應該使用 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...
Django 提供了一些設定,你可以使用它們來增加 HTTP 響應頭的安全性,如 SECURE_CONTENT_TYPE_NOSNIFF
和 SECURE_BROWSER_XSS_FILTER
。你可以在你的 Django 設定中設定它們。
# settings.py
SECURE_CONTENT_TYPE_NOSNIFF = True
SECURE_BROWSER_XSS_FILTER = True
永遠不要信任使用者輸入的資料。你應該始終對使用者輸入的資料進行清洗和驗證。
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...
Django 3.1 引入了非同步檢視和中介軟體支援,這意味著你可以使用 Python 的 async
和 await
關鍵字來處理非同步任務。這對於處理 I/O 繫結任務或其他可以從並行執行中受益的任務非常有用。
建立非同步檢視的方式與建立同步檢視非常相似,但是你需要將檢視函數定義為 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
完成時,它可以釋放伺服器資源來處理其他請求。
你也可以建立非同步中介軟體,它可以處理進入檢視之前或離開檢視之後的請求和響應。
class SimpleMiddleware:
async def __call__(self, request, get_response):
response = await get_response(request)
return response
在這個例子中,SimpleMiddleware
是一個非同步中介軟體,它在處理請求之前和之後沒有做任何事情,只是簡單地將請求傳遞給下一個中介軟體或檢視。
在 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)在請求和響應處理上的異同。
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),
]
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產品業務負責人。