本文為 資料庫正規化 基本介紹系列文,第 1 篇:
在 Django 的 ORM(Object-Relational Mapping,物件關聯對映)中,update_or_create() 是一個 便捷的方法,它可以用來 更新現有記錄,或在記錄不存在時自動建立新記錄。
這在處理資料時非常實用,尤其是在 批量匯入資料、同步外部 API 數據,或 確保唯一記錄存在 時,能夠有效減少程式碼複雜度。
在這篇文章中,我們將詳細介紹 update_or_create() 的用法,包括其 基本語法、參數說明、實際範例,並比較它與其他 ORM 方法的異同,讓你能夠靈活運用這個強大的方法!
update_or_create() 是什麼?
在 Django ORM 中,update_or_create() 提供了一種 先查找再更新,若不存在則建立 的機制,語法如下:
Model.objects.update_or_create(defaults=None, **kwargs)參數說明
| 參數 | 說明 |
|---|---|
defaults | (選填) 這是一個字典,包含要 更新或設定 的欄位值。 |
**kwargs | (必要) 這是查找條件,用來 篩選對應的資料記錄。如果找不到,就會建立新的記錄。 |
回傳值
update_or_create() 會回傳一個 (物件, created) 的 tuple:
物件:更新或建立的 Django Model 物件。created(布林值):如果是新建立的物件,則回傳True,否則回傳False(代表該記錄已存在,並已更新)。
基本範例
假設我們有一個 UserProfile 模型
from django.db import models
class UserProfile(models.Model):
username = models.CharField(max_length=100, unique=True)
email = models.EmailField(unique=True)
age = models.IntegerField(default=18)
def __str__(self):
return self.username
使用 update_or_create()
from myapp.models import UserProfile
user, created = UserProfile.objects.update_or_create(
username="john_doe", # 查找條件
defaults={"email": "john@example.com", "age": 25} # 如果存在就更新
)
if created:
print("新用戶已建立:", user)
else:
print("用戶已存在,已更新資料:", user)
可能的情境
- 如果
username="john_doe"已經存在:email會被更新為"john@example.com"。age會被更新為25。created會是False,表示這筆資料已經存在,並且已被更新。
- 如果
username="john_doe"不存在:- 會建立一筆新的
UserProfile記錄。 created會是True,表示這是一筆新資料。
- 會建立一筆新的
update_or_create() 與 get_or_create() 的比較
update_or_create() 與 get_or_create() 類似,主要區別如下:
| 方法 | 功能 |
|---|---|
get_or_create() | 如果找到資料就回傳,如果沒找到就建立新資料,不會更新現有資料。 |
update_or_create() | 如果找到資料就更新,如果沒找到就建立新資料。 |
get_or_create() 範例
user, created = UserProfile.objects.get_or_create(
username="john_doe",
defaults={"email": "john@example.com", "age": 25}
)- 如果
john_doe存在,它不會更新email或age,只會返回現有物件。 - 如果
john_doe不存在,就會建立新的記錄。
👉 如果你需要更新現有資料,請使用 update_or_create()。
update_or_create() 的進階應用
使用多個查找條件
你可以使用多個條件來查找記錄:
user, created = UserProfile.objects.update_or_create(
username="john_doe",
email="john@example.com",
defaults={"age": 30} # 只更新 `age` 欄位
)
這裡的查找條件是 username="john_doe" 且 email="john@example.com"。
只更新部分欄位
如果只想更新某些欄位,可以在 defaults 內傳入所需的欄位:
user, created = UserProfile.objects.update_or_create(
username="jane_doe",
defaults={"age": 28} # 只更新 `age`,不影響其他欄位
)
update_or_create() 內建 save()
update_or_create() 會在內部執行 save(),所以不需要額外呼叫:
user, created = UserProfile.objects.update_or_create(
username="michael",
defaults={"email": "michael@example.com"}
)
print(user.email) # 自動更新後的資料
這與手動執行 .save() 效果相同。
與 transaction.atomic() 搭配使用
在某些情況下,若有多個 update_or_create() 可能影響到相同的記錄,建議使用 資料庫交易(transaction)來確保資料一致性:
from django.db import transaction
with transaction.atomic():
user, created = UserProfile.objects.update_or_create(
username="alice",
defaults={"email": "alice@example.com", "age": 22}
)
這樣可以確保 在多個請求同時寫入資料時,不會產生競爭條件(Race Condition)。
什麼時候該使用 update_or_create()?
適用情境:
✅ 匯入外部資料(例如 API 回應數據,若存在就更新,否則建立)。
✅ 批量同步資料(避免重複建立相同記錄)。
✅ 確保唯一記錄存在(例如每個 username 只能有一筆記錄)。
✅ 避免手動查找與更新(相比 get() + save(),更簡潔高效)。
不適用情境:
❌ 不需要更新資料,只要確保記錄存在時,應該用 get_or_create()。
❌ 批量更新大量資料,用 bulk_update() 可能效能更好。
總結
✅ update_or_create() 先查找,若存在則更新,若不存在則建立新記錄。
✅ 回傳 (物件, created),created=True 代表新建立,False 代表已更新。
✅ 可用 defaults={} 指定要更新的欄位,不影響 kwargs 查找條件內的欄位。
✅ 比 get_or_create() 更適合需要「更新」的情境。
✅ 可與 transaction.atomic() 搭配,確保數據一致性。
💡 掌握 update_or_create(),讓你的 Django 專案更高效、靈活!🚀