抱歉,您的瀏覽器無法訪問本站
本頁面需要瀏覽器支持(啟用)JavaScript
了解詳情 >

在 Django 框架中,Model 是用來表示資料庫資料的 Python 類別,透過 ORM(物件關聯對應)技術,讓開發者可以用 Python 語法操作資料表。每個 Model 對應一張資料表,類別屬性對應欄位,欄位可設定型別與限制,如 CharField、IntegerField、max_length、null 等。Django 支援資料表之間的關聯,例如一對多(ForeignKey)、一對一(OneToOneField)、多對多(ManyToManyField),讓資料關聯清晰易懂。開發者可以透過 ORM 提供的 API 來新增、查詢、更新、刪除資料,無需寫 SQL。當模型變更時,Django 提供 Migrations 機制來同步資料庫結構。Models 也可以自定義方法、屬性,或透過 Meta 類別設定排序與表名等細節。只要註冊 Model 到 Django 管理後台,就能快速產生完整的資料管理介面。綜合上述,Django 的 Model 系統以簡潔、可讀性高且功能強大的設計,提供開發者一套有效率且穩定的資料庫操作方式。

1. 你建立的第一個 Model

以下程式碼是在 02.Django 4 快速搭建網站 文章中建立一個資料表的程式碼:

1
2
3
4
5
class Post(models.Model):
title = models.CharField(max_length=200)
slug = models.CharField(max_length=200)
body = models.TextField()
pub_date = models.DateTimeField(default=timezone.now)

對應語法說明:

1
2
3
4
class <資料表名稱>(models.Model):
<欄位名稱> = models.<欄位格式>(欄位選項1=值 , 欄位選項1=值)
# ...

2. 欄位型態與屬性設定

2.1 常見欄位型態

欄位格式 參數 說明
BigIntegerField 64位元之大整數
BooleanField 布林值,只有True/False兩種
CharField max_length:指定可接受之字串長度 用來儲存較短資料的字串,通常使用於單行的文字資料
DateField auto_now:每次物件被儲存時即自動加入目前日期 auto_now_add:只有在物件被建立時才加入目前日期 日期格式,可用於datetime.date
DateTimeField 同上 日期時間格式,對應到datetime.datetime
DecimalField max_digits:可接受的最大位數 decimal_places:在所有的位數中,小數佔幾個位數 定點小數數值資料,適用於Python的Decimal模組之實例
FloatField 浮點數欄位
IntegerField 整數欄位,是通用性最高的整數格式
PostiveIntegerField 正整數欄位
SlugField max_length:最大字元長度 和CharField是一樣的,通常用來當做是網址的一部份
TextField 長文字格式,一般是用在HTML表單中的Textarea輸入項目
URLField max_length:最大字元長度 和CharField是一樣的,特別用來記錄完整的URL網址
DecimalField 64位元之大整數

其他詳細欄位說明請參考官方文件

2.2 常見欄位選項

欄位格式 說明
null 此欄位是否接受儲存空值NULL,預設值是False
blank 此欄位是否接受儲存空白內容,預設值是False
choices 以選項的方式(只有固定內容的資料可以選用)當做是此欄位的侯選值
default 輸入此欄位的預設值
help_text 欄位的提示訊息
primary_key 把此欄位設定為資料表中的主鍵KEY,預設值為False

其他詳細欄位選項說明請參考官方文件

2.3 範例

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
from django.db import models

class Product(models.Model):
CATEGORY_CHOICES = [
('ELEC', 'Electronics'),
('BOOK', 'Books'),
('CLTH', 'Clothing'),
('HOME', 'Home & Kitchen'),
]

product_id = models.CharField(
max_length=20,
primary_key=True,
help_text="唯一產品編號,例如 PROD001"
)
name = models.CharField(
max_length=100,
help_text="產品名稱"
)
category = models.CharField(
max_length=4,
choices=CATEGORY_CHOICES,
default='ELEC',
help_text="選擇產品類別"
)
description = models.TextField(
blank=True,
null=True,
help_text="產品描述(可選填)"
)
price = models.DecimalField(
max_digits=10,
decimal_places=2,
default=0.00,
help_text="產品價格"
)
available = models.BooleanField(
default=True,
help_text="是否有庫存"
)

