1
0
mirror of https://github.com/django/django.git synced 2024-12-22 17:16:24 +00:00

Refs #25367 -- Moved conditional expression wrapping to the Exact lookup.

This commit is contained in:
Simon Charette 2019-11-14 23:28:34 -05:00 committed by Mariusz Felisiak
parent 306b687520
commit 37e6c5b79b
3 changed files with 19 additions and 10 deletions

View File

@ -6,7 +6,7 @@ from django.conf import settings
from django.db.backends.base.operations import BaseDatabaseOperations from django.db.backends.base.operations import BaseDatabaseOperations
from django.db.backends.utils import strip_quotes, truncate_name from django.db.backends.utils import strip_quotes, truncate_name
from django.db.models.expressions import Exists, ExpressionWrapper, RawSQL from django.db.models.expressions import Exists, ExpressionWrapper, RawSQL
from django.db.models.query_utils import Q from django.db.models.sql.where import WhereNode
from django.db.utils import DatabaseError from django.db.utils import DatabaseError
from django.utils import timezone from django.utils import timezone
from django.utils.encoding import force_bytes, force_str from django.utils.encoding import force_bytes, force_str
@ -633,10 +633,10 @@ END;
Oracle supports only EXISTS(...) or filters in the WHERE clause, others Oracle supports only EXISTS(...) or filters in the WHERE clause, others
must be compared with True. must be compared with True.
""" """
if isinstance(expression, Exists): if isinstance(expression, (Exists, WhereNode)):
return True
if isinstance(expression, ExpressionWrapper) and isinstance(expression.expression, Q):
return True return True
if isinstance(expression, ExpressionWrapper) and expression.conditional:
return self.conditional_expression_supported_in_where_clause(expression.expression)
if isinstance(expression, RawSQL) and expression.conditional: if isinstance(expression, RawSQL) and expression.conditional:
return True return True
return False return False

View File

@ -274,6 +274,20 @@ class Exact(FieldGetDbPrepValueMixin, BuiltinLookup):
) )
return super().process_rhs(compiler, connection) return super().process_rhs(compiler, connection)
def as_sql(self, compiler, connection):
# Avoid comparison against direct rhs if lhs is a boolean value. That
# turns "boolfield__exact=True" into "WHERE boolean_field" instead of
# "WHERE boolean_field = True" when allowed.
if (
isinstance(self.rhs, bool) and
getattr(self.lhs, 'conditional', False) and
connection.ops.conditional_expression_supported_in_where_clause(self.lhs)
):
lhs_sql, params = self.process_lhs(compiler, connection)
template = '%s' if self.rhs else 'NOT %s'
return template % lhs_sql, params
return super().as_sql(compiler, connection)
@Field.register_lookup @Field.register_lookup
class IExact(BuiltinLookup): class IExact(BuiltinLookup):

View File

@ -1222,12 +1222,7 @@ class Query(BaseExpression):
if isinstance(filter_expr, dict): if isinstance(filter_expr, dict):
raise FieldError("Cannot parse keyword query as dict") raise FieldError("Cannot parse keyword query as dict")
if hasattr(filter_expr, 'resolve_expression') and getattr(filter_expr, 'conditional', False): if hasattr(filter_expr, 'resolve_expression') and getattr(filter_expr, 'conditional', False):
if connections[DEFAULT_DB_ALIAS].ops.conditional_expression_supported_in_where_clause(filter_expr): condition = self.build_lookup(['exact'], filter_expr.resolve_expression(self), True)
condition = filter_expr.resolve_expression(self)
else:
# Expression is not supported in the WHERE clause, add
# comparison with True.
condition = self.build_lookup(['exact'], filter_expr.resolve_expression(self), True)
clause = self.where_class() clause = self.where_class()
clause.add(condition, AND) clause.add(condition, AND)
return clause, [] return clause, []