#34881: Model-rename migration fails with IntegrityError if m2m relations to 
self
exist
-------------------------------+--------------------------------------
     Reporter:  dennisvang     |                    Owner:  nobody
         Type:  Bug            |                   Status:  new
    Component:  Uncategorized  |                  Version:  4.2
     Severity:  Normal         |               Resolution:
     Keywords:                 |             Triage Stage:  Unreviewed
    Has patch:  0              |      Needs documentation:  0
  Needs tests:  0              |  Patch needs improvement:  0
Easy pickings:  0              |                    UI/UX:  0
-------------------------------+--------------------------------------
Description changed by dennisvang:

Old description:

> == 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`
> 2. 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.

New description:

 == 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`
 2. 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.

--

-- 
Ticket URL: <https://code.djangoproject.com/ticket/34881#comment:5>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion on the web visit 
https://groups.google.com/d/msgid/django-updates/0107018adc6496fe-ccdfa5b1-8472-4036-832f-45ff0e51f518-000000%40eu-central-1.amazonses.com.

Reply via email to