Complex queries with Q objects¶
The keyword argument queries in methods such as filter() are "ANDed" together. If you need to perform more complex queries (such as OR statements), you can use the Q object .
The Q object ( django.db.models.Q ) object is used to encapsulate a set of keyword arguments. These keyword arguments are the ones mentioned in "Field Queries" above.
For example, the following Q object encapsulates a LIKE query:
from django.db.models import Q Q(question__startswith='What')
Q objects can be combined using the & and | operators. When an operator is used on two Q objects, it produces a new Q object.
For example, the following statement produces a Q object representing the "OR" of two "question__startswith" queries:
Q(question__startswith='Who') | Q(question__startswith='What')
It is equivalent to the following SQL WHERE clause:
WHERE question LIKE 'Who%' OR question LIKE 'What%'
You can combine & and | operators and use parentheses for grouping to write arbitrarily complex Q objects. Also, Q objects can be negated using the ~ operator, which allows combining normal and negated ( NOT ) queries:
Q(question__startswith='Who') | ~Q(pub_date__year=2005)
Each query function that accepts keyword arguments (eg filter() , exclude() , get() ) can be passed one or more Q objects as positional (unnamed) arguments. If a query function has multiple Q object parameters, the logical relationship of these parameters is "AND". E.g:
Poll.objects.get( Q(question__startswith='Who'), Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)) )
... which roughly translates to this SQL:
SELECT * from polls WHERE question LIKE 'Who%'
AND (pub_date = '2005-05-02' OR pub_date = '2005-05-06')
Query functions can mix Q objects and keyword arguments. All arguments (keyword arguments or Q objects) supplied to the query function are "ANDed" together. However, if a Q object is present, it must precede all keyword arguments. E.g:
Poll.objects.get( Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)), question__startswith='Who')
... is a valid query, equivalent to the previous example; however:
# INVALID QUERY
Poll.objects.get( question__startswith='Who', Q(pub_date=date(2005, 5, 2)) | Q(pub_date=date(2005, 5, 6)))
... is not legal.
see also
The OR query example in Django unit tests demonstrates several uses of Q.
In the source code of Django's Q object implementation:
- # in /django/db/models/query_utils.py
- 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) + kwargs.items())
- def _combine(self, other, conn):
- if not isinstance(other, Q):
- raise TypeError(other)
- obj = type(self)()
- 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
Pass the Q object and construct the search condition
First you still need to import the module:
from django.db.models import Q
Pass in conditions to query:
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2)) q1.children.append(('id', 3)) models.Tb1.objects.filter(q1)
Combine conditions to query:
con = Q()
q1 = Q()
q1.connector = 'OR'
q1.children.append(('id', 1))
q1.children.append(('id', 2)) q1.children.append(('id', 3)) q2 = Q() q2.connector = 'OR' q2.children.append(('status', '在线')) con.add(q1, 'AND') con.add(q2, 'AND') models.Tb1.objects.filter(con)