def __str__(self):
return f"{self.name} ({self.product_id})"

3. 建立與套用資料遷移(Migrations)

使用 Django 框架進行開發,當您新增或是修改模型後,必須透過「資料遷移 (Migrations)」,將資料庫中的資料表進行同步。

3.1 建立遷移檔案 (makemigrations)

1
python manage.py makemigrations

上面這一則指令,會根據所有 APP 底下 models.py 的更動,自動建立一個遷移檔案,紀錄哪些資料標的結構變化。執行成功後會出現類似以下訊息:

1
2
3
Migrations for 'myapp':
myapp/migrations/0001_initial.py
- Create model Book

3.2 套用遷移檔案至資料庫 (migrate)

透過以下指令,將遷移的內容進行資料庫對應資料表的修改與變更。

1
python manage.py migrate

執行完成後會得到類似下面的提示訊息:

1
2
3
4
Operations to perform:
Apply all migrations: admin, auth, contenttypes, myapp, sessions
Running migrations:
Applying myapp.0001_initial... OK

3.3 其他 Migrateions 相關指令

查看目前遷移狀態:

1
python manage.py showmigrations

指令特定的 APP 進行遷移:

1
python manage.py makemigration <app:name>

4. 使用 Django Shell 操作 Models

Djagno 提供互動式 Python 命令列介面 (Django Shell),可以直接透過 Django Models 進行存取資料庫的資料,進行新增、查詢、更新及刪除 (Create, Read, Update, Delete; CRUD) 操作,適合用來測試與偵錯。

4.1 進入 Django Shell

透過以下指令,進入互動式命令介面:

1
python manage.py shell

當終端機看到 Python 的互動式提示符號 (>>>) 即可開始進行操作。

4.2 載入需要操作的模型

假設 posts/models.py 存在 Post 的模型,透過 Python import 語法,將其匯入至互動式介面:

1
from posts.models import Post

4.3 新增資料 (Create)

透過 create() 方法新增一筆資料:

1
2
3
4
5
article = Post.objects.create(
title='Django 教學',
slug='django-course',
content='Test for content ...',
)

或者先建立實體再透過 save() 進行存入資料庫:

1
2
3
4
5
6
article = Post(
title='Django Models 教學',
slug='django-course-models',
content='Test for content ...',
)
article.save()

create()save() 方式都可以使用,取決於使用的時機。

4.4 查詢(讀取)資料 (Read)

查詢所有資料:

1
Post.objects.all()

查詢特定條件 (filter):

1
Post.objects.filter(content="Test for content ...")

查詢單一紀錄 (get):

1
Post.objects.get(slug="django-course-models")

如果 get() 查詢到多筆或找不到資料時會拋出 error,建議使用 try/expect處理。

欄位排序:

1
Post.objects.order_by('-pub_date')

模糊查詢:

1
2
Post.objects.filter(content__icontains="django")
Post.objects.filter(slug__startswith="D")

4.5 更新資料 (Update)

1
2
3
article = Post.objects.get(id=1)
article.title = "Django 入門完全指南"
book.save()

批次更新

1
Post.objects.filter(content__icontains="django").update(title="Django 入門指南書")

4.6 刪除資料 (Delete)

1
2
article = Post.objects.get(id=1)
article.delete()

批次刪除:

1
Post.objects.filter(content__icontains="django").delete()

4.7 其他常用的查詢處理

計算資料筆數:

1
Post.objects.count()

檢查資料是否存在:

1
Post.objects.filter(title="Django 教學").exists()

取得弟一筆資料:

1
Post.objects.first()

取得最新一筆資料(需 ordering):

1
Book.objects.latest('published_date')

5. 建立關聯模型(Relationships)

