F()允許Django在未實際鏈接數據的情況下具有對數據庫字段的值的引用。通常情況下我們在更新數據時需要先從數據庫里將原數據取出后方在內存里,然后編輯某些屬性,最后提交。例如這樣
# Tintin filed a news story!
reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed += 1 reporter.save()
上述代碼中我們先將reporter.stories_filed的值從數據庫中取出放到內存中然后利用python的語法操作計算出新的值之后調用save()方法保存回數據庫最終生成是SQL語句有可能是類似
updatereporterset stores_filed = 20 wherename = 'smp'; --20可能是經過計算之后得到的值。
而我們知道其實我們的需求其實可以理解成SQL:
updatereporterset stores_filed = stores_filed+1 wherename = 'smp'
解決
而F()函數的左右就是直接生成SQL語句來描述類似的需求,看下面代碼:
fromdjango.db.modelsimport F
reporter = Reporters.objects.get(name='Tintin') reporter.stories_filed = F('stories_filed') + 1 reporter.save()
雖然代碼 reporter.stories_filed = F('stories_filed') + 1
有點類似python風格的代碼,但實際上卻能生成SQL語句直接描述對數據庫的操作。
當Django程序中出現F()時,Django會使用SQL語句的方式取代標准的Python操作。
上述代碼中不管 reporter.stories_filed
的值是什么,Python都不曾獲取過其值,python做的唯一的事情就是通過Django的F()函數創建了一條SQL語句然后執行而已。
需要注意的是在使用上述方法更新過數據之后需要重新加載數據來使數據庫中的值與程序中的值對應:
reporter = Reporters.objects.get(pk=reporter.pk)
或者使用更加簡單的方法:
reporter.refresh_from_db()
更新多條數據
與上面的在一個對象中操作的例子相似,F()函數同樣可以使用在查詢集中,配合update()方法。這樣我們同樣可以將更新的兩步合並成一步:
reporter = Reporters.objects.filter(name='Tintin') reporter.update(stories_filed=F('stories_filed') + 1)
我們同樣可以使用 update()
方法增加或者更改字段的值,這樣做的效率比將其取到內存中后再一個個計算值再更新數據庫的效率會提高非常多。
Reporter.objects.all().update(stories_filed=F('stories_filed') + 1)
組合使用
F()函數可以在創建模型時根據已知的N個字段組合出另外的字段數據,看下面的例子:
company = Company.objects.annotate(
chairs_needed=F('num_employees') - F('num_chairs'))
但是如果組合的兩個字段擁有不同的數據類型,那么咱們需要手動告訴Django新生成的數據類似是什么,看下面的列子:
fromdjango.db.modelsimportDateTimeField, ExpressionWrapper, F
Ticket.objects.annotate(
expires=ExpressionWrapper(
F('active_at') + F('duration'), output_field=DateTimeField()))
上述代碼描述了個過期時間的概念,數據庫中保存的是激活時間和持續時間,並且通過參數 output_field
告訴 expires
的類型為 DateTimeField