Django小技巧13: 使用F()表達式

翻譯整理自: simpleisbetterthancomplex.com

在 Django QuerySets API 中, F() 用於直接在數據庫中引用模型的值。假設你有一個帶有price的 Product 模型, 你希望爲所有的Product的價格上漲20%.

一個可以實現在解決方案:

Python

products = Product.objects.all()
for product in products:
    product.price *= 1.2
    product.save()

相反, 你可以在單個查詢中更新price.

Python

from django.db.models import F

Product.objects.update(price=F('price') * 1.2)

你也可以對單個對象執行這個操作:

Python

product = Product.objects.get(pk=5009)
product.price = F('price') * 1.2
product.save()

要注意, 保存模型後, F()對象依然存在.

Python

product.price                   # price = Decimal('10.00')
product.price = F('price') + 1
product.save()                  # price = Decimal('11.00')
product.name = 'What the F()'
product.save()                  # price = Decimal('12.00')

所以, 在更新這樣的字段後, product.price實際上保存的是django.db.models.expressions.CombinedExpression實例, 而不是實際結果。

如果要立即訪問結果:

Python

product.price = F('price') + 1
product.save()
print(product.price)            # <CombinedExpression: F(price) + Value(1)>
product.refresh_from_db()
print(product.price)            # Decimal('13.00')

你可以使用F()實現annotate功能:

Python

from django.db.models import ExpressionWrapper, DecimalField

Product.objects.all().annotate(
    value_in_stock=ExpressionWrapper(
        F('price') * F('stock'), output_field=DecimalField()
    )
)

由於price是DecimalField, 而stock是IntegerField,我們需要將表達式包裝在ExpressionWrapper中.

也可以用來過濾數據:

Python

Product.objects.filter(stock__gte=F('ordered'))
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章