mirror of https://github.com/django/django.git
[3.2.x] Fixed #32369 -- Fixed adding check constraints with pattern lookups and expressions as rhs.
This disables interpolation of constraint creation statements. Since
Constraint.create_sql interpolates its parameters instead of deferring
this responsibility to the backend connection it must disable
connection level parameters interpolation.
Backport of 42e8cf47c7
from master
This commit is contained in:
parent
5d9374b9fb
commit
9607e3a0cc
|
@ -360,6 +360,8 @@ class BaseDatabaseSchemaEditor:
|
||||||
not self.connection.features.supports_expression_indexes
|
not self.connection.features.supports_expression_indexes
|
||||||
):
|
):
|
||||||
return None
|
return None
|
||||||
|
# Index.create_sql returns interpolated SQL which makes params=None a
|
||||||
|
# necessity to avoid escaping attempts on execution.
|
||||||
self.execute(index.create_sql(model, self), params=None)
|
self.execute(index.create_sql(model, self), params=None)
|
||||||
|
|
||||||
def remove_index(self, model, index):
|
def remove_index(self, model, index):
|
||||||
|
@ -375,7 +377,9 @@ class BaseDatabaseSchemaEditor:
|
||||||
"""Add a constraint to a model."""
|
"""Add a constraint to a model."""
|
||||||
sql = constraint.create_sql(model, self)
|
sql = constraint.create_sql(model, self)
|
||||||
if sql:
|
if sql:
|
||||||
self.execute(sql)
|
# Constraint.create_sql returns interpolated SQL which makes
|
||||||
|
# params=None a necessity to avoid escaping attempts on execution.
|
||||||
|
self.execute(sql, params=None)
|
||||||
|
|
||||||
def remove_constraint(self, model, constraint):
|
def remove_constraint(self, model, constraint):
|
||||||
"""Remove a constraint from a model."""
|
"""Remove a constraint from a model."""
|
||||||
|
|
|
@ -2145,6 +2145,7 @@ class OperationTests(OperationTestBase):
|
||||||
fields=[
|
fields=[
|
||||||
('id', models.AutoField(primary_key=True)),
|
('id', models.AutoField(primary_key=True)),
|
||||||
('name', models.CharField(max_length=100)),
|
('name', models.CharField(max_length=100)),
|
||||||
|
('surname', models.CharField(max_length=100, default='')),
|
||||||
('rebate', models.CharField(max_length=100)),
|
('rebate', models.CharField(max_length=100)),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -2178,6 +2179,19 @@ class OperationTests(OperationTestBase):
|
||||||
Author.objects.create(name='Albert', rebate='10$')
|
Author.objects.create(name='Albert', rebate='10$')
|
||||||
author = Author.objects.create(name='Albert', rebate='10%')
|
author = Author.objects.create(name='Albert', rebate='10%')
|
||||||
self.assertEqual(Author.objects.get(), author)
|
self.assertEqual(Author.objects.get(), author)
|
||||||
|
# Right-hand-side baked "%" literals should not be used for parameters
|
||||||
|
# interpolation.
|
||||||
|
check = ~models.Q(surname__startswith=models.F('name'))
|
||||||
|
constraint = models.CheckConstraint(check=check, name='name_constraint_rhs')
|
||||||
|
operation = migrations.AddConstraint('Author', constraint)
|
||||||
|
from_state = to_state
|
||||||
|
to_state = from_state.clone()
|
||||||
|
operation.state_forwards(app_label, to_state)
|
||||||
|
with connection.schema_editor() as editor:
|
||||||
|
operation.database_forwards(app_label, editor, from_state, to_state)
|
||||||
|
Author = to_state.apps.get_model(app_label, 'Author')
|
||||||
|
with self.assertRaises(IntegrityError), transaction.atomic():
|
||||||
|
Author.objects.create(name='Albert', surname='Alberto')
|
||||||
|
|
||||||
@skipUnlessDBFeature('supports_table_check_constraints')
|
@skipUnlessDBFeature('supports_table_check_constraints')
|
||||||
def test_add_or_constraint(self):
|
def test_add_or_constraint(self):
|
||||||
|
|
Loading…
Reference in New Issue