Browse Source

Refs #27149, #29542 -- Simplified subquery parentheses wrapping logic.

Simon Charette 6 years ago
parent
commit
3a505c70e7

+ 2 - 12
django/db/models/expressions.py

@@ -1023,23 +1023,13 @@ class Subquery(Expression):
     def as_sql(self, compiler, connection, template=None, **extra_context):
         connection.ops.check_expression_support(self)
         template_params = {**self.extra, **extra_context}
-        template_params['subquery'], sql_params = self.query.as_sql(compiler, connection)
+        subquery_sql, sql_params = self.query.as_sql(compiler, connection)
+        template_params['subquery'] = subquery_sql[1:-1]
 
         template = template or template_params.get('template', self.template)
         sql = template % template_params
         return sql, sql_params
 
-    def _prepare(self, output_field):
-        # This method will only be called if this instance is the "rhs" in an
-        # expression: the wrapping () must be removed (as the expression that
-        # contains this will provide them). SQLite evaluates ((subquery))
-        # differently than the other databases.
-        if self.template == '(%(subquery)s)':
-            clone = self.copy()
-            clone.template = '%(subquery)s'
-            return clone
-        return self
-
     def get_group_by_cols(self, alias=None):
         if alias:
             return [Ref(alias, self)]

+ 1 - 2
django/db/models/lookups.py

@@ -89,8 +89,7 @@ class Lookup:
             value = self.apply_bilateral_transforms(value)
             value = value.resolve_expression(compiler.query)
         if hasattr(value, 'as_sql'):
-            sql, params = compiler.compile(value)
-            return '(' + sql + ')', params
+            return compiler.compile(value)
         else:
             return self.get_db_prep_lookup(value, connection)
 

+ 1 - 6
django/db/models/sql/compiler.py

@@ -5,7 +5,7 @@ from itertools import chain
 
 from django.core.exceptions import EmptyResultSet, FieldError
 from django.db.models.constants import LOOKUP_SEP
-from django.db.models.expressions import OrderBy, Random, RawSQL, Ref, Subquery
+from django.db.models.expressions import OrderBy, Random, RawSQL, Ref
 from django.db.models.query_utils import QueryWrapper, select_related_descend
 from django.db.models.sql.constants import (
     CURSOR, GET_ITERATOR_CHUNK_SIZE, MULTI, NO_RESULTS, ORDER_DIR, SINGLE,
@@ -126,11 +126,6 @@ class SQLCompiler:
 
         for expr in expressions:
             sql, params = self.compile(expr)
-            if isinstance(expr, Subquery) and not sql.startswith('('):
-                # Subquery expression from HAVING clause may not contain
-                # wrapping () because they could be removed when a subquery is
-                # the "rhs" in an expression (see Subquery._prepare()).
-                sql = '(%s)' % sql
             if (sql, tuple(params)) not in seen:
                 result.append((sql, params))
                 seen.add((sql, tuple(params)))

+ 4 - 1
django/db/models/sql/query.py

@@ -1022,7 +1022,10 @@ class Query(BaseExpression):
         return clone
 
     def as_sql(self, compiler, connection):
-        return self.get_compiler(connection=connection).as_sql()
+        sql, params = self.get_compiler(connection=connection).as_sql()
+        if self.subquery:
+            sql = '(%s)' % sql
+        return sql, params
 
     def resolve_lookup_value(self, value, can_reuse, allow_joins, simple_col):
         if hasattr(value, 'resolve_expression'):