summaryrefslogtreecommitdiff
path: root/django/db/models/sql/query.py
diff options
context:
space:
mode:
Diffstat (limited to 'django/db/models/sql/query.py')
-rw-r--r--django/db/models/sql/query.py73
1 files changed, 9 insertions, 64 deletions
diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py
index 6b50bb8bf6..719ef0f572 100644
--- a/django/db/models/sql/query.py
+++ b/django/db/models/sql/query.py
@@ -25,7 +25,7 @@ from django.db.models.sql.constants import (QUERY_TERMS, ORDER_DIR, SINGLE,
from django.db.models.sql.datastructures import (
EmptyResultSet, Empty, MultiJoin, Join, BaseTable)
from django.db.models.sql.where import (WhereNode, EverythingNode,
- ExtraWhere, AND, OR, EmptyWhere)
+ ExtraWhere, AND, OR, NothingNode)
from django.utils import six
from django.utils.deprecation import RemovedInDjango20Warning
from django.utils.encoding import force_text
@@ -141,7 +141,6 @@ class Query(object):
# - True: group by all select fields of the model
# See compiler.get_group_by() for details.
self.group_by = None
- self.having = where()
self.order_by = []
self.low_mark, self.high_mark = 0, None # Used for offset/limit
self.distinct = False
@@ -268,7 +267,6 @@ class Query(object):
obj.group_by = True
else:
obj.group_by = self.group_by[:]
- obj.having = self.having.clone()
obj.order_by = self.order_by[:]
obj.low_mark, obj.high_mark = self.low_mark, self.high_mark
obj.distinct = self.distinct
@@ -449,7 +447,7 @@ class Query(object):
return number
def has_filters(self):
- return self.where or self.having
+ return self.where
def has_results(self, using):
q = self.clone()
@@ -770,9 +768,8 @@ class Query(object):
else:
return col.relabeled_clone(change_map)
# 1. Update references in "select" (normal columns plus aliases),
- # "group by", "where" and "having".
+ # "group by" and "where".
self.where.relabel_aliases(change_map)
- self.having.relabel_aliases(change_map)
if isinstance(self.group_by, list):
self.group_by = [relabel_column(col) for col in self.group_by]
self.select = [col.relabeled_clone(change_map) for col in self.select]
@@ -1093,7 +1090,7 @@ class Query(object):
"""
Builds a WhereNode for a single filter clause, but doesn't add it
to this Query. Query.add_q() will then add this filter to the where
- or having Node.
+ Node.
The 'branch_negated' tells us if the current branch contains any
negations. This will be used to determine if subqueries are needed.
@@ -1197,59 +1194,11 @@ class Query(object):
def add_filter(self, filter_clause):
self.add_q(Q(**{filter_clause[0]: filter_clause[1]}))
- def need_having(self, obj):
- """
- Returns whether or not all elements of this q_object need to be put
- together in the HAVING clause.
- """
- if not self._annotations:
- return False
- if hasattr(obj, 'refs_aggregate'):
- return obj.refs_aggregate(self.annotations)[0]
- return (refs_aggregate(obj[0].split(LOOKUP_SEP), self.annotations)[0]
- or (hasattr(obj[1], 'refs_aggregate')
- and obj[1].refs_aggregate(self.annotations)[0]))
-
- def split_having_parts(self, q_object, negated=False):
- """
- Returns a list of q_objects which need to go into the having clause
- instead of the where clause. Removes the splitted out nodes from the
- given q_object. Note that the q_object is altered, so cloning it is
- needed.
- """
- having_parts = []
- for c in q_object.children[:]:
- # When constructing the having nodes we need to take care to
- # preserve the negation status from the upper parts of the tree
- if isinstance(c, Node):
- # For each negated child, flip the in_negated flag.
- in_negated = c.negated ^ negated
- if c.connector == OR and self.need_having(c):
- # A subtree starting from OR clause must go into having in
- # whole if any part of that tree references an aggregate.
- q_object.children.remove(c)
- having_parts.append(c)
- c.negated = in_negated
- else:
- having_parts.extend(
- self.split_having_parts(c, in_negated)[1])
- elif self.need_having(c):
- q_object.children.remove(c)
- new_q = self.where_class(children=[c], negated=negated)
- having_parts.append(new_q)
- return q_object, having_parts
-
def add_q(self, q_object):
"""
- A preprocessor for the internal _add_q(). Responsible for
- splitting the given q_object into where and having parts and
- setting up some internal variables.
+ A preprocessor for the internal _add_q(). Responsible for doing final
+ join promotion.
"""
- if not self.need_having(q_object):
- where_part, having_parts = q_object, []
- else:
- where_part, having_parts = self.split_having_parts(
- q_object.clone(), q_object.negated)
# For join promotion this case is doing an AND for the added q_object
# and existing conditions. So, any existing inner join forces the join
# type to remain inner. Existing outer joins can however be demoted.
@@ -1258,11 +1207,8 @@ class Query(object):
# So, demotion is OK.
existing_inner = set(
(a for a in self.alias_map if self.alias_map[a].join_type == INNER))
- clause, require_inner = self._add_q(where_part, self.used_aliases)
+ clause, require_inner = self._add_q(q_object, self.used_aliases)
self.where.add(clause, AND)
- for hp in having_parts:
- clause, _ = self._add_q(hp, self.used_aliases)
- self.having.add(clause, AND)
self.demote_joins(existing_inner)
def _add_q(self, q_object, used_aliases, branch_negated=False,
@@ -1557,11 +1503,10 @@ class Query(object):
return condition, needed_inner
def set_empty(self):
- self.where = EmptyWhere()
- self.having = EmptyWhere()
+ self.where.add(NothingNode(), AND)
def is_empty(self):
- return isinstance(self.where, EmptyWhere) or isinstance(self.having, EmptyWhere)
+ return any(isinstance(c, NothingNode) for c in self.where.children)
def set_limits(self, low=None, high=None):
"""