Opened 7 years ago

Closed 23 months ago

#28987 closed Bug (fixed)

Migration changing ManyToManyField target to 'self' doesn't work correctly

Reported by: MSleepyPanda Owned by: Bhuvnesh
Component: Migrations Version: 2.0
Severity: Normal Keywords: ManyToManyField
Cc: 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

Steps to reproduce:
Create Models:

class Bar(models.Model):
    pass

class Foo(models.Model):
    bar = models.ManyToManyField('Bar', blank=True)

Migrate:

./manage.py makemigrations app
./manage.py migrate

Change type of the ManyToManyField to Foo:

class Bar(models.Model):
    pass

class Foo(models.Model):
    bar = models.ManyToManyField('Foo', blank=True)

Migrate (see above)

In the admin page, navigate to "add Foo", click save

You should see an OperationalError, "no such column: app_foo_bar.from_foo_id"

Change History (16)

comment:1 by Tim Graham, 7 years ago

Summary: makemigrations doesn't catch ManyToManyField type change, leaves DB in inconsistent stateMigration changing ManyToManyField target to 'self' doesn't work correctly
Triage Stage: UnreviewedAccepted

I believe it works correctly as long as the new target model isn't 'self'.

comment:2 by SShayashi, 7 years ago

Needs tests: set
Owner: changed from nobody to SShayashi
Status: newassigned

comment:3 by SShayashi, 7 years ago

Can I check out what you want? You can use 'self' instead of 'Foo' like this :

class Foo(models.Model):
    bar = models.ManyToManyField('self', blank=True)

You meant that we should use 'Foo' rather than 'self', right?

in reply to:  3 comment:4 by MSleepyPanda, 7 years ago

Replying to SShayashi:

Can I check out what you want? You can use 'self' instead of 'Foo' like this :

class Foo(models.Model):
    bar = models.ManyToManyField('self', blank=True)

You meant that we should use 'Foo' rather than 'self', right?

Exactly, though i wasn't aware that self would work in that context. I think i like naming the type directly more, since self could be easily confused with the self argument of class methods.

comment:5 by Mariusz Felisiak, 4 years ago

Needs tests: unset

comment:6 by Mariusz Felisiak, 4 years ago

Owner: SShayashi removed
Status: assignednew

comment:7 by Bhuvnesh, 23 months ago

Owner: set to Bhuvnesh
Status: newassigned

comment:8 by Bhuvnesh, 23 months ago

While altering a many to many field , a new table is created (which is later renamed) and data is copied from old table to new table and then old table is deleted. This issue caused while making this new table here, we are only altering the m2m_reverse_fields ignoring the m2m_fields that points to our model. But both m2m_reverse_fieldsand m2m_fields needs to be changed.
Hope i'm proceeding into the right direction.

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

comment:9 by Bhuvnesh, 23 months ago

It is also failing for the case if process is reversed, like when we migrate passing self/Foo to the m2m field and then change it to Bar.(due to the same reason that we are not altering m2m_fields)

Version 0, edited 23 months ago by Bhuvnesh (next)

comment:10 by Carlton Gibson, 23 months ago

Hi Bhuvnesh

I tried to alter self pointing field and with the changes below its working as expected for the above issue and passing all the tests as well.

If the tests are all passing it's worth opening a PR to make review easier. (Make sure to add a new test for the issue here too.)

Thanks.

comment:12 by Bhuvnesh, 23 months ago

Has patch: set

comment:13 by Mariusz Felisiak, 23 months ago

Patch needs improvement: set

comment:14 by Bhuvnesh, 23 months ago

Patch needs improvement: unset

comment:15 by Mariusz Felisiak, 23 months ago

Triage Stage: AcceptedReady for checkin

comment:16 by Mariusz Felisiak <felisiak.mariusz@…>, 23 months ago

Resolution: fixed
Status: assignedclosed

In 81b1c16:

Fixed #28987 -- Fixed altering ManyToManyField when changing to self-referential.

Note: See TracTickets for help on using tickets.
Back to Top