diff options
| author | Mariusz Felisiak <felisiak.mariusz@gmail.com> | 2025-10-18 15:03:50 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-10-18 15:03:50 +0200 |
| commit | 0c487aa3a7b2417481bf48c1e5355c855873e210 (patch) | |
| tree | 33b92a3bdf11f66d0f67fe4b4338084c7028c709 /tests/schema | |
| parent | b1e0262c9f9d11eae6230b51c5aa5d71122d5f05 (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.py | 96 |
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], |
