- The power of django's Q objects
- Dynamic Django queries (or why kwargs is your friend)
- https://docs.djangoproject.com/en/dev/ref/models/queries/#q-objects
- https://github.com/django/django/blob/master/django/db/models/query_utils.py
- https://docs.djangoproject.com/en/dev/topics/db/queries/
- help('django.db.models.query_utils.Q')
寫這篇的時候 Django 目前的版本是 1.6.5 & 1.7 RC1
用 Q Objects 可以一次做更複雜的 query, 支援 | (OR) 和 & (AND) 的操做
from django.utils import tree
class Q(tree.Node):
"""
Encapsulates filters as objects that can then be combined logically (using
& and |).
"""
# Connection types
AND = 'AND'
OR = 'OR'
default = AND
def __init__(self, *args, **kwargs):
super(Q, self).__init__(children=list(args) + list(six.iteritems(kwargs)))
def _combine(self, other, conn):
if not isinstance(other, Q):
raise TypeError(other)
obj = type(self)()
obj.connector = conn
obj.add(self, conn)
obj.add(other, conn)
return obj
def __or__(self, other):
return self._combine(other, self.OR)
def __and__(self, other):
return self._combine(other, self.AND)
def __invert__(self):
obj = type(self)()
obj.add(self, self.AND)
obj.negate()
return obj
def clone(self):
clone = self.__class__._new_instance(
children=[], connector=self.connector, negated=self.negated)
for child in self.children:
if hasattr(child, 'clone'):
clone.children.append(child.clone())
else:
clone.children.append(child)
return clone
F objects 可以避免把 database 裡的資料抓到 Python memory 操作然後再存回去, 而是直接下 SQL 做操作
原本: (會把資料抓到 memory 做運算再存回去)
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed += 1
reporter.save()
使用 F objects: (直接下 SQL)
from django.db.models import F
reporter = Reporters.objects.get(name='Tintin')
reporter.stories_filed = F('stories_filed') + 1
reporter.save()
使用 Django 的 F() class 的時候, Python 不會知道裡面存的值是什麼, 而是產生操作的 SQL 交給 database, 操作完後 Python 裡的 value 不會更新, 如果要新的值的話要 reload :
reporter = Reporters.objects.get(pk=reporter.pk)
F() 也可以用在 update() 上, 前面的例子就變成:
from django.db.models import F
reporter = Reporters.objects.filter(name='Tintin')
reporter.update(stories_filed=F('stories_filed') + 1)
F() 也支援大量的 objects,
這樣直接下 SQL 操作
會比把資料從 database 抓到 Python,用 Python 跑過一遍修改,再存回去
來的快
ex:
Reporter.objects.all().update(stories_filed=F('stories_filed') + 1)
F() 也可以用於 filter
from django.db.models import F
Entry.objects.filter(n_comments__gt=F('n_pingbacks'))
Entry.objects.filter(n_comments__gt=F('n_pingbacks') * 2)
-
Operations Support
As well as addition, Django supports subtraction, multiplication, division, and modulo arithmetic with F() objects, using Python constants, variables, and even other F() objects.
Django 1.7 支援 power operator **
-
F() 的 Performance 優勢
-
讓 database 去操作,而不是 Python
-
降低一些情況的 query 數量
-
讓 database (而不是 Python) 處理 race condition
資料會是依照 SQL 執行時,database 裡的值來操作, 而不是先前抓到 Python 的 memory 的值, 當有多個 thread 的時候,race condition 就可以讓 database 處理掉, 而不是 Python 這邊另外處理
-