在 Django 中,模型之間常常需要建立關聯,以呈現資料之間的邏輯與結構關係。舉例來說,一個使用者可能撰寫多篇文章,而每篇文章則對應到一位作者,這種關聯關係在資料庫設計中非常常見。為了方便在程式中表示與操作這些關係,Django 提供了三種主要的關聯欄位類型,分別是 ForeignKey(一對多)、OneToOneField(一對一)以及 ManyToManyField(多對多),讓開發者能夠清楚且有效率地定義資料模型之間的關聯性。

5.1 ForeignKey (一對多)

表示「多個紀錄」對應到「一個紀錄」。例如:多篇文章(Article)屬於同一位作者(Author)。

1
2
3
4
5
6
7
class Author(models.Model):
name = models.CharField(max_length=100)

class Article(models.Model):
title = models.CharField(max_length=200)
content = models.TextField()
author = models.ForeignKey(Author, on_delete=models.CASCADE)

ForeignKey() 的第一個參數表示關聯的資料表,第二個參數表示級聯 (CASCADE),當被參照的資料被刪除時,參照資料也會一併刪除。使用案例:

1
2
author = Author.objects.get(id=1)
articles = author.article_set.all() # 預設反查

其中 article_set 為反查關聯的模型 (小寫模型名稱 + _set)。

5.2 OneToOneField (一對一)

表示兩個模型之間為一對一關係,例如一個使用者對應一份個人資料(Profile)。

1
2
3
4
5
6
class User(models.Model):
username = models.CharField(max_length=100)

class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.TextField()
1
2
user = User.objects.get(id=1)
profile = user.profile # 反查 profile

5.3 ManyToManyField (多對多)

表示多個物件彼此互相關聯,例如:學生選課,學生與課程之間是多對多關係。

1
2
3
4
5
6
class Student(models.Model):
name = models.CharField(max_length=100)

class Course(models.Model):
name = models.CharField(max_length=100)
students = models.ManyToManyField(Student, related_name="courses")
1
2
3
4
5
6
7
# 取得某學生的所有課程
student = Student.objects.get(id=1)
student_courses = student.courses.all()

# 取得某課程的所有學生
course = Course.objects.get(id=1)
course_students = course.students.all()

related_name 讓我們能更直覺地從關聯模型反向查詢。
範例(多對多):

1
2
3
4
5
6
class Tag(models.Model):
name = models.CharField(max_length=50)

class Post(models.Model):
title = models.CharField(max_length=100)
tags = models.ManyToManyField(Tag, related_name="posts")
1
2
tag = Tag.objects.get(name="Django")
related_posts = tag.posts.all() # 使用 related_name

5.5 關聯查詢語法範例(ORM 實作)

5.5.1 正向查詢

1
2
3
# 取得某篇文章的作者名字
article = Article.objects.get(id=1)
author_name = article.author.name

5.5.2 反向查詢

1
2
3
# 取得某位作者的所有文章
author = Author.objects.get(id=1)
articles = author.article_set.all() # 若有指定 related_name,則使用 related_name

5.5.3 篩選關聯資料

1
2
# 查詢某作者的所有文章(用 filter)
Article.objects.filter(author__name="王小明")

5.5.4 多層關聯查詢

1
2
# 查詢某課程的所有學生的名字
Course.objects.get(id=1).students.values_list('name', flat=True)
1
2
# 查詢有標籤「Python」的所有文章
Post.objects.filter(tags__name="Python")

6. Meta 類別與自定義 Model 行為

在 Django 的模型中,可以透過 Meta 類別來定義一些模型的元資料(metadata),例如排序方式、資料表名稱、權限設定等。此外,我們也可以透過撰寫自定義方法來擴充模型的行為,例如 __str__() 方法顯示易讀的物件名稱,或加入自定義的查詢方法以提高開發效率。

6.1 Meta 類別自定義模型: 排序 (ordering)

透過 ordering 屬性可以設定模型查詢結果的預設排序方式。

