diff --git a/django/db/backends/oracle/operations.py b/django/db/backends/oracle/operations.py index c44f2a9cee..493854ce04 100644 --- a/django/db/backends/oracle/operations.py +++ b/django/db/backends/oracle/operations.py @@ -6,7 +6,7 @@ from django.conf import settings from django.db.backends.base.operations import BaseDatabaseOperations from django.db.backends.utils import strip_quotes, truncate_name 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.utils import timezone 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 must be compared with True. """ - if isinstance(expression, Exists): - return True - if isinstance(expression, ExpressionWrapper) and isinstance(expression.expression, Q): + if isinstance(expression, (Exists, WhereNode)): 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: return True return False diff --git a/django/db/models/lookups.py b/django/db/models/lookups.py index 4b41906966..59e1b7211b 100644 --- a/django/db/models/lookups.py +++ b/django/db/models/lookups.py @@ -274,6 +274,20 @@ class Exact(FieldGetDbPrepValueMixin, BuiltinLookup): ) 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 class IExact(BuiltinLookup): diff --git a/django/db/models/sql/query.py b/django/db/models/sql/query.py index e6803649e7..f14859fda1 100644 --- a/django/db/models/sql/query.py +++ b/django/db/models/sql/query.py @@ -1222,12 +1222,7 @@ class Query(BaseExpression): if isinstance(filter_expr, dict): raise FieldError("Cannot parse keyword query as dict") 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 = 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) + condition = self.build_lookup(['exact'], filter_expr.resolve_expression(self), True) clause = self.where_class() clause.add(condition, AND) return clause, []