使用 django.db.models.F 表達式的 Django ORM 強大功能
在使用 Django 時,經常會遇到想在不直接寫 SQL 的情況下完成複雜運算的需求。此時,django.db.models.F 表達式就顯得非常有用。
本文將說明 F 表達式是什麼、何時以及如何使用,並透過幾個實際範例展示其應用。
1. F 表達式是什麼?
F 表達式是一種引用資料庫欄位值的表達式。也就是說,它在資料庫層面讀取欄位值,並可用於與其他欄位比較或進行運算。
from django.db.models import F
重點 -
F表達式不是 Python 物件,而會被轉換成 SQL 表達式。 - 使用F可以在資料庫端一次完成運算,避免先取值再回寫,效能更佳。
2. 為什麼需要 F 表達式?
2-1. 防止競爭條件
想像以下情境:
product.stock -= 1
product.save()
- 若兩位使用者同時購買同一商品,第一位會將
stock減 1 並儲存,第二位則會讀取到已減 1 的值,再減 1,結果stock會被減 2,產生錯誤。
使用 F 表達式,資料庫會自行完成遞減,避免競爭問題。
Product.objects.filter(id=product_id).update(stock=F('stock') - 1)
2-2. 複雜篩選
F 表達式可用於欄位之間的比較。
# 價格大於折扣價的商品
Product.objects.filter(price__gt=F('discount_price'))
2-3. 大量更新
利用 F 表達式可一次性更新多筆資料。
# 所有商品價格上調 10%
Product.objects.update(price=F('price') * 1.10)
3. F 表達式的使用方法
3-1. 基本用法
from django.db.models import F
# 欄位比較
qs = Book.objects.filter(pages__gt=F('chapters'))
# 欄位運算
qs = Book.objects.update(pages=F('pages') + 10)
3-2. 與 Q 表達式結合
Q 表達式可用於構造複雜條件。
from django.db.models import Q
qs = Book.objects.filter(
Q(pages__gt=F('chapters')) | Q(pages__lt=F('pages') * 2)
)
3-3. 與 annotate 結合
annotate 可為查詢集添加虛擬欄位。
from django.db.models import F, Value, FloatField
qs = Book.objects.annotate(
ratio=F('pages') / F('chapters')
).filter(ratio__gt=5)
注意:不同資料庫對
F表達式的支援程度不同,例如 SQLite 可能不支援*運算,使用前請先測試。
4. 實戰範例
4-1. 庫存管理
# 減少庫存 1,若庫存降至 0 以下則停用
Product.objects.filter(id=product_id, stock__gt=0).update(
stock=F('stock') - 1,
is_active=Case(
When(stock=1, then=Value(False)),
default=Value(True),
output_field=BooleanField()
)
)
4-2. 折扣率計算
# 只查詢折扣率 ≥ 20% 的商品
Product.objects.annotate(
discount_rate=F('discount_price') / F('price')
).filter(discount_rate__gte=0.2)
4-3. 大量價格上調
# 將「electronics」類別的所有商品價格上調 15%
Product.objects.filter(category='electronics').update(
price=F('price') * 1.15
)
5. 使用 F 表達式的技巧
| 情境 | 推薦用法 |
|---|---|
| 競爭 | update() + F |
| 欄位比較 | filter(field__gt=F('other_field')) |
| 虛擬欄位 | annotate(new_field=F('field1') + F('field2')) |
| 條件更新 | Case + When + F |
Tip:
F表達式直接轉成 SQL,建議透過資料庫的執行計畫檢視實際效能。
6. 總結
django.db.models.F 表達式是讓你在資料庫層面完成運算的強大工具。 - 解決競爭條件 - 簡化複雜篩選 - 高效處理大量更新
若想更進一步發揮 Django ORM 的潛力,請多加使用 F 表達式。 
進一步閱讀 - Django 官方文件: F expressions - 實作範例: GitHub Gist
Happy coding! 🚀
目前沒有評論。