1
2
3
4
5
6
class Article(models.Model):
title = models.CharField(max_length=200)
published_date = models.DateTimeField()

class Meta:
ordering = ['-published_date'] # 預設以發佈日期遞減排序

這樣當我們使用 Article.objects.all() 時,資料會依照發佈日期從新到舊排序。

6.2 Meta 類別自定義模型: 資料表名稱 (db_table)

Django 預設會根據模型名稱自動建立資料表名,例如模型 Article 對應的資料表為 appname_article。你可以使用 db_table 自定義資料表名稱:

1
2
3
4
5
class Article(models.Model):
title = models.CharField(max_length=200)

class Meta:
db_table = 'my_articles' # 自訂資料表名稱

6.3 Meta 類別自定義模型: 權限 (permissions)

可以在 Meta 中自定義額外的權限,例如給特定角色額外操作的能力:

1
2
3
4
5
6
7
8
class Report(models.Model):
title = models.CharField(max_length=200)

class Meta:
permissions = [
("can_approve", "Can approve reports"),
("can_reject", "Can reject reports"),
]

這些權限會在 auth_permission 表中建立,可以搭配 Django 的權限系統使用(如 admin 介面或 @permission_required 裝飾器)。

6.4 自定義模型方法: __str__()

定義物件在顯示(例如 admin 後台、印出物件)時的字串表達方式,提高可讀性:

1
2
3
4
5
class Author(models.Model):
name = models.CharField(max_length=100)

def __str__(self):
return f"Author: {self.name}"

在 admin 中或使用 print(author) 時,會顯示 Author: 張大明 而非 <Author object>

6.5 自定義查詢方法

你可以在模型中定義常用的查詢邏輯,提高重用性與可讀性。例如:

1
2
3
4
5
6
7
class Product(models.Model):
name = models.CharField(max_length=100)
price = models.DecimalField(max_digits=8, decimal_places=2)
is_active = models.BooleanField(default=True)

def is_expensive(self):
return self.price > 1000

或者你也可以透過 Manager 自定義查詢集(更進階的用法):

1
2
3
4
5
6
7
8
9
10
11
12
13
class ActiveProductManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(is_active=True)

class Product(models.Model):
name = models.CharField(max_length=100)
is_active = models.BooleanField(default=True)

objects = models.Manager() # 預設管理器
active = ActiveProductManager() # 自訂管理器

# 使用自訂查詢
Product.active.all()

7. 整合 Django Admin 後台

Django 提供功能強大且即時可用的管理後台(Admin site),讓我們能快速檢視與操作資料庫中的資料。透過簡單的設定,就能將自訂模型整合進後台,並根據實際需求調整後台介面的顯示方式與操作便利性。

7.1 在 admin.py 中註冊模型(Model)

若要讓模型顯示在 Django Admin 後台中,需在對應的 app 資料夾內的 admin.py 檔案中註冊該模型。

1
2
3
4
5
6
# blog/admin.py

from django.contrib import admin
from .models import Article

admin.site.register(Article)

這樣一來,Article 模型就會出現在後台的操作介面中,預設提供新增、修改、刪除與列表功能。

7.2 自定義後台顯示樣式

為了讓資料管理更清晰與便利,我們可以透過自定義 ModelAdmin 類別的方式,客製化後台資料列表的顯示與搜尋行為。

7.2.1 list_display:自訂列表顯示欄位

設定在模型列表頁中要顯示哪些欄位。

1
2
class ArticleAdmin(admin.ModelAdmin):
list_display = ('title', 'author', 'published_date', 'is_published')

7.2.2 search_fields:啟用關鍵字搜尋功能

讓管理員可以在後台透過關鍵字搜尋特定欄位內容。

1
2
class ArticleAdmin(admin.ModelAdmin):
search_fields = ('title', 'content', 'author__name')

支援外鍵欄位(使用 __ 連結關聯欄位)。

7.2.3 list_filter:側邊欄篩選器

