summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Godwin <andrew@aeracode.org>2014-08-09 17:50:00 +1000
committerAndrew Godwin <andrew@aeracode.org>2014-08-09 17:50:00 +1000
commit27b6f284353a7a477a1a0ae4beffd12003a91fb5 (patch)
treef567b0b1b95fdca1d1a589d3e6a8bf75fdc10bc9
parent8fe406864c5bbdd20e32d6127d377ed292006c5c (diff)
Fixed #23264: Schema backends honour db_constraint
-rw-r--r--django/db/backends/schema.py10
-rw-r--r--tests/schema/models.py9
-rw-r--r--tests/schema/tests.py93
3 files changed, 106 insertions, 6 deletions
diff --git a/django/db/backends/schema.py b/django/db/backends/schema.py
index 8bc9bfa432..db22dba8bb 100644
--- a/django/db/backends/schema.py
+++ b/django/db/backends/schema.py
@@ -228,7 +228,7 @@ class BaseDatabaseSchemaEditor(object):
}
)
# FK
- if field.rel:
+ if field.rel and field.db_constraint:
to_table = field.rel.to._meta.db_table
to_column = field.rel.to._meta.get_field(field.rel.field_name).column
if self.connection.features.supports_foreign_keys:
@@ -430,7 +430,7 @@ class BaseDatabaseSchemaEditor(object):
}
)
# Add any FK constraints later
- if field.rel and self.connection.features.supports_foreign_keys:
+ if field.rel and self.connection.features.supports_foreign_keys and field.db_constraint:
to_table = field.rel.to._meta.db_table
to_column = field.rel.to._meta.get_field(field.rel.field_name).column
self.deferred_sql.append(
@@ -530,7 +530,7 @@ class BaseDatabaseSchemaEditor(object):
)
# Drop any FK constraints, we'll remake them later
fks_dropped = set()
- if old_field.rel:
+ if old_field.rel and old_field.db_constraint:
fk_names = self._constraint_names(model, [old_field.column], foreign_key=True)
if strict and len(fk_names) != 1:
raise ValueError("Found wrong number (%s) of foreign key constraints for %s.%s" % (
@@ -739,7 +739,9 @@ class BaseDatabaseSchemaEditor(object):
}
)
# Does it have a foreign key?
- if new_field.rel and fks_dropped:
+ if new_field.rel and \
+ (fks_dropped or (old_field.rel and not old_field.db_constraint)) and \
+ new_field.db_constraint:
to_table = new_field.rel.to._meta.db_table
to_column = new_field.rel.get_related_field().column
self.execute(
diff --git a/tests/schema/models.py b/tests/schema/models.py
index c3d6593c99..ece07194b4 100644
--- a/tests/schema/models.py
+++ b/tests/schema/models.py
@@ -50,6 +50,15 @@ class Book(models.Model):
apps = new_apps
+class BookWeak(models.Model):
+ author = models.ForeignKey(Author, db_constraint=False)
+ title = models.CharField(max_length=100, db_index=True)
+ pub_date = models.DateTimeField()
+
+ class Meta:
+ apps = new_apps
+
+
class BookWithM2M(models.Model):
author = models.ForeignKey(Author)
title = models.CharField(max_length=100, db_index=True)
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index 64726aff4e..4222510040 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -10,7 +10,7 @@ from django.db.transaction import atomic
from .models import (Author, AuthorWithM2M, Book, BookWithLongName,
BookWithSlug, BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename,
UniqueTest, Thing, TagThrough, BookWithM2MThrough, AuthorTag, AuthorWithM2MThrough,
- AuthorWithEvenLongerName)
+ AuthorWithEvenLongerName, BookWeak)
class SchemaTests(TransactionTestCase):
@@ -27,7 +27,8 @@ class SchemaTests(TransactionTestCase):
models = [
Author, AuthorWithM2M, Book, BookWithLongName, BookWithSlug,
BookWithM2M, Tag, TagIndexed, TagM2MTest, TagUniqueRename, UniqueTest,
- Thing, TagThrough, BookWithM2MThrough, AuthorWithEvenLongerName
+ Thing, TagThrough, BookWithM2MThrough, AuthorWithEvenLongerName,
+ BookWeak,
]
# Utility functions
@@ -150,6 +151,94 @@ class SchemaTests(TransactionTestCase):
else:
self.fail("No FK constraint for author_id found")
+ @unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
+ def test_fk_db_constraint(self):
+ "Tests that the db_constraint parameter is respected"
+ # Create the table
+ with connection.schema_editor() as editor:
+ editor.create_model(Tag)
+ editor.create_model(Author)
+ editor.create_model(BookWeak)
+ # Check that initial tables are there
+ list(Author.objects.all())
+ list(Tag.objects.all())
+ list(BookWeak.objects.all())
+ # Check that BookWeak doesn't have an FK constraint
+ constraints = self.get_constraints(BookWeak._meta.db_table)
+ for name, details in constraints.items():
+ if details['columns'] == ["author_id"] and details['foreign_key']:
+ self.fail("FK constraint for author_id found")
+ # Make a db_constraint=False FK
+ new_field = ForeignKey(Tag, db_constraint=False)
+ new_field.set_attributes_from_name("tag")
+ with connection.schema_editor() as editor:
+ editor.add_field(
+ Author,
+ new_field,
+ )
+ # Make sure no FK constraint is present
+ constraints = self.get_constraints(Author._meta.db_table)
+ for name, details in constraints.items():
+ if details['columns'] == ["tag_id"] and details['foreign_key']:
+ self.fail("FK constraint for tag_id found")
+ # Alter to one with a constraint
+ new_field_2 = ForeignKey(Tag)
+ new_field_2.set_attributes_from_name("tag")
+ with connection.schema_editor() as editor:
+ editor.alter_field(
+ Author,
+ new_field,
+ new_field_2,
+ strict=True,
+ )
+ # Make sure the new FK constraint is present
+ constraints = self.get_constraints(Author._meta.db_table)
+ for name, details in constraints.items():
+ if details['columns'] == ["tag_id"] and details['foreign_key']:
+ self.assertEqual(details['foreign_key'], ('schema_tag', 'id'))
+ break
+ else:
+ self.fail("No FK constraint for tag_id found")
+ # Alter to one without a constraint again
+ new_field_2 = ForeignKey(Tag)
+ new_field_2.set_attributes_from_name("tag")
+ with connection.schema_editor() as editor:
+ editor.alter_field(
+ Author,
+ new_field_2,
+ new_field,
+ strict=True,
+ )
+ # Make sure no FK constraint is present
+ constraints = self.get_constraints(Author._meta.db_table)
+ for name, details in constraints.items():
+ if details['columns'] == ["tag_id"] and details['foreign_key']:
+ self.fail("FK constraint for tag_id found")
+
+ @unittest.skipUnless(connection.features.supports_foreign_keys, "No FK support")
+ def test_m2m_db_constraint(self):
+ # Create the table
+ with connection.schema_editor() as editor:
+ editor.create_model(Tag)
+ editor.create_model(Author)
+ # Check that initial tables are there
+ list(Author.objects.all())
+ list(Tag.objects.all())
+ # Make a db_constraint=False FK
+ new_field = ManyToManyField("schema.Tag", related_name="authors", db_constraint=False)
+ new_field.contribute_to_class(Author, "tags")
+ # Add the field
+ with connection.schema_editor() as editor:
+ editor.add_field(
+ Author,
+ new_field,
+ )
+ # Make sure no FK constraint is present
+ constraints = self.get_constraints(new_field.rel.through._meta.db_table)
+ for name, details in constraints.items():
+ if details['columns'] == ["tag_id"] and details['foreign_key']:
+ self.fail("FK constraint for tag_id found")
+
def test_add_field(self):
"""
Tests adding fields to models