Django中F函數的使用

開發我的博客時,統計每篇文章瀏覽量的邏輯一般是這樣寫的:數據庫

post = Post.objects.get(...)
post.views += 1
post.save()

上面的語句已經至關簡短了,但實際上還有更好的辦法,就是運用 F 函數:django

from django.db.models import F

post = Post.objects.get(...)
post.views = F('views') + 1
post.save()

看起來彷佛都差很少,可是用 F 函數有幾個顯著的好處:函數

  • 減小了操做次數post.view += 1 是 Python 在內存中操做的,而後再從內存把數據更新到數據庫;而 F('views') + 1 是直接操做的數據庫,減小了一個操做層級。
  • 避免競爭。競爭是指多個 Python 線程同時對同一個數據進行更新,post.view += 1 就有可能丟失其中的某些更新操做,而 F('views') + 1 因爲是直接操做數據庫,不會有丟失數據的問題。

注意,正由於 F 函數沒有在內存中操做,所以更新完數據後須要從新刷新內存中的模型對象:post

...
post.save()
# 從新取值
post = Post.objects.get(...)

或者這樣:線程

...
post.save()
# 從新取值
post.refresh_from_db()

Done!code

除此以外,F 函數還支持跨字段的查找:對象

# models.py
class Age(models.Model):
    year = models.IntegerField(default=6)
    month = models.IntegerField(default=10)

# --------------

# 獲取全部 year > month 的數據
res = Age.objects.filter(year__gt=F('month'))

F 函數支持加,減,乘,除,取模和冪運算:內存

Age.objects.filter(year__gt=F('month') * 2)
Age.objects.filter(year__gt=F('month') + F('year'))

對於日期字段,也能夠輕鬆處理:開發

>>> from datetime import timedelta
>>> Entry.objects.filter(date__gt=F('pub_date') + timedelta(days=3))

跨關係的查找也是能夠的:文檔

# models.py
class Person(...):
    name = ...

class People(...):
    name = ...

class Age(...):
    ...
    person = models.OneToOneField(Person, ...)
    people = models.OneToOneField(People, ...)

# --------------

# 獲取全部 person.name == user.name 的數據
res = Age.objects.filter(person__name=F('people__name'))
F 函數還有一些更高級的用法,如與聚合的配合,這裏就不列舉了,有興趣的能夠前往文檔觀摩。
相關文章
相關標籤/搜索