本文為 Django 分類功能系列教學,第 6 篇:
get_or_create 是 Django 提供的一個實用方法,用於查找資料庫中的某個物件,若未找到則創建它。
這在初始化數據或確保資料唯一性時非常有用。
本篇文章將帶您了解 get_or_create 的運作方式,並逐步解析其關鍵參數與使用範例,幫助您靈活運用。
什麼是 get_or_create?
get_or_create 是 Django ORM 提供的一個便捷方法,主要用於 查找資料庫中的特定物件,如果該物件 不存在,則會 創建並儲存 到資料庫。
運作機制
- 查找資料庫:根據提供的條件(例如名稱或時間)進行查詢。
- 創建新物件:如果查詢不到符合條件的物件,則會創建一個新物件並儲存至資料庫。
此方法會回傳一個 tuple,包含:
- 第一個值:查找到的 或 新創建的 模型物件。
- 第二個值:布林值,表示該物件是否是新創建的(
True代表新建,False代表查找到已存在的物件)。
回傳 Tuple 值範例
假設我們有一個 Category 模型:
from django.db import models
class Category(models.Model):
name = models.CharField(max_length=255, unique=True)
created_at = models.DateTimeField(auto_now_add=True)
def __str__(self):
return self.name
執行 get_or_create:
category, created = Category.objects.get_or_create(name="科技")情境 1:資料庫中已有 name="科技" 的分類
category:返回資料庫中已存在的Category物件created:False(表示該物件已存在,未創建新物件)- 回傳結果:
(<Category: 科技>, False)情境 2:資料庫中尚無 name="科技" 的分類
category:返回 新創建 的Category物件created:True(表示剛剛創建了該物件)- 回傳結果:
(<Category: 科技>, True)如果你想查看 category 的內容,可以這樣做:
print(category.__dict__)假設該物件是新創建的,輸出可能是:
{
'id': 5,
'name': '科技',
'created_at': datetime.datetime(2024, 2, 24, 14, 0, 0),
}關鍵參數解說
基本語法
Model.objects.get_or_create(defaults=None, **kwargs)kwargs(必填)- 查詢條件,必須傳入一個或多個參數,對應模型的欄位名稱。
- 用於匹配資料庫中的資料,例如:
Category.objects.get_or_create(name="餐飲")查詢資料庫是否存在name="餐飲"的分類。
defaults(選填)- 傳入字典,指定創建新物件時,需要設置的額外欄位值。
- 若不提供此參數,
get_or_create會僅依據kwargs創建新物件。 - 範例:
Category.objects.get_or_create( name="運動", defaults={"created_at": "2024-01-01"} )- 查詢條件是
name="運動"。 - 如果創建新物件,則設定
created_at="2024-01-01"。
- 查詢條件是
運作行為解析
查找流程
- Django 根據
kwargs條件生成 SQL 查詢語句。 - 如果找到符合條件的物件,返回該物件,並將布林值
created=False。
創建流程
- 如果查詢未找到符合條件的物件,Django 使用
kwargs和defaults的值創建一個新物件。 - 創建的物件會立即儲存到資料庫中,並返回該物件,將布林值
created=True。
實用範例
基本用法
category, created = Category.objects.get_or_create(name="教育")
if created:
print(f"新建了分類:{category.name}")
else:
print(f"分類已存在:{category.name}")
行為解析
- 如果資料庫中存在
name="教育"的分類,返回該分類,並輸出「分類已存在」。 - 如果資料庫中不存在該分類,創建新分類並輸出「新建了分類」。
使用 defaults
category, created = Category.objects.get_or_create(
name="娛樂",
defaults={"created_at": "2024-01-01"}
)
行為解析
- 查詢條件:
name="娛樂"。 - 如果創建新分類:
name設為"娛樂"。created_at設為"2024-01-01"。
錯誤處理:唯一約束導致的錯誤
當模型的欄位具有唯一約束(如 name 是唯一的),如果多個請求同時執行 get_or_create 且嘗試創建相同的資料,可能會導致 IntegrityError。
解決方式是使用 try/except 處理:
from django.db import IntegrityError
try:
category, created = Category.objects.get_or_create(
name="餐飲",
defaults={"created_at": "2024-01-01"}
)
except IntegrityError:
category = Category.objects.get(name="餐飲")
created = False
未解構與解構版本解析
在 get_or_create 方法中,返回值是一個 tuple,包含:
- 查詢到的或新創建的物件。
- 一個布林值,表示是否創建了新物件。
解構版本
category, created = Category.objects.get_or_create(name="教育")- 說明:
- 直接將返回的 tuple 解構成兩個變數:
category:返回的分類物件。created:布林值,表示是否創建新物件。
- 直接將返回的 tuple 解構成兩個變數:
- 簡潔性:適合熟悉 Python 解構語法的開發者。
未解構版本
result = Category.objects.get_or_create(
name="教育",
defaults={"created_at": "2024-01-01"}
)
category = result[0] # 取得返回的分類物件
created = result[1] # 取得是否創建新物件的布林值- 說明:
- 首先接收 tuple,再手動提取兩個值。
- 適用場景:
- 初學者需要熟悉
get_or_create的返回值結構時。 - 較複雜的操作邏輯需要手動分別處理返回值時。
- 初學者需要熟悉
使用注意事項
- 競爭條件(Race Condition)
- Django 的
get_or_create是原子操作,理論上避免了大多數競爭條件,但當多個請求同時操作同一條件時,仍可能拋出IntegrityError。
- Django 的
- 僅適用於查找或新增
- 如果需要更新現有物件,請改用
update_or_create,該方法同時支持查找、創建和更新操作。
- 如果需要更新現有物件,請改用
結論
get_or_create 是一個簡單高效的方法,用於在資料庫中查找或新增物件。
- 常見用法:初始化資料、確保資料唯一性、減少重複插入。
- 靈活性:透過
defaults提供額外參數,滿足創建時的欄位需求。 - 實用建議:熟悉解構與未解構的用法,根據場景靈活選擇。
現在,試著將 get_or_create 應用於您的 Django 專案吧!