Fixed #25492 -- Checked deferred foreign key constraints before dropping them.

This allows running foreign key data and schema altering operations in the
same migration on PostgreSQL.

Thanks Tim for review.
This commit is contained in:
Simon Charette 2016-12-17 15:06:47 -05:00
parent a4cac17200
commit cd7efa2033
2 changed files with 21 additions and 0 deletions

View File

@ -15,6 +15,10 @@ class DatabaseSchemaEditor(BaseDatabaseSchemaEditor):
sql_create_varchar_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s varchar_pattern_ops)%(extra)s" sql_create_varchar_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s varchar_pattern_ops)%(extra)s"
sql_create_text_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s text_pattern_ops)%(extra)s" sql_create_text_index = "CREATE INDEX %(name)s ON %(table)s (%(columns)s text_pattern_ops)%(extra)s"
# Setting the constraint to IMMEDIATE runs any deferred checks to allow
# dropping it in the same transaction.
sql_delete_fk = "SET CONSTRAINTS %(name)s IMMEDIATE; ALTER TABLE %(table)s DROP CONSTRAINT %(name)s"
def quote_value(self, value): def quote_value(self, value):
return psycopg2.extensions.adapt(value) return psycopg2.extensions.adapt(value)

View File

@ -532,6 +532,23 @@ class SchemaTests(TransactionTestCase):
with connection.schema_editor() as editor: with connection.schema_editor() as editor:
editor.alter_field(Note, old_field, new_field, strict=True) editor.alter_field(Note, old_field, new_field, strict=True)
@skipUnlessDBFeature('can_defer_constraint_checks', 'can_rollback_ddl')
def test_alter_fk_checks_deferred_constraints(self):
"""
#25492 - Altering a foreign key's structure and data in the same
transaction.
"""
with connection.schema_editor() as editor:
editor.create_model(Node)
old_field = Node._meta.get_field('parent')
new_field = ForeignKey(Node, CASCADE)
new_field.set_attributes_from_name('parent')
parent = Node.objects.create()
with connection.schema_editor() as editor:
# Update the parent FK to create a deferred constraint check.
Node.objects.update(parent=parent)
editor.alter_field(Node, old_field, new_field, strict=True)
def test_alter_text_field_to_date_field(self): def test_alter_text_field_to_date_field(self):
""" """
#25002 - Test conversion of text field to date field. #25002 - Test conversion of text field to date field.