Opened 6 years ago
Last modified 14 months ago
#29574 new Bug
Unable to create model instance after changing an abstract model to non-abstract due to "foreign key mismatch" error
Reported by: | josephbiko | Owned by: | |
---|---|---|---|
Component: | Migrations | Version: | 2.1 |
Severity: | Normal | Keywords: | |
Cc: | josephbiko | Triage Stage: | Accepted |
Has patch: | no | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
Django Foreign key's do not track the models DB when the model is inherited from abstract class.
Steps to reproduce:
create models:"
class A(models.Model): field = models.IntegerField() class Meta: abstract = True class B(A): field2 = models.IntegerField() class C(models.Model): fk = models.ForeignKey(B,on_delete=models.CASCADE)
migrate
change the models (by removeing the meta )to:
class A(models.Model): field = models.IntegerField() class B(A): field2 = models.IntegerField() class C(models.Model): fk = models.ForeignKey(B,on_delete=models.CASCADE)
run migrations.
Now add an object of class B in the admin.
resulting error:
"foreign key mismatch - "models_c" referencing "models_b""
Change History (12)
comment:1 by , 6 years ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:2 by , 6 years ago
Owner: | removed |
---|---|
Status: | assigned → new |
comment:3 by , 6 years ago
Component: | Uncategorized → Migrations |
---|---|
Resolution: | → needsinfo |
Status: | new → closed |
Type: | Uncategorized → Bug |
follow-up: 6 comment:4 by , 6 years ago
Upon further inspection I assume you had an existing B
entry before attempting to run the migration that adds the B.a_ptr
primary key and it failed because no rows were present in the newly added A
table?
In this case I think you should be in charge of populating A
with a data migration (either using RunPython
or RunSQL
) instead of expecting Django to do it for you.
comment:5 by , 6 years ago
Cc: | added |
---|---|
Description: | modified (diff) |
Resolution: | needsinfo |
Status: | closed → new |
comment:6 by , 6 years ago
Replying to Simon Charette:
Upon further inspection I assume you had an existing
B
entry before attempting to run the migration that adds theB.a_ptr
primary key and it failed because no rows were present in the newly addedA
table?
In this case I think you should be in charge of populating
A
with a data migration (either usingRunPython
orRunSQL
) instead of expecting Django to do it for you.
No there was no data present before
comment:7 by , 6 years ago
Summary: | Django Foreign Key Mismatch → Unable to create model instance after changing an abstract model to non-abstract due to "foreign key mismatch" error |
---|---|
Triage Stage: | Unreviewed → Accepted |
Reproduced at 1e9b02a4c28142303fb4d33632e77ff7e26acb8b.
comment:8 by , 17 months ago
hi, i was working around to find the real cause of this issue and i am writing my observation here but i am not sure if they are fully correct or not, it would be really helpful if someone could cross-check/confirm.
1. when a_ptr
is created its a primary key hence has UNIQUE constraint.
2. since a_ptr
is a non nullable field it asks for a default value to populate the existing rows(even for empty db). And as we provide default value the UNIQUE constraint fails.
3. Now as UNIQUE constraints failed , it defies one of the rule of foreign key constraints given here (Under the heading Required and Suggested Database Indexes) which says The parent key columns named in the foreign key constraint are not the primary key of the parent table and are not subject to a unique constraint using collating sequence specified in the CREATE TABLE
. This subsequently leads to the "foreign key mismatch - "models_c" referencing "models_b""
error.
I'm using django dev version and its giving me error as soon as i migrate second time.
comment:9 by , 17 months ago
Ok, so i have found the cause (the one above is incorrect):
- When we run migration for the first time 2 db tables are created (B and C) , in which
C.fk
points to primary key of B i.eid
. - Now when we run second migration, table A is created and B is recreated with field
a_ptr
as primary key and all the old fields of B are deleted(evenid
). No changes for table C. - Since
c.fk
still points tob.id
(at physical level), it throwsforeign_key_mismatch
error. - If we explicity define primary key in model B everything works as expected.(temporary solution)
bid = models.IntegerField(primary_key=True)
Maybe a rough solution can be to recreate a model if new primary key is created and model contains a related field?
comment:10 by , 17 months ago
Owner: | set to |
---|---|
Status: | new → assigned |
comment:12 by , 14 months ago
Owner: | removed |
---|---|
Status: | assigned → new |
Hello josephbiko,
I assume you meant that running
makemigrations
between your two model scenarios doesn't generate the appropriate database alterations?There's a few bugs (#23521, #25247) related to switching from concrete to abstract inheritance but in the abstract to concrete case there shouldn't be any problem as
C.fk
should be automatically repointed toB.a_ptr
whenA
is made concrete.I'm afraid we'll need a more detailed reproduction test case in order to reproduce your issue. Please include tracebacks and detail every steps your perform to get there.