下篇來記錄子目錄的設定、前端環境的建立和 model 資料庫的連結與處理,整體流程上來說,通常會以 urls -> views -> model -> render templates
來進行。
專案子目錄的建立
一個子目錄是一個資料夾,也可視為一個模組,必須包含 urls.py
和 views.py
檔案,urls.py
是用來管理整個模組的頁面路徑結構,而 views.py
則是負責渲染程式到頁面的 Python 函式模組。為了每個子目錄連結都可以在全站中來去自如,需要將資料夾模組化,所以要建立 __init__.py
檔案。
在專案資料夾內新增子目錄
除了自己手動新建資料夾之外,Django 也有指令來創建:
$ django-admin startproapp 資料夾名稱
$ python manage.py startapp 資料夾名稱
: 這款較可確保執行環境的穩定
每一個透過 Django startapp 指令生成的資料夾,都可以當作一個應用程式,功能比較完整,不用再自己刻,但是接下來兩個檔案,就必須自己建立了XD。
urls.py
經過上篇的介紹,就會知道這個檔案是用來管理入口頁的結構和路徑,而且順序很重要。1
2
3
4
5
6
7
8from django.urls import path
from . import views
app_name = '子目錄'
urlpatterns = [
path('', views.home, name='home'),
]views.py
而 views 則是負責渲染路徑的程式。1
2
3
4from django.shortcuts import render
def home(req):
return render(req, '子目錄/index.html')
前端環境的設定與載入
若是想要直接在專案資料夾裡處理 CSS,在上篇有提到可以在專案資料夾下建立 static 資料夾,專門存放靜態檔案,例如 CSS、JS 和 圖片。若不使用套件,就可以很單純的加上 CSS 檔案並連結到樣版 html。
1 | {% load static %} |
詳細的前端工具載入與設定會在 JS 打包篇詳解~
在 Django 與資料庫連結
在 html 製作要與資料庫連動的表單(form),有兩個跟資料庫有關的屬性:action 和 method
1 | <form action="把資料送去哪裡" method="用什麼方法送"></form> |
action 的值是一個網頁路徑,是指這個表單的內容在啟動觸發器時,會把資料送去哪裡處理;method 的值則是選擇用什麼方法送去,目前 html 只有兩種方法:GET 和 POST。
- GET: 網址會把輸入資料顯示在網址上,稱作 QueryString,用在查詢或搜尋比較好
- POST: 反之,網址會把輸入資料隱藏,資料會在 request 物件裡的 body,撈資料也是從這裡,但至少在前台不會顯示,像是新增、更新和刪除等操作用 POST 會較合適。
model.py
生成資料庫
要先在 Django 專案資料夾裡生成資料庫,就可以直接在專案資料夾裡生成操作資料表(table)。用 ORM(Object-Relationship Mapping 物件關聯性對照)寫入資料或讀取在子目錄下的 model.py。
1 | from django.db import models |
建完模組後,記得也要去 settings.py
註冊 APP。
增加完之後用 Django 指令生成資料表和欄位:
1 | $ python manage.py makemigrations |
生成一個 migrations/0001.initial.py 給子目錄,但目前只是生成,還要去 Apply 它,所以
1 | $ python manage.py migrate |
就會產生從 model.py
寫好的模組建成資料庫檔案,而 table 的名稱就會叫做 子目錄_class名稱
。若要更新修改模組檔案,還是要再跑上述兩個指令。另外,還可以指定要回到哪條 migration,但是該條所做的內容也會跟著消失,雖然有版控的感覺,但倒退嚕還是會有一定的風險在,雖然再執行一次 migrate
資料結構會回來,但內容卻會永遠消失。
CRUD
接下來開始資料庫最基本的操作,就是 CRUD,分別是 Create 新增創建、Read 查詢搜尋顯示、Update 更新資料、Delete 刪除資料。以下是在 Django 框架下操作 CRUD 的練習和心得,在 Django 操作 CRUD,必須同時處理三個檔案,分別是 urls.py
、views.py
和 html
,那我們就繼續看下去~😄
Create 新增
urls.py
: 新增路徑1
2
3
4
5
6
7
8
9
10from django.urls import path
from . import views
app_name = '子目錄'
urlpatterns = [
path("", views.home, name="index") # 子目錄首頁
path("new", views.new, name="new") # 要輸入資料的頁面
path("add", views.create, name="add") # 寫入模組
]views.py
: 渲染路徑和程式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18from django.shortcuts import render, redirect # 渲染路徑、轉址兼解讀路徑
from django.views.decorators.http import require_POST # 判斷是不是 POST
from .models import class名稱 # 從同家的 model 取 class
# 要輸入資料的頁面
def new(req):
return render(req, "子目錄/new.html")
# 寫入資料庫
def create(req):
變數_單 = class名稱(
name=req.POST["name"],
description=req.POST["description"]
)
變數_單.save()
return redirect("root")new.html
: 渲染到輸入資料的頁面1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18<h1>新增</h1>
<form action="{% url '子目錄:add' %}" method="post">
<!-- 使用 POST 方法時的安全驗證機制 -->
{% csrf_token %}
<div>
<label for="name">姓名</label>
<input type="text" id="name" name="name">
<label for="description">簡介</label>
<textarea id="description" name="description"></textarea>
.
.
etc.
</div>
<input type="submit" value="新增">
</form>
Read 查詢
查詢有兩件事要做:
- 在子目錄首頁檢視總列表(index)
- 點擊總列表內容後會連到詳細資料頁面去(show)
要在子目錄的 index.html 中列出清單,會用 class.object.all()
來列出:
views.py
: 渲染路徑和程式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23from django.shortcuts import render, redirect # 渲染路徑、轉址兼解讀路徑
from django.views.decorators.http import require_POST # 判斷是不是 POST
from .models import class名稱 # 從同家的 model.py 取 class
# 要列出總清單的頁面
def home(req):
變數_複 = class名稱.objects.all()
return render(req, "子目錄/index.html", {"key": 變數_複})
# 要輸入資料的頁面
def new(req):
return render(req, "子目錄/new.html")
# 寫入資料庫
def create(req):
變數_單 = class名稱(
name=req.POST["name"],
description=req.POST["description"]
)
變數_單.save()
return redirect("root")index.html
: 渲染到要列出總清單的頁面1
2
3
4
5
6
7
8
9
10
11<h1>總列表</h1>
<!-- 前往新增的頁面 -->
<a href="{% url '子目錄:new' %}">新增</a>
<!-- 用迴圈渲染出總列表 -->
{% for 變數_單 in 變數_複 %}
<!-- 設計卡片囉~ -->
<div>
<!-- 渲染出名稱 -->
{{ 變數_單.name }}
</div>
{% endfor %}
第二個是點擊內容會連去該筆資料的詳細頁面,網址的目標設定為 子目錄/編號
:
urls.py
: 新增路徑1
2
3
4
5
6
7
8
9
10
11
12
13from django.urls import path
from . import views
app_name = '子目錄'
urlpatterns = [
path("", views.home, name="index") # 子目錄首頁
path("new", views.new, name="new") # 要輸入資料的頁面
path("add", views.create, name="add") # 寫入模組
# 網址應該是一個變動的變數,所以要用<>包住,而且順序非常重要,讓比對性的變數網址放在最後,才不會讓其他網址變成變數的值
path("<id>", views.show, name="show") # 單筆資料的詳細頁面
]views.py
: 渲染路徑和程式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29from django.shortcuts import render, redirect get_object_or_404 # 渲染路徑、轉址兼解讀路徑、判斷有無值不然就404
from django.views.decorators.http import require_POST # 判斷是不是 POST
from .models import class名稱 # 從同家的 model.py 取 class
# 要列出總清單的頁面
def home(req):
變數_複 = class名稱.objects.all()
return render(req, "子目錄/index.html", {"key": 變數_複})
# 要列出單筆資料詳細內容的頁面
def show(req, id):
# 為了防止使用者在 QueryString 自己亂找編號,要做一個防止措施
變數_單 = get_object_or_404(class名稱, pk=id) # 主鍵是 id
return render(req, "子目錄/show.html", {"key": 變數_單})
# 要輸入資料的頁面
def new(req):
return render(req, "子目錄/new.html")
# 寫入資料庫
def create(req):
變數_單 = class名稱(
name=req.POST["name"],
description=req.POST["description"]
)
變數_單.save()
return redirect("root")show.html
: 渲染到要列出單筆資料詳細內容的頁面1
2<h1>{{ 變數_單.name }}</h1>
<p>{{ 變數_單.description }}</p>
Update 更新
接下來會在 show.html 裡放上編輯按鈕,會進入更新頁面輸入內容,按下更新按鈕後回到該筆資料頁面,網址的目標設定為 子目錄/編號/edit
:
urls.py
: 新增路徑1
2
3
4
5
6
7
8
9
10
11
12from django.urls import path
from . import views
app_name = '子目錄'
urlpatterns = [
path("", views.home, name="index") # 子目錄首頁
path("new", views.new, name="new") # 要輸入資料的頁面
path("add", views.create, name="add") # 寫入模組
path("<id>/edit", views.edit, name="edit") # 重新輸入資料的頁面
path("<id>", views.show, name="show") # 單筆資料的詳細頁面
]edit.html
: 渲染到重新輸入資料的頁面1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17<h1>更新</h1>
<form action="{% url '子目錄:show' 變數_單.id %}" method="post">
{% csrf_token %}
<div>
<label for="name">姓名</label>
<input type="text" id="name" name="name" value="{{ 變數_單.name }}">
<label for="description">簡介</label>
<textarea id="description" name="description">{{ 變數_單.description }}</textarea>
.
.
etc.
</div>
<input type="submit" value="更新">
</form>views.py
: 渲染路徑和程式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44from django.shortcuts import render, redirect get_object_or_404 # 渲染路徑、轉址兼解讀路徑、判斷有無值不然就404
from django.views.decorators.http import require_POST # 判斷是不是 POST
from .models import class名稱 # 從同家的 model.py 取 class
# 要列出總清單的頁面
def home(req):
變數_複 = class名稱.objects.all()
return render(req, "子目錄/index.html", {"key": 變數_複})
# 要列出單筆資料詳細內容的頁面,若從編輯按鈕的 POST 進入,則會進入 if 流程
def show(req, id):
變數_單 = get_object_or_404(class名稱, pk=id)
if req.method == "POST":
變數_單.name = req.POST["name"]
變數_單.description = req.POST["description"]
.
.
etc.
變數_單.save()
return redirect(f"/子目錄/{變數_單.id}")
else:
return render(req, "子目錄/show.html", {"key": 變數_單})
# 在單筆資料頁面下按下編輯按鈕時後進入的頁面
def edit(req, id):
變數_單 = get_object_or_404(class名稱, pk=id)
return render(req, "子目錄/edit.html", {"key": 變數_單})
# 要輸入資料的頁面
def new(req):
return render(req, "子目錄/new.html")
# 寫入資料庫
def create(req):
變數_單 = class名稱(
name=req.POST["name"],
description=req.POST["description"]
)
變數_單.save()
return redirect("root")show.html
: 渲染到要列出單筆資料詳細內容的頁面1
2
3
4<h1>{{ 變數_單.name }}</h1>
<p>{{ 變數_單.description }}</p>
<a href="{% url '子目錄:edit' 變數_單.id %}">編輯</a>
Delete 刪除
最後的刪除按鈕也會放在 show.html 裡,按下刪除後會連動資料苦的內容一併刪除,按下刪除按鈕後回到 index.html 總列表頁面,網址的目標設定為 子目錄/編號/delete
:
urls.py
: 新增路徑1
2
3
4
5
6
7
8
9
10
11
12
13from django.urls import path
from . import views
app_name = '子目錄'
urlpatterns = [
path("", views.home, name="index") # 子目錄首頁
path("new", views.new, name="new") # 要輸入資料的頁面
path("add", views.create, name="add") # 寫入模組
path("<id>/edit", views.edit, name="edit") # 重新輸入資料的頁面
path("<id>/delete", views.delete, name="delete") # 刪除後跳轉
path("<id>", views.show, name="show") # 單筆資料的詳細頁面
]views.py
: 渲染路徑和程式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51from django.shortcuts import render, redirect, get_object_or_404 # 渲染路徑、轉址兼解讀路徑、判斷有無值不然就404
from django.views.decorators.http import require_POST # 判斷是不是 POST
from .models import class名稱 # 從同家的 model.py 取 class
# 要列出總清單的頁面
def home(req):
變數_複 = class名稱.objects.all()
return render(req, "子目錄/index.html", {"key": 變數_複})
# 要列出單筆資料詳細內容的頁面,若從編輯按鈕的 POST 進入,則會進入 if 流程
def show(req, id):
變數_單 = get_object_or_404(class名稱, pk=id)
if req.method == "POST":
變數_單.name = req.POST["name"]
變數_單.description = req.POST["description"]
.
.
etc.
變數_單.save()
return redirect(f"/子目錄/{變數_單.id}")
else:
return render(req, "子目錄/show.html", {"key": 變數_單})
# 在單筆資料頁面下按下編輯按鈕時後進入的頁面
def edit(req, id):
變數_單 = get_object_or_404(class名稱, pk=id)
return render(req, "子目錄/edit.html", {"key": 變數_單})
# 要輸入資料的頁面
def new(req):
return render(req, "子目錄/new.html")
# 寫入資料庫
def create(req):
變數_單 = class名稱(
name=req.POST["name"],
description=req.POST["description"]
)
變數_單.save()
return redirect("root")
# 連同資料庫刪除該筆資料(硬刪)
def delete(req, id):
變數_單 = get_object_or_404(class名稱, pk=id)
變數_單.delete()
return redirect("子目錄:index")show.html
: 渲染到要列出單筆資料詳細內容的頁面1
2
3
4
5
6
7
8
9<h1>{{ 變數_單.name }}</h1>
<p>{{ 變數_單.description }}</p>
<a href="{% url '子目錄:edit' 變數_單.id %}">編輯</a>
<form action="{% url '子目錄:delete' 變數_單.id %}" method="post">
{% csrf_token %}
<button>刪除</button>
</form>
小結
Django 起手式下篇從子目錄的建立開始介紹,我這邊指的子目錄,其實就代表一個獨立的應用程式,它們各自管理自己名下的檔案們,就不會跟其它的子目錄有衝突,我也很喜歡這種設計。接下來淺談了在 Django 環境中也可以把前端環境整合進來,但我打算將過程、實作和打包再另外寫一篇。
然後就開始介紹連接資料庫、table 生成和 CRUD(我真的很常把 CRUD 寫成 CRUD…好吃!),一開始學習時覺得好多東西,但一旦了解脈絡,再加上練習,我想也能很快駕馭它。