Opened 9 months ago

Last modified 27 hours ago

#34881 closed Bug

Model-rename migration fails with IntegrityError if m2m relations to self exist — at Version 4

Reported by: dennisvang Owned by: nobody
Component: Migrations Version: dev
Severity: Normal Keywords: sqlite
Cc: Simon Charette, Mariusz Felisiak, David Wobrock, Jase Hackman Triage Stage: Ready for checkin
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: no
Easy pickings: no UI/UX: no

Description (last modified by dennisvang)

Description

Please consider the (contrived) minimal example below, part of an app called myapp:

class Person(models.Model):
    name = models.CharField(max_length=255)
    children = models.ManyToManyField(
        to='self', through='myapp.Relation', blank=True
    )


class Relation(models.Model):
    parent = models.ForeignKey(
        to='myapp.Person',
        related_name='relations_as_parent',
        on_delete=models.CASCADE,
    )
    child = models.ForeignKey(
        to='myapp.Person',
        related_name='relations_as_child',
        on_delete=models.CASCADE,
    )

Now suppose I rename the Person model to Foo and update corresponding references.

Then I run manage.py makemigrations, which correctly recognizes that the model has been renamed.

Now, applying this migration to an empty database works, without issue, but applying the migration to a database with existing data fails with an IntegrityError.

Steps to reproduce

  1. start a new project, start a new app called myapp, with models as above.
  2. run makemigrations and migrate
  3. Load (valid) data from the following fixture:
    [
      {"model": "myapp.person", "pk": 1, "fields": {"name": "Jenny"}}, 
      {"model": "myapp.person", "pk": 2, "fields": {"name": "Johnny"}}, 
      {"model": "myapp.person", "pk": 3, "fields": {"name": "Mom"}}, 
      {"model": "myapp.person", "pk": 4, "fields": {"name": "Dad"}}, 
      {"model": "myapp.relation", "pk": 1, "fields": {"parent": 3, "child": 1}},
      {"model": "myapp.relation", "pk": 2, "fields": {"parent": 3, "child": 2}},
      {"model": "myapp.relation", "pk": 3, "fields": {"parent": 4, "child": 1}}, 
      {"model": "myapp.relation", "pk": 4, "fields": {"parent": 4, "child": 2}}
    ]
    
  4. rename the Person model to e.g. Foo and update all references in code
  5. run makemigrations and migrate again

What happens

The migrate command fails with

django.db.utils.IntegrityError: The row in table 'myapp_relation' with primary key '1' has an invalid foreign key: myapp_relation.child_id contains a value '1' that does not have a corresponding value in myapp_person.id.

But a Person with id=1 does exist in the database.

What I would expect to happen

I would expect this to work without any problems.

Notes

I also tried the same steps with an *implicit* through model , i.e. children = models.ManyToManyField(to='self', blank=True).
This works without issue.

Change History (4)

comment:1 by dennisvang, 9 months ago

Summary: Migration fails with IntegrityError after renaming model with existing m2m relations to selfMigration fails with IntegrityError after renaming model if m2m relations to self exist

comment:2 by dennisvang, 9 months ago

Summary: Migration fails with IntegrityError after renaming model if m2m relations to self existModel rename fails during migration if m2m relations to self exist

comment:3 by dennisvang, 9 months ago

Summary: Model rename fails during migration if m2m relations to self existModel-rename migration fails with IntegrityError if m2m relations to self exist

comment:4 by dennisvang, 9 months ago

Description: modified (diff)
Note: See TracTickets for help on using tickets.
Back to Top