Opened 5 months ago
Closed 5 months ago
#35510 closed Bug (invalid)
migration on_delete=django.db.models.deletion.CASCADE does not create a ON DELETE CASCADE constraint
Reported by: | Daniel Ahern | Owned by: | nobody |
---|---|---|---|
Component: | Database layer (models, ORM) | Version: | 5.0 |
Severity: | Normal | Keywords: | |
Cc: | Triage Stage: | Unreviewed | |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description
Python 3.12.0 (using a conda environment)
Django 5.6
MariaDB/MySQL 8.0.30-0ubuntu0.22.04.1 (Ubuntu)
models.py:
from django.db import models # class TableBoolean(models.Model): # field1 = models.BooleanField(default=False) # class Meta: # db_table = 'test_boolean' class Parent(models.Model): name = models.CharField(max_length=100) def __str__(self): return self.name class Meta: db_table = 'test_parent' class Child(models.Model): parent = models.ForeignKey(Parent, on_delete=models.CASCADE) name = models.CharField(max_length=100) def __str__(self): return self.name class Meta: db_table = 'test_child'
Then I do:
python manage.py makemigrations v506
which makes:
# Generated by Django 5.0.6 on 2024-06-08 14:09 import django.db.models.deletion from django.db import migrations, models class Migration(migrations.Migration): initial = True dependencies = [ ] operations = [ migrations.CreateModel( name='Parent', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=100)), ], options={ 'db_table': 'test_parent', }, ), migrations.CreateModel( name='Child', fields=[ ('id', models.BigAutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')), ('name', models.CharField(max_length=100)), ('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='v506.parent')), ], options={ 'db_table': 'test_child', }, ), ]
Running the migration creates a table that does NOT cascade delete:
| test_child | CREATE TABLE `test_child` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `parent_id` bigint NOT NULL, PRIMARY KEY (`id`), KEY `test_child_parent_id_e1a9888d_fk_test_parent_id` (`parent_id`), CONSTRAINT `test_child_parent_id_e1a9888d_fk_test_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `test_parent` (`id`) )
Then I test by:
mysql> insert into test_parent(name) values ('test_parent'); mysql> insert into test_child (name, parent_id) values ('test_child', 1); mysql> delete from test_parent where id = 1; ERROR 1451 (23000): Cannot delete or update a parent row: a foreign key constraint fails (`django506`.`test_child`, CONSTRAINT `test_child_parent_id_e1a9888d_fk_test_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `test_parent` (`id`))
I am able to alter the table:
ALTER TABLE `test_child` DROP FOREIGN KEY `test_child_parent_id_e1a9888d_fk_test_parent_id`; ALTER TABLE `test_child` ADD CONSTRAINT `test_child_parent_id_e1a9888d_fk_test_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `test_parent` (`id`) ON DELETE CASCADE; mysql> show create table test_child; test_child | CREATE TABLE `test_child` ( `id` bigint NOT NULL AUTO_INCREMENT, `name` varchar(100) NOT NULL, `parent_id` bigint NOT NULL, PRIMARY KEY (`id`), KEY `test_child_parent_id_e1a9888d_fk_test_parent_id` (`parent_id`), CONSTRAINT `test_child_parent_id_e1a9888d_fk_test_parent_id` FOREIGN KEY (`parent_id`) REFERENCES `test_parent` (`id`) ON DELETE CASCADE mysql> delete from test_parent where id = 1; Query OK, 1 row affected (0.01 sec) mysql> select count(*) from test_child; +----------+ | count(*) | +----------+ | 0 | +----------+ 1 row in set (0.00 sec)
I would expect ON DELETE CASCADE to be on the table made by the migration because the migration has "on_delete=django.db.models.deletion.CASCADE" on the line:
('parent', models.ForeignKey(on_delete=django.db.models.deletion.CASCADE, to='v506.parent')),
Note:
See TracTickets
for help on using tickets.
As documented: When an object referenced by a ForeignKey is deleted, Django will emulate the behavior of the SQL constraint specified by the
on_delete
argument. ...on_delete
doesn’t create an SQL constraint in the database. Support for database-level cascade options may be implemented later.