summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSimon Charette <charette.s@gmail.com>2019-03-16 13:48:59 -0400
committerMariusz Felisiak <felisiak.mariusz@gmail.com>2019-03-18 09:32:09 +0100
commit883d87074dd916224e2436ecc3dad8dd80e87c16 (patch)
tree6e78bc9a0c31b68afdb206cd896dd252b5821a78
parent2a92e2e3c12e5c4cad0ce2a2d5964675ef837fe7 (diff)
[2.2.x] Fixed #30258 -- Adjusted postgres schema value quoting of ranges.
Thanks Tilman Koschnick for the report and patch. Backport of 386d89ab55e620440d30590a8a104fe6d5eef830 from master
-rw-r--r--django/db/backends/postgresql/schema.py3
-rw-r--r--tests/postgres_tests/test_constraints.py35
2 files changed, 37 insertions, 1 deletions
diff --git a/django/db/backends/postgresql/schema.py b/django/db/backends/postgresql/schema.py
index 9eecaac19a..a81fd314e3 100644
--- a/django/db/backends/postgresql/schema.py
+++ b/django/db/backends/postgresql/schema.py
@@ -22,7 +22,8 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
sql_delete_procedure = 'DROP FUNCTION %(procedure)s(%(param_types)s)'
def quote_value(self, value):
- return psycopg2.extensions.adapt(value)
+ # getquoted() returns a quoted byte string of the adapted value.
+ return psycopg2.extensions.adapt(value).getquoted().decode()
def _field_indexes_sql(self, model, field):
output = super()._field_indexes_sql(model, field)
diff --git a/tests/postgres_tests/test_constraints.py b/tests/postgres_tests/test_constraints.py
new file mode 100644
index 0000000000..0e09a1c546
--- /dev/null
+++ b/tests/postgres_tests/test_constraints.py
@@ -0,0 +1,35 @@
+from django.db import connection, transaction
+from django.db.models import Q
+from django.db.models.constraints import CheckConstraint
+from django.db.utils import IntegrityError
+
+from . import PostgreSQLTestCase
+from .models import RangesModel
+
+try:
+ from psycopg2.extras import NumericRange
+except ImportError:
+ pass
+
+
+class SchemaTests(PostgreSQLTestCase):
+ def get_constraints(self, table):
+ """Get the constraints on the table using a new cursor."""
+ with connection.cursor() as cursor:
+ return connection.introspection.get_constraints(cursor, table)
+
+ def test_check_constraint_range_value(self):
+ constraint_name = 'ints_between'
+ self.assertNotIn(constraint_name, self.get_constraints(RangesModel._meta.db_table))
+ constraint = CheckConstraint(
+ check=Q(ints__contained_by=NumericRange(10, 30)),
+ name=constraint_name,
+ )
+ with connection.schema_editor() as editor:
+ editor.add_constraint(RangesModel, constraint)
+ with connection.cursor() as cursor:
+ constraints = connection.introspection.get_constraints(cursor, RangesModel._meta.db_table)
+ self.assertIn(constraint_name, constraints)
+ with self.assertRaises(IntegrityError), transaction.atomic():
+ RangesModel.objects.create(ints=(20, 50))
+ RangesModel.objects.create(ints=(10, 30))