Django: ListView & paginator

Django Django-CBV

GitHub 範例
這篇是Django CBV, FBV 系列的延續,如果還沒看過可以先看之前的文章 ٩(。・ω・。)

FBV

上一篇文章寫到部落格文章的詳細頁面,如果要顯示文章列表,我們可以這樣寫:

1
2
3
4
5
6
7
8
def post_list(request):
posts = Post.objects.all()
paginator = Paginator(posts, 10)
page_number = request.GET.get('page')
page_obj = paginator.get_page(page_number)
return TemplateResponse(request, 'blog/post_list.html', {
'page_obj': page_obj,
})

通常列表會分頁顯示,所以這裡我們使用了 Django 的Paginator  類。其中Paginator.get_page方法會傳回一個Page物件,其中包含所有與頁數相關的詳細信息,像是:

1
2
3
4
•	page_obj.has_previous:是否有上一頁。
• page_obj.has_next:是否有下一頁。
• page_obj.paginator.num_pages:總頁數(從 page_obj 中可以訪問 paginator 的屬性)。
• page_obj.number:當前頁數。

詳細內容可以參考官方文檔,如果有其他需求,例如篩選和排序,則可以透過修改products的查詢方法而改變。

進一步,可以將重複的內容提取到  paged_object_list_context,使分頁的程式重複使用:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
def post_list(request):
posts = Post.objects.all()
context = {
'posts':posts
} | paged_object_list_context(request, posts, paginate_by=10)
return TemplateResponse(request, 'blog/post_list.html', context)

def paged_object_list_context(request, object_list, paginate_by):
paginator = Paginator(object_list, paginate_by)
page_number = request.GET.get('page', 1)
page_obj = paginator.get_page(page_number)
return {
'page_obj': page_obj,
}

這樣就算完成了,每一個步驟也很清楚 d(`・∀・)b

CBV

如果使用 CBV 的 ListView 要怎麼寫呢?根據Django 官方文檔,寫這樣即可:

1
2
3
class PostListView(ListView):
model = Post
paginate_by = 10

短短的這幾行就取代我們上面寫的一大堆,好像恍如看到 Ruby on Rails 的黑魔法一樣,或許這就是慣例優於設定(Convention over Configuration)的魅力,雖然第一次用的人應該會嚇死(´ ー`)。

簡短真的是件好事嗎?

雖然使用 CBV 的 ListView 確實讓程式碼變得異常簡短,但我們不能單純依賴表面的簡潔來判斷它的優劣。這種簡短的程式可能在初期覺得方便,但當專案邏輯變得複雜時,過於依賴 CBV 反而會讓專案變得更麻煩。

簡短 VS 可擴展性

CBV 強調重用和簡化常見的視圖邏輯,像這樣的 ListView 可以快速幫助我們實現文章列表分頁。但隨著專案需求的增加,很可能需要加入自定義邏輯,例如:

• 根據使用者的權限過濾資料。

• 計算特定的統計數據或傳遞更多上下文。

• 甚至需要處理複雜的表單提交和驗證。

這時,CBV 的結構可能會讓人感覺「被框架鎖住了」,需要深入了解 CBV 的內部運作,並編寫大量的 Mixin 或覆寫方法來達到自定義邏輯。這時候,可能會發現原本簡單的 CBV 開始變得難以管理,甚至比起 FBV 更加繁瑣。

CBV 隱藏的細節

CBV 的一大挑戰在於它隱藏了太多的細節。這雖然讓程式碼看起來乾淨,但也讓開發者難以追蹤和理解其背後的邏輯。例如,當需要修改預設行為時,往往需要覆寫多個內部方法,或是結合 Mixin 來達成目的,這無形中增加了學習成本和程式碼複雜度。

一旦邏輯變得複雜,很快會發現,對這種內部機制的過度依賴反而會增加維護難度。這時候,不得不在 FBV 和 CBV 之間做一個權衡:是選擇簡單清晰但冗長的程式,還是依賴框架的「黑箱」來讓程式碼看起來簡潔?

要選擇 FBV 還是 CBV,最重要的是…

當視圖邏輯簡單且相對固定時,CBV 確實比較方便,讓開發者專注於商業邏輯,減少重複程式碼。然而,一旦商業邏輯開始變得複雜,FBV 提供了更多的靈活性和可控性。隨著專案的成長,適當的結構和清晰的邏輯才是程式碼真正的價值所在


本篇文章是我由以下參考資料整理而成,如果您有興趣了解更多,請參考:

參考資料:

Django Views — The Right Way

Django 官方文檔

Comments