“透過 Django ListView 和 DetailView,輕鬆實現資料查詢,
最大化開發生產力!”
如果在前面的文章中了解了 Django 的基本 View 類和 FormView,那麼現在是時候更具體地探索 通用視圖(Generic Views) 了。
ListView 和 DetailView 特別針對 ‘資料輸出’ 而設計,能夠通過簡單的設置快速實現列表頁面和詳細頁面。
1. 什麼是 ListView 和 DetailView?
-
ListView
-
提供將模型(Model)中的多個對象以列表形式展示的功能。
-
可以輕鬆應用分頁(Pagination)、排序和搜尋功能,幾乎可以在所有的“列表頁面”中使用。
-
-
DetailView
-
顯示特定對象(如:文章、商品、用戶等)的詳細信息。
-
通過 URL 參數或 pk(主鍵)值來查找該對象,並能在模板中輕鬆渲染。
-
這兩個類別是 Django 提供的 通用視圖 的一部分,能夠快速實現 CRUD 中的“讀取”功能,是強大的工具。
2. ListView 的基本結構和使用方法
2.1 基本例子
# views.py
from django.views.generic import ListView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'post_list.html'
context_object_name = 'posts' # 在模板中使用的上下文變數名(默認值:object_list)
# paginate_by = 10 # 每頁顯示的條目數(可選)
# 當需要額外調整查詢集時使用 get_queryset
def get_queryset(self):
# 例:如果只想顯示最新的文章?
return Post.objects.order_by('-created_at')
-
model
: 指定要展示哪個模型的數據。 -
template_name
: 模板文件路徑(默認值:<app_name>/<model_name>_list.html
)。 -
context_object_name
: 在模板中使用的上下文對象名稱(默認值:object_list
)。 -
paginate_by
: 可以指定每頁顯示的對象數量(分頁處理)。
2.2 在 urls.py 中連接 ListView
# urls.py
from django.urls import path
from .views import PostListView
urlpatterns = [
path('posts/', PostListView.as_view(), name='post_list'),
]
2.3 基本模板範例
<!-- 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.pk %}">{{ post.title }}</a>
</li>
{% endfor %}
</ul>
<!-- 實現分頁時 -->
{% if is_paginated %}
<div>
{% if page_obj.has_previous %}
<a href="?page={{ page_obj.previous_page_number }}">上一頁</a>
{% endif %}
<span>頁面 {{ page_obj.number }} / {{ page_obj.paginator.num_pages }}</span>
{% if page_obj.has_next %}
<a href="?page={{ page_obj.next_page_number }}">下一頁</a>
{% endif %}
</div>
{% endif %}
</body>
</html>
核心關鍵詞: “列表頁面自動化”,“分頁(Pagination)”,“高效數據排列”
3. DetailView 的基本結構和使用方法
3.1 基本例子
# views.py
from django.views.generic import DetailView
from .models import Post
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
context_object_name = 'post' # 在模板中使用的上下文變數名(默認值:object)
# (可選)如果希望在 URL 中使用非 pk 的其他識別符,可以重載 get_slug_field等。
-
model
: 查詢特定模型的單一對象。 -
template_name
: 模板文件路徑(默認值:<app_name>/<model_name>_detail.html
)。 -
context_object_name
: 在模板中使用的上下文對象名稱(默認值:object
)。 -
如果 URL 模式中包含
<int:pk>/
或<slug:slug>/
等模式,Django 會通過該值自動查找對象。
3.2 在 urls.py 中連接 DetailView
# urls.py
from django.urls import path
from .views import PostDetailView
urlpatterns = [
path('posts/<int:pk>/', PostDetailView.as_view(), name='post_detail'),
]
3.3 基本模板範例
<!-- post_detail.html -->
<!DOCTYPE html>
<html>
<head>
<title>{{ post.title }}</title>
</head>
<body>
<h1>{{ post.title }}</h1>
<p>撰寫日期: {{ post.created_at }}</p>
<div>
{{ post.content }}
</div>
<a href="{% url 'post_list' %}">回到列表</a>
</body>
</html>
4. 擴展 ListView & DetailView
4.1 get_queryset, get_context_data
get_queryset()
: 可以客製化查詢集以符合所需條件。
例如:僅顯示某特定用戶的文章列表、關鍵字過濾、根據特定欄位排序等。
def get_queryset(self):
queryset = super().get_queryset()
return queryset.filter(is_active=True)
get_context_data()
: 可以將額外的數據傳遞給模板。
def get_context_data(self, **kwargs):
context = super().get_context_data(**kwargs)
context['extra_info'] = '附加信息'
return context
4.2 slug、自定義查找
DetailView 可以使用 slug
(短文本標識符)替代 pk
,並可通過指定 slug_field
、slug_url_kwarg
進行自定義配置。
class PostDetailView(DetailView):
model = Post
slug_field = 'slug' # 模型中的 slug 欄位名
slug_url_kwarg = 'slug' # URL 模式中接收的參數名
4.3 與 Mixin 的結合
-
與 LoginRequiredMixin 或 PermissionRequiredMixin 等一起使用,可以輕鬆控制對列表和詳細頁面的訪問權限。
-
像 SearchMixin 這樣的自定義 Mixin,可以創建邏輯來處理搜尋參數(query),並在多個 ListView 中重用。
5. 簡單的實戰例子:實現討論區功能
以之前文章中提到的模型 Post
為基礎,來一起構建 列表 + 詳細 的功能。
# models.py
class Post(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
created_at = models.DateTimeField(auto_now_add=True)
slug = models.SlugField(unique=True) # 使用 slug 範例
def __str__(self):
return self.title
# views.py
from django.views.generic import ListView, DetailView
from .models import Post
class PostListView(ListView):
model = Post
template_name = 'post_list.html'
context_object_name = 'posts'
paginate_by = 5 # 每頁 5 個項目
def get_queryset(self):
# 假設顯示的是啟用狀態的文章,而不是 slug
return Post.objects.filter(is_active=True).order_by('-created_at')
class PostDetailView(DetailView):
model = Post
template_name = 'post_detail.html'
context_object_name = 'post'
slug_field = 'slug'
slug_url_kwarg = 'slug'
# urls.py
urlpatterns = [
path('posts/', PostListView.as_view(), name='post_list'),
path('posts/<slug:slug>/', PostDetailView.as_view(), name='post_detail'),
]
-
列表頁面: 可以通過更改頁碼,如
/posts/?page=2
來查看列表。 -
詳細頁面: 使用
posts/<slug>/
路徑來搜尋特定文章,並在模板中顯示。
6. 與 FBV 的比較:列表/詳細頁面到底有多容易實現?
類別 | FBV (函式基礎視圖) | ListView/DetailView (CBV) |
---|---|---|
代碼結構 | 需分別編寫列表/詳細函數,分頁、排序等需要自行實現 | 僅通過設置屬性,即可輕鬆客製化列表、分頁、排序、搜尋等功能 |
可讀性/維護性 | 條件語句、迴圈在多處交錯,隨著項目增大變得更複雜 | 列表/詳細邏輯分離,擴展(方法重寫)明確,維護方便 |
開發生產力(關鍵詞) | “代碼重複增加,耗時” | “縮短開發時間(Time-saving),提升生產力(Productivity boost)” |
模板數據傳遞 | 需要手動構建上下文字典以傳遞給 render | 基本自動傳遞上下文(object_list , object )。額外數據也可以在 get_context_data 中輕鬆處理 |
分頁、搜尋等高級功能 | 需要編寫單獨邏輯 | 可以輕鬆啟用的內建功能和屬性 |
7. 結論及下篇文章預告
Django ListView 和 DetailView 透過簡化“數據列表”和“詳細頁面”的實現,給予了開發者極大的便利。
透過自動化常用功能如分頁、上下文數據附加、根據 URL 參數進行對象查詢等,可以在 代碼重用性和開發生產力 上獲得巨大優勢。
CBV(類別基礎視圖)系列將會繼續!
在下篇文章中,我們將探索如何使用CreateView
、UpdateView
、DeleteView
方便地構建 CRUD 邏輯。
再次查看前一篇文章
“利用 Django 的 ListView 和 DetailView,
迅速查詢數據、輕鬆開發,並獲得更高的生產力(Productivity)!”
目前沒有評論。