在上一篇文章中,我們探討了Django的類別基礎視圖(CBV)為何重要,以及與函數基礎視圖(FBV)相比的優點。本篇文章將深入了解所有CBV的根本,即 Django的基本View類別。
“要正確理解CBV,首先要了解django.views.View是如何運作以及其結構。”
1. Django View類別是什麼?
Django的所有類別基礎視圖都繼承自django.views.View
類別,使用的形式如下:
from django.views import View
class MyView(View):
def get(self, request, *args, **kwargs):
# 處理GET請求的邏輯
...
def post(self, request, *args, **kwargs):
# 處理POST請求的邏輯
...
View類別的特點
-
HTTP方法的分離
當請求進來時,Django會內部透過dispatch()
方法自動調用對應請求方法的函數,如get()
,post()
,put()
,delete()
等。- 因此不必像FBV那樣使用“if request.method == 'GET': … else: …”的條件語句,使代碼結構更為清晰。
-
繼承與擴展性
可以繼承View類別創建多個子視圖,將通用邏輯放在父類別中,將個別邏輯放在子類別中,極大化代碼重用。
2. View類別的基本結構和原理
最簡單的示例
# views.py
from django.http import HttpResponse
from django.views import View
class HelloCBV(View):
def get(self, request, *args, **kwargs):
return HttpResponse("Hello, CBV!")
-
get()
方法:當瀏覽器發出GET請求(在地址欄輸入URL、點擊鏈接等)時執行。 -
HttpResponse("Hello, CBV!")
:直接創建並返回文本形式的響應。
urls.py連接
# urls.py
from django.urls import path
from .views import HelloCBV
urlpatterns = [
path('hello/', HelloCBV.as_view(), name='hello_cbv'),
]
-
.as_view()
方法將CBV轉換成Django能夠理解的形式。 -
與URL模式連接時,當以
http://example.com/hello/
發出GET請求時,將調用HelloCBV
的get()
方法。
3. View類別的用法和實務示例
如上所示,單純返回“一個字符串”的情況並不常見。在實際項目中,通常會進行JSON響應、模板渲染或執行數據庫查詢等操作。在此我們將以JSON響應和模板渲染為例進行探討。
3.1 JSON響應處理示例
# views.py
from django.http import JsonResponse
from django.views import View
class UserDataView(View):
def get(self, request, *args, **kwargs):
# 假設通過GET參數接收user_id
user_id = request.GET.get('user_id', None)
if not user_id:
return JsonResponse({'error': 'No user_id provided'}, status=400)
# 實際將執行DB查詢等操作
user_data = {
'id': user_id,
'name': f'User_{user_id}',
'role': 'admin'
}
return JsonResponse(user_data, status=200)
def post(self, request, *args, **kwargs):
# 可以解析POST請求主體中的JSON或form數據。
# 可以使用request.POST, request.body, request.FILES等
# 在實際服務中執行JSON解析後的DB保存邏輯
new_user_data = {
'id': 123,
'name': 'NewUser',
'role': 'member'
}
return JsonResponse(new_user_data, status=201)
-
JsonResponse
:Django中方便生成JSON響應的工具。 -
request.GET
,request.POST
:可從Django的HttpRequest對象中提取GET/POST參數。 -
在實務中,數據將與DB模型關聯或透過序列化器以更結構化的方式處理。
3.2 模板渲染示例
# views.py
from django.shortcuts import render
from django.views import View
class GreetingView(View):
def get(self, request, *args, **kwargs):
context = {
'title': 'Welcome to My Site',
'greeting': 'Hello, this is a GreetingView!'
}
return render(request, 'greeting.html', context)
<!-- templates/greeting.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{ title }}</title>
</head>
<body>
<h1>{{ greeting }}</h1>
</body>
</html>
-
render()
函數將查找模板文件(greeting.html
)並渲染成HTML以HttpResponse
形式返回。 -
以此方式,CBV內部也可以輕鬆進行模板渲染。
4. View類別的擴展與重用性
View類別有用的主要原因之一就是“代碼重用”。隨著項目規模的擴大,將多個視圖共同需要的邏輯(例如:日誌、授權檢查、公共數據處理等)放在父類別中,由子類別繼承使用會更加有效率。
4.1 將共通邏輯放在父類別中
# views.py
from django.http import JsonResponse
from django.views import View
class BaseLoggingView(View):
def dispatch(self, request, *args, **kwargs):
# 對所有請求(GET/POST等)執行共通邏輯
print(f"[Log] {request.method} request at {request.path}")
return super().dispatch(request, *args, **kwargs)
class ChildLoggingView(BaseLoggingView):
def get(self, request, *args, **kwargs):
data = {'message': 'GET response from child'}
return JsonResponse(data)
def post(self, request, *args, **kwargs):
data = {'message': 'POST response from child'}
return JsonResponse(data)
-
dispatch()
方法:是用來控制Django執行視圖邏輯前後的核心方法。 -
在這個示例中,對所有請求打印日誌後,通過
super().dispatch()
來調用實際的get()
,post()
等方法。
4.2 通過Mixin添加功能
Django中經常使用Mixin技術來“混合特定功能”。例如,將LoginRequiredMixin(檢查登入狀態)、PermissionRequiredMixin(檢查權限)等混合到CBV中。
from django.contrib.auth.mixins import LoginRequiredMixin
from django.views import View
from django.http import JsonResponse
class SecuredView(LoginRequiredMixin, View):
def get(self, request, *args, **kwargs):
return JsonResponse({'message': 'You are authenticated.'})
- Mixin的使用計劃在後續說明通用視圖或權限管理時進一步詳述,因此這裡只需了解“可以這樣組合功能”即可。
5. 與FBV的簡單比較
分類 | FBV (函數基礎視圖) | CBV (類別基礎視圖) |
---|---|---|
編寫方式 | 函數形式編寫 | 類別&方法形式編寫 |
HTTP方法處理 | if request.method == 'GET': ... else: ... |
get() , post() 等方法分離 |
代碼重複可能性 | 當邏輯變複雜時容易出現重複代碼 | 可透過繼承和Mixin重用共通邏輯 |
擴展性 | 共通邏輯通常混在函數內 | 透過類繼承結構應對複雜需求更為合適 |
可讀性 | 在簡單原型中有利 | 隨著規模增大,更適合保持明確結構 |
-
FBV適合快速編寫小型或簡單功能,而CBV在擴展性和維護性上更具優勢。
-
特別是在團隊項目或中大型項目中,使用CBV將更有效率。
6. 更深入探討:dispatch()
與URL參數
6.1 為何直接重寫dispatch()
-
共通前後處理:可在每次請求時檢查DB連接、執行權限檢查或記錄日誌等。
-
方法映射:內部使用
request.method.lower()
查找並調用get()
,post()
,put()
等。如果想額外自定義處理如PATCH
等方法,可以重寫dispatch()
來處理。
class CustomDispatchView(View):
def dispatch(self, request, *args, **kwargs):
print("Custom pre-processing logic here.")
response = super().dispatch(request, *args, **kwargs)
print("Custom post-processing logic here.")
return response
6.2 接收URL參數
如果在urls.py
中如<int:user_id>/
指定了路徑參數,則可在CBV的get()
, post()
方法中通過kwargs
接收值。
# urls.py
urlpatterns = [
path('user/<int:user_id>/', UserDetailView.as_view(), name='user_detail'),
]
# views.py
class UserDetailView(View):
def get(self, request, *args, **kwargs):
user_id = kwargs.get('user_id')
# 以user_id查詢DB
return HttpResponse(f"User ID: {user_id}")
- 與FBV相同,可以從
kwargs
中取出URL參數使用。
7. 更豐富的實際案例:簡單留言板示例
對於想要更實際運用View類別的朋友,這裡提供一個簡單的留言板列表和詳細頁面的示例代碼。(在下一篇文章中將介紹泛型視圖,使CRUD實現更為簡便,但這裡主要展示僅使用基本View類別的可行性。)
# models.py - 示例模型
from django.db import models
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.title
# views.py
from django.views import View
from django.shortcuts import render, get_object_or_404
from .models import Post
# 查看帖子列表
class PostListView(View):
def get(self, request, *args, **kwargs):
posts = Post.objects.order_by('-created_at')
context = {'posts': posts}
return render(request, 'post_list.html', context)
# 查看帖子詳細
class PostDetailView(View):
def get(self, request, *args, **kwargs):
post_id = kwargs.get('pk')
post = get_object_or_404(Post, pk=post_id)
context = {'post': post}
return render(request, 'post_detail.html', context)
<!-- post_list.html -->
<!DOCTYPE html>
<html>
<head>
<title>帖子列表</title>
</head>
<body>
<h1>帖子列表</h1>
<ul>
{% for post in posts %}
<li>
<a href="{% url 'post_detail' post.id %}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
</body>
</html>
<!-- post_detail.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{ post.title }}</title>
</head>
<body>
<h1>{{ post.title }}</h1>
<p>{{ post.content }}</p>
<p>創建日期: {{ post.created_at }}</p>
</body>
</html>
# urls.py
from django.urls import path
from .views import PostListView, PostDetailView
urlpatterns = [
path('posts/', PostListView.as_view(), name='post_list'),
path('posts/<int:pk>/', PostDetailView.as_view(), name='post_detail'),
]
-
PostListView
:在接收到GET請求時查詢所有帖子並傳遞給模板(post_list.html
)。 -
PostDetailView
:根據URL參數pk
查找特定帖子並傳遞給模板(post_detail.html
)。 -
這樣,我們可以僅用基本View類別輕鬆構建列表和詳細頁面。
不過,若要構成完整的CRUD,則需要Create/Update/Delete邏輯。Django提供的泛型視圖(Generic Views)豐富了這部分內容,詳細內容將在下一篇文章中介紹!
8. 結論和下一篇文章預告
至此,您對Django的基本View類別的運作方式及實際應用有了初步了解。總結要點如下:
-
繼承django.views.View,重寫
get()
/post()
/dispatch()
等方法來響應HTTP請求。 -
將共通邏輯放在父類別中,只重寫子視圖中的必要部分,這樣可以極大化代碼重用。
-
能夠在模板渲染、JSON響應、DB查詢等多種場景中輕鬆編寫視圖邏輯。
-
如簡單的消息板示例,僅用基本View類別也能構建完整的項目。
不過,若想更方便地處理CRUD操作,了解Django提供的泛型視圖(Generic Views)會更為便利。
在下一篇文章中,我們將專注於簡化表單處理的FormView
類別。透過學習,我們將掌握“接收用戶輸入、保存、在驗證失敗時顯示錯誤信息”等過程的自動化方法。
CBV系列仍將持續!
- 第3篇:“透過FormView簡化表單處理”
- 第4篇:“ListView和DetailView的使用方法”
- 第5篇:“透過CreateView, UpdateView, DeleteView實現CRUD”
- …(之後還會持續更新)
查看過往文章
額外參考資料
-
Django社群 – 在Django社群中可以找到各種案例。
希望這篇文章能解答你對基本View類別的結構與應用方法的疑問。在下一篇文章中,我們將學習如何通過FormView輕鬆處理“表單填寫→驗證→錯誤處理→成功重定向”等過程,期待您的關注!
“Django的View類別不僅僅是根據HTTP方法分離代碼,
它還能顯著改善大型項目的擴展性與維護性,成為強大的工具。”
期待能繼續深入探討CBV,帶來更高效的Django開發!
目前沒有評論。