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 josephbiko)

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 josephbiko, 6 years ago

Owner: changed from nobody to josephbiko
Status: newassigned

comment:2 by josephbiko, 6 years ago

Owner: josephbiko removed
Status: assignednew

comment:3 by Simon Charette, 6 years ago

Component: UncategorizedMigrations
Resolution: needsinfo
Status: newclosed
Type: UncategorizedBug

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.fkshould be automatically repointed to B.a_ptr when A 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.

comment:4 by Simon Charette, 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 josephbiko, 6 years ago

Cc: josephbiko added
Description: modified (diff)
Resolution: needsinfo
Status: closednew

in reply to:  4 comment:6 by josephbiko, 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 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.

No there was no data present before

comment:7 by Tim Graham, 6 years ago

Summary: Django Foreign Key MismatchUnable to create model instance after changing an abstract model to non-abstract due to "foreign key mismatch" error
Triage Stage: UnreviewedAccepted

comment:8 by Bhuvnesh, 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.

Last edited 16 months ago by Bhuvnesh (previous) (diff)

comment:9 by Bhuvnesh, 17 months ago

Ok, so i have found the cause (the one above is incorrect):

  1. 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.e id .
  2. 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.
  3. Since c.fk still points to b.id (at physical level), it throws foreign_key_mismatch error.
  4. 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?

Last edited 17 months ago by Bhuvnesh (previous) (diff)

comment:10 by Bhuvnesh, 17 months ago

Owner: set to Bhuvnesh
Status: newassigned

comment:12 by Bhuvnesh, 14 months ago

Owner: Bhuvnesh removed
Status: assignednew
Note: See TracTickets for help on using tickets.
Back to Top