可以根據特定欄位篩選資料,例如日期、狀態、分類等。

1
2
class ArticleAdmin(admin.ModelAdmin):
list_filter = ('published_date', 'is_published', 'author')

在後台列表頁左側會出現篩選選單,方便快速縮小資料範圍。

8. 進階技巧與實務應用

隨著 Django 專案越來越複雜,我們可以運用進階技巧讓程式更具可讀性、可維護性與彈性。以下介紹幾個常見的實務應用技巧,包括自定查詢邏輯、模型繼承、訊號機制、欄位優化與特殊欄位使用等。

8.1 使用 Managers 自定義查詢邏輯

在模型中可以透過自定義 Manager 來封裝複雜或常用的查詢邏輯。
範例:

1
2
3
4
5
6
7
8
9
10
class PublishedArticleManager(models.Manager):
def get_queryset(self):
return super().get_queryset().filter(is_published=True)

class Article(models.Model):
title = models.CharField(max_length=200)
is_published = models.BooleanField(default=False)

objects = models.Manager() # 預設 Manager
published = PublishedArticleManager() # 自定 Manager

使用方式:

1
Article.published.all()  # 只會回傳已發佈的文章

8.2 Model 繼承與抽象類別(Abstract Base Classes)

Django 支援模型繼承,可以建立一個「抽象基底模型」來共用欄位與邏輯,減少重複程式碼。
範例:

1
2
3
4
5
6
7
8
9
class TimestampedModel(models.Model):
created_at = models.DateTimeField(auto_now_add=True)
updated_at = models.DateTimeField(auto_now=True)

class Meta:
abstract = True # 不會建立對應資料表

class Article(TimestampedModel):
title = models.CharField(max_length=200)

這樣 Article 會自動繼承 created_atupdated_at 欄位,但不會建立 TimestampedModel 的資料表。

8.3 模型訊號(Model Signals)

Django 提供一組訊號機制(signals),允許我們在模型執行某些動作前後執行自訂邏輯。
常見訊號:

  • pre_save:儲存前
  • post_save:儲存後
  • pre_delete / post_delete

範例:

1
2
3
4
5
6
7
from django.db.models.signals import post_save
from django.dispatch import receiver

@receiver(post_save, sender=Article)
def notify_author(sender, instance, created, **kwargs):
if created:
print(f"新文章已建立:{instance.title}")

這種方式可以用來做自動通知、紀錄日誌、建立關聯資料等用途。

8.4 善用 choices 設定列舉型欄位

當欄位只有固定選項時(例如文章狀態、性別、等級),可以使用 choices 增加資料一致性與後台清晰度。
範例:

1
2
3
4
5
6
7
8
9
10
11
12
13
class Article(models.Model):
DRAFT = 'D'
PUBLISHED = 'P'
ARCHIVED = 'A'

STATUS_CHOICES = [
(DRAFT, '草稿'),
(PUBLISHED, '已發佈'),
(ARCHIVED, '封存'),
]

title = models.CharField(max_length=200)
status = models.CharField(max_length=1, choices=STATUS_CHOICES, default=DRAFT)

在 admin 後台與表單中會自動顯示對應的中文標籤,增加可讀性。

8.5 使用進階欄位型別

Django 提供多種進階欄位型別,方便處理特殊需求資料:

8.5.1 UUIDField:使用 UUID 作為主鍵或識別碼(更安全

1
2
3
4
import uuid

class APIKey(models.Model):
id = models.UUIDField(primary_key=True, default=uuid.uuid4, editable=False)

8.5.2 SlugField:可讀性佳的網址段落(適合用於 SEO)

1
2
3
class Article(models.Model):
title = models.CharField(max_length=200)
slug = models.SlugField(unique=True)

可以搭配 pre_saveslugify() 自動產生。

8.5.3 ImageField:處理圖片上傳

1
2
3
class Profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
avatar = models.ImageField(upload_to='avatars/')

需要搭配 Pillow 套件安裝 pip install Pillow

留言