Opened 10 years ago

Last modified 18 months ago

#23034 new New feature

Add migrations support for adding ManyToMany "through" model

Reported by: lorinkoz@… Owned by:
Component: Migrations Version: dev
Severity: Normal Keywords:
Cc: carsten.fuchs@… Triage Stage: Accepted
Has patch: yes Needs documentation: no
Needs tests: no Patch needs improvement: yes
Easy pickings: no UI/UX: no

Description

Adding a "through" model on a ManyToMany field make "makemigrations" fail with an explicit error stating that it is not possible. I have worked it around by renaming the field, creating the migration (so as to make Django believe it's a new field) and then renaming the field back to the original name and creating another migration (which is correctly acknowledged by Django as a simple "renaming"). I understand the implications of adding a through model from the migrations perspective, but maybe a more friendly output could be achieved. Is it even possible to create some sort of interaction, like when you create a field with not null and no default value, so as to ask the user if they want to destroy/create a new field??

Change History (14)

comment:1 by Tim Graham, 10 years ago

Summary: Migrations fail with modified ManyToMany "through" modelAdd migrations support for adding ManyToMany "through" model
Triage Stage: UnreviewedAccepted
Type: UncategorizedNew feature

As Andrew noted in #22476, "as the error message says, you cannot alter an M2M without a through model into one with a through model, at least not in the current system." I'm not sure how feasible it will be to add support for thits, but tentatively accepting.

comment:2 by Andrew Godwin, 10 years ago

Triage Stage: AcceptedSomeday/Maybe

Triaging this to "someday/maybe". It would be nice, but it's a complex thing to add.

comment:3 by Marten Kenbeek, 9 years ago

Owner: changed from nobody to Marten Kenbeek
Status: newassigned
Triage Stage: Someday/MaybeAccepted
Version: 1.7-rc-1master

comment:5 by Marten Kenbeek, 9 years ago

Patch needs improvement: set

comment:6 by Marten Kenbeek, 9 years ago

Patch needs improvement: unset

comment:7 by Tim Graham, 9 years ago

Patch needs improvement: set

Markus reviewed the PR.

comment:8 by Carsten Fuchs, 9 years ago

Cc: carsten.fuchs@… added

comment:9 by Simon Charette, 6 years ago

FWIW a workaround for the current state of things, as long as through._meta.db_table points to the previously automatically generated db_table, is to wrap the generated operations in a SeparateDatabaseAndState.

comment:10 by Marten Kenbeek, 6 years ago

Owner: Marten Kenbeek removed
Status: assignednew

comment:11 by Simon Charette, 6 years ago

Owner: set to Simon Charette
Status: newassigned

comment:12 by Simon Charette, 5 years ago

Owner: Simon Charette removed
Status: assignednew

I'm not actively working on this ticket so I'll deassign myself but I made some progress by using a different approach.

My idea was to teach the auto-detector to detect ManyToMany(through) addition where through is a model compatible with the previously auto-created model. When it detected this case it would use the questioner to ask the user whether or not the previous table should be reused. On a "yes" a AddManyToManyThrough operation that has a noop database_forwards but an appropriate state_forwards to deal with the ModelState insertion would be added to the operations. If the new db_table wasn't matching or fields were added then the appropriate AlterModelTable and AddField operations would be added after the AddManyToManyThrough as well.

[CreateModel('Foo'), AddManyToManyThrough('Foo', 'bars', ManyToMany('Bar', through='FooBar')] could be optimized into
[CreateModel('Foo'), CreateModel('FooBar', fks), AddField('Foo', 'bars', ManyToMany('Bar', through='FooBar')] and the normal chain of optimizations could then take place.

The work so far is available on this branch

comment:13 by Carsten Agger, 5 years ago

As a developer bitten by this I'd like to second this motion: A customer changed their data model mid-project, and now we need to add fields to a many-to-many relationship & I'm looking at a) deleting all migrations and reinitializing the DB or b) make one of the workarounds here play without being too much of a hack.

I'd be grateful to be able to do this automatically one day, I think the use case is common enough.

comment:14 by Mariusz Felisiak, 18 months ago

As far as I'm aware, this transformation is too fragile to be automated (see https://youtu.be/4QF9UHEFPCY). It's also documented how to do this with SeparateDatabaseAndState().

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