1
0
mirror of https://github.com/django/django.git synced 2025-10-24 14:16:09 +00:00

Clarified SeparateDatabaseAndState docs and added example of changing ManyToManyField.

Co-Authored-By: Mariusz Felisiak <felisiak.mariusz@gmail.com>
Co-Authored-By: Carlton Gibson <carlton.gibson@noumenal.es>
Co-Authored-By: René Fleschenberg <rene@fleschenberg.net>
This commit is contained in:
Adam Johnson
2020-03-03 17:51:39 +00:00
committed by Mariusz Felisiak
parent a2f554249e
commit a9ee6872bd
2 changed files with 102 additions and 4 deletions

View File

@@ -318,6 +318,92 @@ could either do nothing (as in the example above) or remove some or all of the
data from the new application. Adjust the second argument of the
:mod:`~django.db.migrations.operations.RunPython` operation accordingly.
.. _changing-a-manytomanyfield-to-use-a-through-model:
Changing a ``ManyToManyField`` to use a ``through`` model
=========================================================
If you change a :class:`~django.db.models.ManyToManyField` to use a ``through``
model, the default migration will delete the existing table and create a new
one, losing the existing relations. To avoid this, you can use
:class:`.SeparateDatabaseAndState` to rename the existing table to the new
table name whilst telling the migration autodetector that the new model has
been created. You can check the existing table name through
:djadmin:`sqlmigrate` or :djadmin:`dbshell`. You can check the new table name
with the through model's ``_meta.db_table`` property. Your new ``through``
model should use the same names for the ``ForeignKey``\s as Django did. Also if
it needs any extra fields, they should be added in operations after
:class:`.SeparateDatabaseAndState`.
For example, if we had a ``Book`` model with a ``ManyToManyField`` linking to
``Author``, we could add a through model ``AuthorBook`` with a new field
``is_primary``, like so::
from django.db import migrations, models
import django.db.models.deletion
class Migration(migrations.Migration):
dependencies = [
('core', '0001_initial'),
]
operations = [
migrations.SeparateDatabaseAndState(
database_operations=[
# Old table name from checking with sqlmigrate, new table
# name from AuthorBook._meta.db_table.
migrations.RunSQL(
sql='ALTER TABLE core_book_authors RENAME TO core_authorbook',
reverse_sql='ALTER TABLE core_authorbook RENAME TO core_book_authors',
),
],
state_operations=[
migrations.CreateModel(
name='AuthorBook',
fields=[
(
'id',
models.AutoField(
auto_created=True,
primary_key=True,
serialize=False,
verbose_name='ID',
),
),
(
'author',
models.ForeignKey(
on_delete=django.db.models.deletion.DO_NOTHING,
to='core.Author',
),
),
(
'book',
models.ForeignKey(
on_delete=django.db.models.deletion.DO_NOTHING,
to='core.Book',
),
),
],
),
migrations.AlterField(
model_name='book',
name='authors',
field=models.ManyToManyField(
to='core.Author',
through='core.AuthorBook',
),
),
],
),
migrations.AddField(
model_name='authorbook',
name='is_primary',
field=models.BooleanField(default=False),
),
]
Changing an unmanaged model to managed
======================================