简体   繁体   中英

Django IntegrityError changing a ForeignKey

I have a model LucyGuide which extends Django's User model through a OneToOneField :

class LucyGuide(models.Model):
    user = models.OneToOneField(User, on_delete=models.CASCADE)

There is also a Company model which has a field called lucy_guide which is a ForeignKey to the User model:

class Company(models.Model):
    lucy_guide = models.ForeignKey(User)

I'd like to change this to

class Company(models.Model):
    lucy_guide = models.ForeignKey(LucyGuide)

However, when I implement this change and make and run migrations, I run into an IntegrityError :

django.db.utils.IntegrityError: insert or update on table "lucy_web_company" violates foreign key constraint "lucy_web_company_lucy_guide_id_de643702_fk_lucy_web_"
DETAIL:  Key (lucy_guide_id)=(461) is not present in table "lucy_web_lucyguide".

This question is similar to IntegrityError Insert or update on table "orders_order" violates foreign key constraint " ; it seems like I have created LucyGuide objects before referencing them as foreign keys.

What is the best way to fix this? Is there a series of commands I need to write in the shell to create these users?

Update

From looking around in the shell, it seems like Django still expects the same numerical id s for the ForeignKey , even though the model has changed (from User to LucyGuide ). Here are the ids of User s which are also LucyGuide s:

In [11]: lucy_guide_users = [user for user in User.objects.all() if hasattr(user, 'lucyguide')]

In [16]: [user.id for user in lucy_guide_users]
Out[16]: [12, 8, 461, 497, 500, 471, 475, 495]

Notice that this contains the id of 461 from the error. The id s of LucyGuide s, however, are simply

In [17]: [guide.id for guide in LucyGuide.objects.all()]
Out[17]: [1, 2, 3, 4, 5, 6, 7, 8]

It seems like the way to fix this is to change the primary keys of the LucyGuide s, but it seems from What is the best approach to change primary keys in an existing Django app? that this is a very involved process. Is there a simpler way?

You can't simply change the target of the foreign key. For each existing company, you need to change lucy_guide_id from the related user's id to the related lucy_guide's id. Django can't do this for you.

You could do the migration in several steps. First, add a new foreign key and create a migration

class Company(models.Model):
    lucy_guide = models.ForeignKey(User)
    new_lucy_guide = models.ForeignKey(LucyGuide, blank=True, null=True)

Next, create a data migration to populate the new_lucy_guide field.

Then you can drop the lucy_guide field, and create a migration.

class Company(models.Model):
    new_lucy_guide = models.ForeignKey(LucyGuide, blank=True, null=True)

Finally you can rename your field and create a migration:

class Company(models.Model):
    lucy_guide = models.ForeignKey(LucyGuide, blank=True, null=True)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM