summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Petrov <maximpetrov@yahoo.com>2020-08-19 05:22:12 +0300
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2020-08-19 06:43:54 +0200
commitbf6d07730c41ae23836d8dae98626fe8614307e2 (patch)
tree9abb04e5bd1631fdd6c58ef35a6d286627ec1289
parente2e34f4de3b90f3820ee11d49cc369ef573bc2ef (diff)
Fixed #31902 -- Fixed crash of ExclusionConstraint on expressions with params.
-rw-r--r--django/contrib/postgres/constraints.py9
-rw-r--r--tests/postgres_tests/test_constraints.py12
2 files changed, 17 insertions, 4 deletions
diff --git a/django/contrib/postgres/constraints.py b/django/contrib/postgres/constraints.py
index 2ae72c402e..12c185a777 100644
--- a/django/contrib/postgres/constraints.py
+++ b/django/contrib/postgres/constraints.py
@@ -66,20 +66,21 @@ class ExclusionConstraint(BaseConstraint):
self.opclasses = opclasses
super().__init__(name=name)
- def _get_expression_sql(self, compiler, connection, query):
+ def _get_expression_sql(self, compiler, schema_editor, query):
expressions = []
for idx, (expression, operator) in enumerate(self.expressions):
if isinstance(expression, str):
expression = F(expression)
expression = expression.resolve_expression(query=query)
- sql, params = expression.as_sql(compiler, connection)
+ sql, params = expression.as_sql(compiler, schema_editor.connection)
try:
opclass = self.opclasses[idx]
if opclass:
sql = '%s %s' % (sql, opclass)
except IndexError:
pass
- expressions.append('%s WITH %s' % (sql % params, operator))
+ sql = sql % tuple(schema_editor.quote_value(p) for p in params)
+ expressions.append('%s WITH %s' % (sql, operator))
return expressions
def _get_condition_sql(self, compiler, schema_editor, query):
@@ -92,7 +93,7 @@ class ExclusionConstraint(BaseConstraint):
def constraint_sql(self, model, schema_editor):
query = Query(model, alias_cols=False)
compiler = query.get_compiler(connection=schema_editor.connection)
- expressions = self._get_expression_sql(compiler, schema_editor.connection, query)
+ expressions = self._get_expression_sql(compiler, schema_editor, query)
condition = self._get_condition_sql(compiler, schema_editor, query)
include = [model._meta.get_field(field_name).column for field_name in self.include]
return self.template % {
diff --git a/tests/postgres_tests/test_constraints.py b/tests/postgres_tests/test_constraints.py
index 7d79e65239..89463650e8 100644
--- a/tests/postgres_tests/test_constraints.py
+++ b/tests/postgres_tests/test_constraints.py
@@ -7,6 +7,7 @@ from django.db import (
from django.db.models import (
CheckConstraint, Deferrable, F, Func, Q, UniqueConstraint,
)
+from django.db.models.functions import Left
from django.test import skipUnlessDBFeature
from django.utils import timezone
@@ -608,6 +609,17 @@ class ExclusionConstraintTests(PostgreSQLTestCase):
editor.remove_constraint(RangesModel, constraint)
self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
+ def test_expressions_with_params(self):
+ constraint_name = 'scene_left_equal'
+ self.assertNotIn(constraint_name, self.get_constraints(Scene._meta.db_table))
+ constraint = ExclusionConstraint(
+ name=constraint_name,
+ expressions=[(Left('scene', 4), RangeOperators.EQUAL)],
+ )
+ with connection.schema_editor() as editor:
+ editor.add_constraint(Scene, constraint)
+ self.assertIn(constraint_name, self.get_constraints(Scene._meta.db_table))
+
def test_range_adjacent_initially_deferred(self):
constraint_name = 'ints_adjacent_deferred'
self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))