Opened 5 years ago
Closed 5 years ago
#31343 closed Bug (duplicate)
Foreign key constraint to MTI child model is lost if the child model's parent was changed.
Reported by: | Antonis Christofides | Owned by: | nobody |
---|---|---|---|
Component: | Migrations | Version: | dev |
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
Steps to reproduce
- In a project using PostgreSQL, create an app
places
with the following models:from django.db import models class Place(models.Model): name = models.CharField(max_length=50) class Restaurant(Place): serves_hot_dogs = models.BooleanField(default=False) class MenuItem(models.Model): restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
- Run
./manage.py makemigrations
. It will create0001_initial.py
.
- Change the models to this:
from django.db import models class Place(models.Model): name = models.CharField(max_length=50) class CommercialPlace(Place): business_name = models.CharField(max_length=50) class Restaurant(CommercialPlace): serves_hot_dogs = models.BooleanField(default=False) class MenuItem(models.Model): restaurant = models.ForeignKey(Restaurant, on_delete=models.CASCADE)
The difference is that Restaurant
now inherits the new CommercialPlace
, whereas before it was directly inheriting Place
. The MenuItem
model is untouched.
- Execute
/.manage.py makemigrations
.
At this stage it will not know what to do ("You are trying to add a non-nullable field 'commercialplace_ptr' to restaurant without a default"). Select option 1 (provide a one-off default) and enter 0 as the default value.
(This doesn't make sense, but it doesn't matter. What should happen here is for commercialplace_ptr
to get the value place_ptr
previously had, but Django can't figure this out on its own, so the developer will need to write it in the migration. This has nothing to do with the bug, so in this example we can ignore this problem.)
Migration 0002_auto_something.py will be created as a result of this step.
- Execute
./manage.py sqlmigrate places 0002
.
Result
The sqlmigrate output contains, among other things, this:
ALTER TABLE "places_restaurant" DROP COLUMN "place_ptr_id" CASCADE;
As a result of the CASCADE, the foreign key constraint from MenuItem.restaurant
will be dropped. No constraint is created in its place.
Change History (1)
comment:1 by , 5 years ago
Resolution: | → duplicate |
---|---|
Status: | new → closed |
Summary: | Foreign key constraint to a multi-table inheritance child model is lost if the child model's parent is changed → Foreign key constraint to MTI child model is lost if the child model's parent was changed. |
Thanks for this ticket. I think it's another use case for
AlterModelBases
, see #23521. I was able to migrate this properly with the following operations: