summaryrefslogtreecommitdiff
path: root/tests/schema
diff options
context:
space:
mode:
authorMariusz Felisiak <felisiak.mariusz@gmail.com>2025-10-18 15:03:50 +0200
committerGitHub <noreply@github.com>2025-10-18 15:03:50 +0200
commit0c487aa3a7b2417481bf48c1e5355c855873e210 (patch)
tree33b92a3bdf11f66d0f67fe4b4338084c7028c709 /tests/schema
parentb1e0262c9f9d11eae6230b51c5aa5d71122d5f05 (diff)
Fixed #21961 -- Added support for database-level delete options for ForeignKey.
Thanks Simon Charette for pair programming. Co-authored-by: Nick Stefan <NickStefan12@gmail.com> Co-authored-by: Akash Kumar Sen <71623442+Akash-Kumar-Sen@users.noreply.github.com> Co-authored-by: Simon Charette <charette.s@gmail.com>
Diffstat (limited to 'tests/schema')
-rw-r--r--tests/schema/tests.py96
1 files changed, 95 insertions, 1 deletions
diff --git a/tests/schema/tests.py b/tests/schema/tests.py
index 88d4ebbc8b..ab8b07e9d3 100644
--- a/tests/schema/tests.py
+++ b/tests/schema/tests.py
@@ -18,6 +18,8 @@ from django.db import (
from django.db.backends.utils import truncate_name
from django.db.models import (
CASCADE,
+ DB_CASCADE,
+ DB_SET_NULL,
PROTECT,
AutoField,
BigAutoField,
@@ -411,6 +413,40 @@ class SchemaTests(TransactionTestCase):
)
@skipUnlessDBFeature("can_create_inline_fk")
+ def test_inline_fk_db_on_delete(self):
+ with connection.schema_editor() as editor:
+ editor.create_model(Author)
+ editor.create_model(Book)
+ editor.create_model(Note)
+ self.assertForeignKeyNotExists(Note, "book_id", "schema_book")
+ # Add a foreign key from model to the other.
+ with (
+ CaptureQueriesContext(connection) as ctx,
+ connection.schema_editor() as editor,
+ ):
+ new_field = ForeignKey(Book, DB_CASCADE)
+ new_field.set_attributes_from_name("book")
+ editor.add_field(Note, new_field)
+ self.assertForeignKeyExists(Note, "book_id", "schema_book")
+ # Creating a FK field with a constraint uses a single statement without
+ # a deferred ALTER TABLE.
+ self.assertFalse(
+ [
+ sql
+ for sql in (str(statement) for statement in editor.deferred_sql)
+ if sql.startswith("ALTER TABLE") and "ADD CONSTRAINT" in sql
+ ]
+ )
+ # ON DELETE clause is used.
+ self.assertTrue(
+ any(
+ capture_query["sql"].startswith("ALTER TABLE")
+ and "ON DELETE" in capture_query["sql"]
+ for capture_query in ctx.captured_queries
+ )
+ )
+
+ @skipUnlessDBFeature("can_create_inline_fk")
def test_add_inline_fk_update_data(self):
with connection.schema_editor() as editor:
editor.create_model(Node)
@@ -566,6 +602,63 @@ class SchemaTests(TransactionTestCase):
editor.alter_field(Author, new_field2, new_field, strict=True)
self.assertForeignKeyNotExists(Author, "tag_id", "schema_tag")
+ @skipUnlessDBFeature("supports_foreign_keys", "can_introspect_foreign_keys")
+ def test_fk_alter_on_delete(self):
+ with connection.schema_editor() as editor:
+ editor.create_model(Author)
+ editor.create_model(Book)
+ self.assertForeignKeyExists(Book, "author_id", "schema_author")
+ # Change CASCADE to DB_CASCADE.
+ old_field = Book._meta.get_field("author")
+ new_field = ForeignKey(Author, DB_CASCADE)
+ new_field.set_attributes_from_name("author")
+ with (
+ connection.schema_editor() as editor,
+ CaptureQueriesContext(connection) as ctx,
+ ):
+ editor.alter_field(Book, old_field, new_field)
+ self.assertForeignKeyExists(Book, "author_id", "schema_author")
+ self.assertIs(
+ any("ON DELETE" in query["sql"] for query in ctx.captured_queries), True
+ )
+ # Change DB_CASCADE to CASCADE.
+ old_field = new_field
+ new_field = ForeignKey(Author, CASCADE)
+ new_field.set_attributes_from_name("author")
+ with (
+ connection.schema_editor() as editor,
+ CaptureQueriesContext(connection) as ctx,
+ ):
+ editor.alter_field(Book, old_field, new_field)
+ self.assertForeignKeyExists(Book, "author_id", "schema_author")
+ self.assertIs(
+ any("ON DELETE" in query["sql"] for query in ctx.captured_queries), False
+ )
+
+ @isolate_apps("schema")
+ @skipUnlessDBFeature("supports_foreign_keys", "can_introspect_foreign_keys")
+ def test_create_model_db_on_delete(self):
+ class Parent(Model):
+ class Meta:
+ app_label = "schema"
+
+ class Child(Model):
+ parent_fk = ForeignKey(Parent, DB_SET_NULL, null=True)
+
+ class Meta:
+ app_label = "schema"
+
+ with connection.schema_editor() as editor:
+ editor.create_model(Parent)
+ with CaptureQueriesContext(connection) as ctx:
+ with connection.schema_editor() as editor:
+ editor.create_model(Child)
+
+ self.assertForeignKeyNotExists(Child, "parent_id", "schema_parent")
+ self.assertIs(
+ any("ON DELETE" in query["sql"] for query in ctx.captured_queries), True
+ )
+
@isolate_apps("schema")
def test_no_db_constraint_added_during_primary_key_change(self):
"""
@@ -4598,6 +4691,7 @@ class SchemaTests(TransactionTestCase):
"to_table": editor.quote_name(table),
"to_column": editor.quote_name(model._meta.auto_field.column),
"deferrable": connection.ops.deferrable_sql(),
+ "on_delete_db": "",
}
)
self.assertIn(
@@ -4784,7 +4878,7 @@ class SchemaTests(TransactionTestCase):
error_messages={"invalid": "error message"},
help_text="help text",
limit_choices_to={"limit": "choice"},
- on_delete=PROTECT,
+ on_delete=CASCADE,
related_name="related_name",
related_query_name="related_query_name",
validators=[lambda x: x],