[Django] #37034: Improve writing migrations how-to add through field on a ManyToManyField

6 views
Skip to first unread message

Django

unread,
Apr 14, 2026, 6:47:19 AM (3 days ago) Apr 14
to django-...@googlegroups.com
#37034: Improve writing migrations how-to add through field on a ManyToManyField
-------------------------------------+-------------------------------------
Reporter: Clifford | Owner: Clifford Gama
Gama |
Type: Bug | Status: assigned
Component: | Version: dev
Documentation | Keywords: migrations,
Severity: Normal | ManyToManyField, through
Triage Stage: | Has patch: 0
Unreviewed |
Needs documentation: 0 | Needs tests: 0
Patch needs improvement: 0 | Easy pickings: 0
UI/UX: 0 |
-------------------------------------+-------------------------------------
1. Inaccurate description of how Django handles this change: The section
states that "the default migration will delete the existing table and
create a new one". This is not accurate. Django
[https://github.com/django/django/blob/d61f33f03b3177afdf1d76153014bad4107b1224/django/db/backends/base/schema.py#L894
refuses to apply a migration] when `through=` is added/changed on an
existing `ManyToManyField`.

2. The through model example does not accurately reflect the database: The
current example uses `on_delete=DO_NOTHING` and `models.UniqueConstraint`,
whereas Django's auto-generated through tables use `CASCADE` and
`unique_together`. In other words, future model states will not bear a
correct representation of what's in the db.

3. The example can be simplified by setting `Meta.db_table` on the new
through model to match the existing table name, eliminating the need for a
`RunSQL` rename operation.

The section also suggests using `sqlmigrate` or `dbshell` to find the
existing table name, which is indirect. The simplest approach is to
inspect `field.through._meta.db_table` before modifying the field.

Incidentally for the case where db_table remains the same, #36803 may
allow us to suggest a simpler alternative in the docs, one that does not
need to use `SeparateDatabaseAndState`.
--
Ticket URL: <https://code.djangoproject.com/ticket/37034>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

Django

unread,
Apr 14, 2026, 6:56:57 AM (3 days ago) Apr 14
to django-...@googlegroups.com
#37034: Improve writing migrations how-to add through field on a ManyToManyField
-------------------------------------+-------------------------------------
Reporter: Clifford Gama | Owner: Clifford
| Gama
Type: Bug | Status: assigned
Component: Documentation | Version: dev
Severity: Normal | Resolution:
Keywords: migrations, | Triage Stage:
ManyToManyField, through | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Sarah Boyce):

* cc: Adam Johnson (added)

Comment:

So from my understanding, this section of the docs was added to add an
example of using `SeperateDatabaseAndState` rather than showing the best
way to change a `ManyToManyField` to use a `through` model. See
https://github.com/django/django/pull/12523 for details.
So I suppose my question would be, do you have a better example for using
`SeperateDatabaseAndState`?
--
Ticket URL: <https://code.djangoproject.com/ticket/37034#comment:1>

Django

unread,
Apr 14, 2026, 8:12:07 AM (3 days ago) Apr 14
to django-...@googlegroups.com
#37034: Improve writing migrations how-to add through field on a ManyToManyField
-------------------------------------+-------------------------------------
Reporter: Clifford Gama | Owner: Clifford
| Gama
Type: Bug | Status: assigned
Component: Documentation | Version: dev
Severity: Normal | Resolution:
Keywords: migrations, | Triage Stage:
ManyToManyField, through | Unreviewed
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Comment (by Clifford Gama):

As a compromise between demonstrating how to use
`SeparateDatabaseAndState` and demonstrating how to migrate a m2m field's
through attribute correctly, I intend to keep the example and mention the
alternatives as part of the example. I will show open a PR in a day or so
to show what that'd look like.
--
Ticket URL: <https://code.djangoproject.com/ticket/37034#comment:2>

Django

unread,
Apr 15, 2026, 1:06:42 PM (2 days ago) Apr 15
to django-...@googlegroups.com
#37034: Improve writing migrations how-to add through field on a ManyToManyField
-------------------------------------+-------------------------------------
Reporter: Clifford Gama | Owner: Clifford
| Gama
Type: Bug | Status: assigned
Component: Documentation | Version: dev
Severity: Normal | Resolution:
Keywords: migrations, | Triage Stage: Accepted
ManyToManyField, through, |
SeparateDatabaseAndState |
Has patch: 0 | Needs documentation: 0
Needs tests: 0 | Patch needs improvement: 0
Easy pickings: 0 | UI/UX: 0
-------------------------------------+-------------------------------------
Changes (by Natalia Bidart):

* keywords: migrations, ManyToManyField, through => migrations,
ManyToManyField, through, SeparateDatabaseAndState
* stage: Unreviewed => Accepted

Comment:

Thank you for the ticket, Clifford. I agree that a more focused how-to is
the right direction. To keep each topic clear, I suggest splitting this
into two separate how-to guides: one for `SeparateDatabaseAndState`, and
another for migrating a m2m to use a `through` model.

These are distinct goals, and combining them makes the example harder to
follow and less accurate. This aligns better with the [https://diataxis.fr
/how-to-guides/ Diataxis definition of how-to guides as goal-oriented
instructions]:

> How-to guides are directions that guide the reader through a problem or
towards a result. How-to guides are goal-oriented.

Concretely, one guide would show a clean, representative use of
`SeparateDatabaseAndState` (maybe creating an index on a big table without
downtime? is there a DB primitive that Django does not support?), and the
other would demonstrate the correct way to migrate an M2M to a through
model without relying on it. Even if implemented in a single PR, keeping
the guides separate would improve clarity and avoid conflating the two
concerns.
--
Ticket URL: <https://code.djangoproject.com/ticket/37034#comment:3>
Reply all
Reply to author
Forward
0 new messages