Skip to content

Instantly share code, notes, and snippets.

@wdv4758h
Last active April 25, 2018 01:59
Show Gist options
  • Save wdv4758h/85cb83ecde3ccabfc145 to your computer and use it in GitHub Desktop.
Save wdv4758h/85cb83ecde3ccabfc145 to your computer and use it in GitHub Desktop.
django Q & F

Q objects

寫這篇的時候 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() expressions

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 這邊另外處理

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment