Django CRUD 的 R(Read):資料讀取與顯示功能指南
更新日期: 2024 年 12 月 2 日
本文為 Django 進階教學,第 7 篇:
- 理解 Django 中的相對路徑與絕對路徑
- Django URL 路徑設置|name 參數與命名空間(Namespace)
- Django 串接資料庫與模型建構:完整入門指南
- Django 模型遷移與資料庫同步完整指南
- 使用 Django ORM 將資料寫入資料庫:新手入門指南
- Django 實現 CRUD 的 C(Create):新增資料功能完整指南
- Django CRUD 的 R(Read):資料讀取與顯示功能指南 👈 所在位置
- Django CRUD 的 U(Update):資料更新功能完整指南
- Django CRUD 的 D(Delete):資料刪除功能完整指南
建議閱讀本文前,先閱讀完 Django 新手教學 系列文
Django 的 CRUD:R(Read) 功能主要用於從資料庫讀取資料並展示給用戶。
本篇將帶你通過實例完成資料列表顯示和單筆資料的查看,並詳細解釋路由設計與動態 URL 的生成過程。
專案目錄結構
完成資料讀取功能後,專案目錄應如下:
mysite/
├── manage.py
├── mysite/
│ ├── settings.py # 專案配置文件
│ ├── urls.py # 主路由配置
│
├── resumes/
│ ├── __init__.py
│ ├── admin.py
│ ├── apps.py
│ ├── models.py # 定義 Resume 模型
│ ├── views.py # 定義新增資料與處理邏輯
│ ├── urls.py # 配置應用的路由
│ ├── templates/
│ ├── resumes/
│ ├── home.html # 顯示 Resume 列表
│ ├── show.html # 顯示單筆資料
│ ├── new.html # 新增資料表單
├── db.sqlite3 # SQLite 資料庫
配置路由與視圖
在 resumes/urls.py
中定義路由:
from django.urls import path
from . import views
app_name = 'resumes' # 定義 namespace,供模板生成動態路徑使用
urlpatterns = [
path("", views.home, name='list'), # 主頁,顯示所有資料
path("<int:id>/", views.show, name="show"), # 顯示單筆資料
path("new/", views.new, name='nn') # 新增資料頁面
]
在 Django 的 urls.py
中,<int:id>
是一種 路徑轉換器 (path converter),其作用是:
<>
是表示變數的佔位符:- 它允許在 URL 模式中定義一個動態部分。
- 動態部分的值會被提取並傳遞給對應的視圖函數作為參數。
int
是轉換器的類型:- 指定這個動態部分必須是一個整數。
- 如果 URL 中的值不是整數(例如字母或特殊符號),Django 會自動返回一個 404 錯誤。
id
是變數名稱:- 當匹配這個 URL 模式時,Django 會提取動態部分的值並賦值給
id
。 - 然後將該值作為參數傳遞給對應的視圖函數。
- 當匹配這個 URL 模式時,Django 會提取動態部分的值並賦值給
具體說明
path("<int:id>/", views.show, name="show")
- 如果訪問的 URL 是
/123/
,Django 會:- 提取
123
,並確認它是整數。 - 將
123
傳遞給views.show
作為id
的值。
- 提取
對應的視圖函數可能像這樣:
from django.http import HttpResponse
def show(request, id):
return HttpResponse(f"您請求的資料 ID 是: {id}")
當訪問 /123/
時,瀏覽器將顯示:
您請求的資料 ID 是: 123
可用的路徑轉換器類型
Django 提供了幾種內建的路徑轉換器,您可以根據需求選擇:
str
:匹配任何非空字符串(預設類型)。int
:匹配正負整數。slug
:匹配字母、數字、連字號和下劃線。uuid
:匹配一個 UUID。path
:匹配路徑,包括斜槓。
範例:
path("<str:name>/", views.greet, name="greet"),
path("<slug:slug>/", views.article, name="article"),
path("<uuid:identifier>/", views.item, name="item"),
這些路徑轉換器讓 Django 的 URL 配置變得更靈活,也能使代碼更具可讀性和結構化。
配置視圖
主頁視圖:顯示資料列表
在 resumes/views.py
中定義首頁的邏輯,用於顯示所有資料:
from django.shortcuts import render
from .models import Resume
def home(request):
# 讀取所有 Resume 資料
resumes = Resume.objects.all()
return render(
request,
"resumes/home.html",
{"resumes": resumes}
)
逐行解析:
resumes = Resume.objects.all()
:- 查詢
Resume
模型中的所有資料,返回一個 QuerySet(類似列表的物件)。 - QuerySet 包含每一筆資料的實例,這些實例對應資料庫中的記錄。
- 查詢
return render()
:"resumes/home.html"
:指定渲染的模板。{"resumes": resumes}
:將 QuerySet 以字典的形式傳遞給模板,鍵為resumes
,值為查詢結果。- 模板可以通過
{% for resume in resumes %}
迴圈讀取資料。
補充說明:MyModel.objects.all()
MyModel.objects.all()
是 Django 框架中特有的語法。
在 Django 中,每個模型類別(例如 MyModel
)都自動擁有一個名為 objects
的管理器(Manager),該管理器提供了多種方法來查詢資料庫。
其中,all()
方法用於獲取該模型在資料庫中的所有記錄,並返回一個 QuerySet 物件。
這種設計,使得開發者能夠以簡潔且直觀的方式進行資料庫操作,而無需直接撰寫 SQL 查詢。
例如,MyModel.objects.all()
會生成一個 SELECT 查詢,檢索 MyModel
對應資料表中的所有記錄。
相當於:
select * from table
需要注意的是,這種語法是 Django 的特性,在其他 Python 框架或純 Python 環境中並不存在。
因此,若在非 Django 環境中使用 MyModel.objects.all()
,會導致錯誤。
單筆資料視圖:顯示指定 ID 的資料
在 resumes/views.py
中定義單筆資料的查看邏輯:
from django.shortcuts import render, get_object_or_404
from .models import Resume
def show(request, id):
# 若資料不存在,返回 404 錯誤
resume = get_object_or_404(Resume, id=id)
return render(
request,
"resumes/show.html",
{"resume": resume}
)
逐行解析:
resume = get_object_or_404(Resume, id=id)
:- 嘗試從
Resume
模型中查詢主鍵為id
的資料。 - 如果資料存在,返回對應的物件;如果不存在,自動返回 404 錯誤頁面。
- 嘗試從
return render()
:"resumes/show.html"
:指定渲染的模板。{"resume": resume}
:將查詢結果以字典的形式傳遞給模板。
設置資料列表模板:home.html
在首頁顯示資料列表,並為每筆資料添加超連結:
{% extends "shared/layout.html" %}
{% block content %}
<h1>Resume 首頁</h1>
<a href="{% url 'resumes:nn' %}">新增 Resume</a>
<ul>
{% for resume in resumes %}
<li>
<a href="{% url 'resumes:show' resume.id %}">{{ resume.title }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}
解析 {% url ‘resumes:show’ resume.id %}
在 Django 模板中,{% url %}
是用來生成動態路徑的標籤。
以下是該標籤 {% url 'resumes:show' resume.id %}
生成超連結的具體解析,與對應代碼的詳細說明:
'resumes:show'
表示路由的名稱空間和名稱
路由的名稱空間:
resumes
,定義在應用的 urls.py
中,通過以下代碼設定:
# resumes/urls.py
app_name = 'resumes'
這使得該應用的路由擁有命名空間,便於與其他應用的路由區分。
路由的名稱:
show
,對應以下路由定義:
# resumes/urls.py
urlpatterns = [
path("<int:id>/", views.show, name="show"), # 單筆資料的路由
]
該路由中,<int:id>
是路徑參數,用於捕獲 URL 中的整數值。
當 name="show"
時,該路由可以被引用為 resumes:show
。
模板中的 resume.id
:主鍵與資料來源解析
在 Django 的模板中,resume.id
是單筆資料的主鍵,對應於資料庫中 Resume
模型的 id
欄位。
以下將詳細說明 resume
和 resumes
的來源及其在模板中的使用。
resumes
的來源:從視圖到模板的傳遞
- 定義視圖函數
在views.py
中,我們定義了home
函數,負責處理主頁請求,查詢資料並將結果傳遞到模板。
具體代碼如下:
# resumes/views.py
from django.shortcuts import render
from .models import Resume
def home(request):
resumes = Resume.objects.all() # 取得所有資料
return render(request, "resumes/home.html", {"resumes": resumes})
- 逐行解釋:
Resume.objects.all()
:- 查詢資料庫: 該方法調用 Django ORM,查詢資料庫中
Resume
模型的所有記錄。 - 返回結果: 返回一個 QuerySet,它是一個類似列表的物件,包含多筆資料,每筆資料對應於資料庫中的一條記錄。
- 用途: 這些資料將在模板中被渲染,展示給用戶。
- 查詢資料庫: 該方法調用 Django ORM,查詢資料庫中
{"resumes": resumes}
:- 上下文傳遞: 使用 Python 字典將查詢結果
resumes
作為上下文數據傳遞給模板。 - 模板變數: 在模板中,
resumes
變數即代表 QuerySet,包含所有 Resume 資料。
- 上下文傳遞: 使用 Python 字典將查詢結果
resume
的來源:模板中的迴圈變數
在模板中,resume
是通過 Django 模板語法 {% for resume in resumes %}
定義的迴圈變數。
以下為模板範例代碼:
{% extends "shared/layout.html" %}
{% block content %}
<h1>Resume 列表</h1>
<ul>
{% for resume in resumes %}
<li>
<a href="{% url 'resumes:show' resume.id %}">{{ resume.title }}</a>
</li>
{% endfor %}
</ul>
{% endblock %}
- 逐行解析:
{% for resume in resumes %}
:- 迴圈變數: 將
resumes
(從視圖傳遞的 QuerySet)中的每一筆資料逐一取出,賦值給resume
。- 每次迴圈,
resume
代表 QuerySet 中的一個物件,對應於資料庫中的一條記錄。
- 每次迴圈,
- 迴圈變數: 將
resume.id
:- 主鍵:
id
是resume
的屬性,對應於資料庫中該記錄的主鍵欄位。
- 主鍵:
{% url 'resumes:show' resume.id %}
:- 動態生成 URL,用於指向單筆資料的詳細頁面(如
/resumes/1/
)。
- 動態生成 URL,用於指向單筆資料的詳細頁面(如
resume.id
的角色:資料庫記錄的主鍵
- 定義:
resume.id
是Resume
模型的主鍵(Primary Key),由 Django 自動生成。- 主鍵唯一標識每一筆資料,方便在應用中進行資料操作(如讀取、更新或刪除)。
- 資料結構對應:
假設資料庫中有以下記錄:- 第一次迴圈時,
resume
對應於id=1
的記錄。 - 第二次迴圈時,
resume
對應於id=2
的記錄。
- 第一次迴圈時,
+----+-------------+----------+-----------+
| id | title | skill | content |
+----+-------------+----------+-----------+
| 1 | Developer | Python | Backend |
| 2 | Designer | Photoshop| UI/UX |
+----+-------------+----------+-----------+
- 實際應用: 在模板中,我們可以透過
resume.id
指向詳細頁:
<a href="{% url 'resumes:show' resume.id %}">{{ resume.title }}</a>
- 生成的超連結如下:
<a href="/resumes/1/">Developer</a>
<a href="/resumes/2/">Designer</a>
完整運作流程
- 資料庫查詢:
- 使用
Resume.objects.all()
查詢所有Resume
資料,返回 QuerySet。
- 使用
- 上下文傳遞:
- 將 QuerySet 封裝成字典,作為上下文傳遞到模板中。
- 模板渲染:
- 在模板中,通過
{% for resume in resumes %}
迴圈遍歷 QuerySet。
- 在模板中,通過
- 生成超連結:
- 使用
resume.id
動態生成超連結,指向每筆資料的詳細頁面。
- 使用
補充:{% url %}
的動態生成
當你在 Django 模板中使用動態模板標籤 {% url %}
時,它的主要作用是 動態生成 URL,避免在模板中硬編碼靜態路徑。
這樣做有以下好處:
- 方便管理:如果 URL 改變,只需在
urls.py
中更新即可,模板中會自動更新。 - 減少出錯:避免在多處模板中直接硬編碼 URL,降低出錯風險。
- 支持多應用:利用命名空間(
app_name
)支持跨應用路徑生成。
基本語法
{% url '命名空間:路徑名稱' 參數1 參數2 ... %}
- 命名空間:
- 對應
urls.py
中的app_name
。 - 幫助在多應用中區分 URL,例如:
resumes:show
。
- 對應
- 路徑名稱:
- 對應
urlpatterns
中的name='...'
。 - 用於識別特定的路徑配置。
- 對應
- 參數:
- 如果路徑定義中包含動態部分(例如
<int:id>
),則這裡需要傳入對應的值。
- 如果路徑定義中包含動態部分(例如
Django
的 URL 配置並不是簡單地將 app_name:路徑名稱
和參數拼接在一起,而是依賴於 urls.py
中的 urlpatterns
定義 來動態解析 URL。
{% url %}
的解析過程
當模板中使用 {% url 'resumes:show' resume.id %}
時,Django 會執行以下步驟:
- 找到命名空間:
resumes
是app_name
,表示這段 URL 屬於resumes
應用。
- 匹配路徑名稱:
show
是urlpatterns
中的name='show'
,Django 會定位到以下這段定義:
path('<int:id>/', views.show, name='show')
- 解析路徑參數:
<int:id>
定義了路徑中需要的動態參數id
。resume.id
的值(假設為123
)會被填入<int:id>
的佔位符中。
- 生成 URL:
- 根據
path('<int:id>/', ...)
,生成的路徑是/123/
。
- 根據
單筆資料模板:show.html
在 resumes/templates/resumes/show.html
中設置單筆資料的顯示邏輯:
{% extends "shared/layout.html" %}
{% block content %}
<h1>{{ resume.title }}</h1>
<h3>{{ resume.skill }}</h3>
<article>
<p>{{ resume.content }}</p>
</article>
{% endblock %}
代碼解析
{{ resume.title }}
:顯示該筆資料的title
屬性。{{ resume.skill }}
:顯示該筆資料的skill
屬性。{{ resume.content }}
:顯示該筆資料的content
屬性。
小結
通過以上步驟,我們完成了 Django CRUD 的 R(Read)功能:
- 顯示資料列表:在首頁模板中使用迴圈遍歷資料,並為每筆資料生成動態超連結。
- 顯示單筆資料:根據 URL 中的動態 ID 查詢資料並顯示詳細內容。
- RESTful 設計:通過動態路由設計實現清晰的資源定位,符合 RESTful API 的標準。
這套資料讀取功能為後續的資料操作(更新與刪除)奠定了堅實基礎!