2021-07-13 15:25:37 +08:00
|
|
|
|
=================================
|
|
|
|
|
How to create database migrations
|
|
|
|
|
=================================
|
2015-02-04 02:09:54 +08:00
|
|
|
|
|
|
|
|
|
This document explains how to structure and write database migrations for
|
|
|
|
|
different scenarios you might encounter. For introductory material on
|
|
|
|
|
migrations, see :doc:`the topic guide </topics/migrations>`.
|
|
|
|
|
|
|
|
|
|
.. _data-migrations-and-multiple-databases:
|
|
|
|
|
|
|
|
|
|
Data migrations and multiple databases
|
2016-01-03 18:56:22 +08:00
|
|
|
|
======================================
|
2015-02-04 02:09:54 +08:00
|
|
|
|
|
|
|
|
|
When using multiple databases, you may need to figure out whether or not to
|
|
|
|
|
run a migration against a particular database. For example, you may want to
|
|
|
|
|
**only** run a migration on a particular database.
|
|
|
|
|
|
|
|
|
|
In order to do that you can check the database connection's alias inside a
|
|
|
|
|
``RunPython`` operation by looking at the ``schema_editor.connection.alias``
|
|
|
|
|
attribute::
|
|
|
|
|
|
|
|
|
|
from django.db import migrations
|
|
|
|
|
|
|
|
|
|
def forwards(apps, schema_editor):
|
2017-07-26 21:34:10 +08:00
|
|
|
|
if schema_editor.connection.alias != 'default':
|
2015-02-04 02:09:54 +08:00
|
|
|
|
return
|
|
|
|
|
# Your migration code goes here
|
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
|
|
|
|
|
dependencies = [
|
|
|
|
|
# Dependencies to other migrations
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
operations = [
|
|
|
|
|
migrations.RunPython(forwards),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
You can also provide hints that will be passed to the :meth:`allow_migrate()`
|
|
|
|
|
method of database routers as ``**hints``:
|
|
|
|
|
|
2018-09-11 01:00:34 +08:00
|
|
|
|
.. code-block:: python
|
2022-05-31 13:40:54 +08:00
|
|
|
|
:caption: ``myapp/dbrouters.py``
|
2015-02-04 02:09:54 +08:00
|
|
|
|
|
2017-06-26 22:30:31 +08:00
|
|
|
|
class MyRouter:
|
2015-02-04 02:09:54 +08:00
|
|
|
|
|
2015-02-19 15:27:58 +08:00
|
|
|
|
def allow_migrate(self, db, app_label, model_name=None, **hints):
|
2015-02-04 02:09:54 +08:00
|
|
|
|
if 'target_db' in hints:
|
|
|
|
|
return db == hints['target_db']
|
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
Then, to leverage this in your migrations, do the following::
|
|
|
|
|
|
|
|
|
|
from django.db import migrations
|
|
|
|
|
|
|
|
|
|
def forwards(apps, schema_editor):
|
|
|
|
|
# Your migration code goes here
|
2015-05-13 20:19:51 +08:00
|
|
|
|
...
|
2015-02-04 02:09:54 +08:00
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
|
|
|
|
|
dependencies = [
|
|
|
|
|
# Dependencies to other migrations
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
operations = [
|
|
|
|
|
migrations.RunPython(forwards, hints={'target_db': 'default'}),
|
|
|
|
|
]
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2015-02-19 15:27:58 +08:00
|
|
|
|
If your ``RunPython`` or ``RunSQL`` operation only affects one model, it's good
|
|
|
|
|
practice to pass ``model_name`` as a hint to make it as transparent as possible
|
|
|
|
|
to the router. This is especially important for reusable and third-party apps.
|
|
|
|
|
|
2015-02-05 00:29:08 +08:00
|
|
|
|
Migrations that add unique fields
|
2016-01-03 18:56:22 +08:00
|
|
|
|
=================================
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
|
|
|
|
Applying a "plain" migration that adds a unique non-nullable field to a table
|
|
|
|
|
with existing rows will raise an error because the value used to populate
|
|
|
|
|
existing rows is generated only once, thus breaking the unique constraint.
|
|
|
|
|
|
|
|
|
|
Therefore, the following steps should be taken. In this example, we'll add a
|
|
|
|
|
non-nullable :class:`~django.db.models.UUIDField` with a default value. Modify
|
|
|
|
|
the respective field according to your needs.
|
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
* Add the field on your model with ``default=uuid.uuid4`` and ``unique=True``
|
|
|
|
|
arguments (choose an appropriate default for the type of the field you're
|
|
|
|
|
adding).
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
* Run the :djadmin:`makemigrations` command. This should generate a migration
|
|
|
|
|
with an ``AddField`` operation.
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
* Generate two empty migration files for the same app by running
|
|
|
|
|
``makemigrations myapp --empty`` twice. We've renamed the migration files to
|
|
|
|
|
give them meaningful names in the examples below.
|
|
|
|
|
|
|
|
|
|
* Copy the ``AddField`` operation from the auto-generated migration (the first
|
2017-03-28 02:07:11 +08:00
|
|
|
|
of the three new files) to the last migration, change ``AddField`` to
|
|
|
|
|
``AlterField``, and add imports of ``uuid`` and ``models``. For example:
|
2015-05-13 20:19:51 +08:00
|
|
|
|
|
2018-09-11 01:00:34 +08:00
|
|
|
|
.. code-block:: python
|
2022-05-31 13:40:54 +08:00
|
|
|
|
:caption: ``0006_remove_uuid_null.py``
|
2015-05-13 20:19:51 +08:00
|
|
|
|
|
2015-08-11 15:51:01 +08:00
|
|
|
|
# Generated by Django A.B on YYYY-MM-DD HH:MM
|
2015-05-13 20:19:51 +08:00
|
|
|
|
from django.db import migrations, models
|
|
|
|
|
import uuid
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
|
|
|
|
|
dependencies = [
|
2015-05-13 20:19:51 +08:00
|
|
|
|
('myapp', '0005_populate_uuid_values'),
|
2015-02-05 00:29:08 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
operations = [
|
2015-05-13 20:19:51 +08:00
|
|
|
|
migrations.AlterField(
|
2015-02-05 00:29:08 +08:00
|
|
|
|
model_name='mymodel',
|
|
|
|
|
name='uuid',
|
2015-05-13 20:19:51 +08:00
|
|
|
|
field=models.UUIDField(default=uuid.uuid4, unique=True),
|
2015-02-05 00:29:08 +08:00
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
* Edit the first migration file. The generated migration class should look
|
|
|
|
|
similar to this:
|
|
|
|
|
|
2018-09-11 01:00:34 +08:00
|
|
|
|
.. code-block:: python
|
2022-05-31 13:40:54 +08:00
|
|
|
|
:caption: ``0004_add_uuid_field.py``
|
2015-05-13 20:19:51 +08:00
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
|
|
|
|
|
dependencies = [
|
|
|
|
|
('myapp', '0003_auto_20150129_1705'),
|
|
|
|
|
]
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
operations = [
|
|
|
|
|
migrations.AddField(
|
|
|
|
|
model_name='mymodel',
|
|
|
|
|
name='uuid',
|
|
|
|
|
field=models.UUIDField(default=uuid.uuid4, unique=True),
|
|
|
|
|
),
|
|
|
|
|
]
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
Change ``unique=True`` to ``null=True`` -- this will create the intermediary
|
|
|
|
|
null field and defer creating the unique constraint until we've populated
|
|
|
|
|
unique values on all the rows.
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
* In the first empty migration file, add a
|
|
|
|
|
:class:`~django.db.migrations.operations.RunPython` or
|
|
|
|
|
:class:`~django.db.migrations.operations.RunSQL` operation to generate a
|
2017-03-28 02:07:11 +08:00
|
|
|
|
unique value (UUID in the example) for each existing row. Also add an import
|
|
|
|
|
of ``uuid``. For example:
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2018-09-11 01:00:34 +08:00
|
|
|
|
.. code-block:: python
|
2022-05-31 13:40:54 +08:00
|
|
|
|
:caption: ``0005_populate_uuid_values.py``
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
2015-08-11 15:51:01 +08:00
|
|
|
|
# Generated by Django A.B on YYYY-MM-DD HH:MM
|
2017-01-21 20:40:33 +08:00
|
|
|
|
from django.db import migrations
|
2015-02-05 00:29:08 +08:00
|
|
|
|
import uuid
|
|
|
|
|
|
|
|
|
|
def gen_uuid(apps, schema_editor):
|
|
|
|
|
MyModel = apps.get_model('myapp', 'MyModel')
|
|
|
|
|
for row in MyModel.objects.all():
|
|
|
|
|
row.uuid = uuid.uuid4()
|
2017-03-28 02:07:11 +08:00
|
|
|
|
row.save(update_fields=['uuid'])
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
|
|
|
|
|
dependencies = [
|
2015-05-13 20:19:51 +08:00
|
|
|
|
('myapp', '0004_add_uuid_field'),
|
2015-02-05 00:29:08 +08:00
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
operations = [
|
|
|
|
|
# omit reverse_code=... if you don't want the migration to be reversible.
|
|
|
|
|
migrations.RunPython(gen_uuid, reverse_code=migrations.RunPython.noop),
|
|
|
|
|
]
|
|
|
|
|
|
2015-05-13 20:19:51 +08:00
|
|
|
|
* Now you can apply the migrations as usual with the :djadmin:`migrate` command.
|
2015-02-05 00:29:08 +08:00
|
|
|
|
|
|
|
|
|
Note there is a race condition if you allow objects to be created while this
|
|
|
|
|
migration is running. Objects created after the ``AddField`` and before
|
|
|
|
|
``RunPython`` will have their original ``uuid``’s overwritten.
|
2015-06-04 23:54:06 +08:00
|
|
|
|
|
2016-01-31 04:46:28 +08:00
|
|
|
|
.. _non-atomic-migrations:
|
|
|
|
|
|
|
|
|
|
Non-atomic migrations
|
|
|
|
|
~~~~~~~~~~~~~~~~~~~~~
|
|
|
|
|
|
|
|
|
|
On databases that support DDL transactions (SQLite and PostgreSQL), migrations
|
|
|
|
|
will run inside a transaction by default. For use cases such as performing data
|
|
|
|
|
migrations on large tables, you may want to prevent a migration from running in
|
|
|
|
|
a transaction by setting the ``atomic`` attribute to ``False``::
|
|
|
|
|
|
|
|
|
|
from django.db import migrations
|
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
atomic = False
|
|
|
|
|
|
|
|
|
|
Within such a migration, all operations are run without a transaction. It's
|
|
|
|
|
possible to execute parts of the migration inside a transaction using
|
|
|
|
|
:func:`~django.db.transaction.atomic()` or by passing ``atomic=True`` to
|
|
|
|
|
``RunPython``.
|
|
|
|
|
|
|
|
|
|
Here's an example of a non-atomic data migration that updates a large table in
|
|
|
|
|
smaller batches::
|
|
|
|
|
|
|
|
|
|
import uuid
|
|
|
|
|
|
|
|
|
|
from django.db import migrations, transaction
|
|
|
|
|
|
|
|
|
|
def gen_uuid(apps, schema_editor):
|
|
|
|
|
MyModel = apps.get_model('myapp', 'MyModel')
|
|
|
|
|
while MyModel.objects.filter(uuid__isnull=True).exists():
|
|
|
|
|
with transaction.atomic():
|
|
|
|
|
for row in MyModel.objects.filter(uuid__isnull=True)[:1000]:
|
|
|
|
|
row.uuid = uuid.uuid4()
|
|
|
|
|
row.save()
|
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
atomic = False
|
|
|
|
|
|
|
|
|
|
operations = [
|
|
|
|
|
migrations.RunPython(gen_uuid),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
The ``atomic`` attribute doesn't have an effect on databases that don't support
|
2018-12-04 10:37:28 +08:00
|
|
|
|
DDL transactions (e.g. MySQL, Oracle). (MySQL's `atomic DDL statement support
|
|
|
|
|
<https://dev.mysql.com/doc/refman/en/atomic-ddl.html>`_ refers to individual
|
|
|
|
|
statements rather than multiple statements wrapped in a transaction that can be
|
|
|
|
|
rolled back.)
|
2016-01-31 04:46:28 +08:00
|
|
|
|
|
2015-06-04 23:54:06 +08:00
|
|
|
|
Controlling the order of migrations
|
2016-01-03 18:56:22 +08:00
|
|
|
|
===================================
|
2015-06-04 23:54:06 +08:00
|
|
|
|
|
|
|
|
|
Django determines the order in which migrations should be applied not by the
|
|
|
|
|
filename of each migration, but by building a graph using two properties on the
|
|
|
|
|
``Migration`` class: ``dependencies`` and ``run_before``.
|
|
|
|
|
|
|
|
|
|
If you've used the :djadmin:`makemigrations` command you've probably
|
|
|
|
|
already seen ``dependencies`` in action because auto-created
|
|
|
|
|
migrations have this defined as part of their creation process.
|
|
|
|
|
|
2015-07-01 15:16:17 +08:00
|
|
|
|
The ``dependencies`` property is declared like this::
|
2015-06-04 23:54:06 +08:00
|
|
|
|
|
|
|
|
|
from django.db import migrations
|
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
|
|
|
|
|
dependencies = [
|
|
|
|
|
('myapp', '0123_the_previous_migration'),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
Usually this will be enough, but from time to time you may need to
|
|
|
|
|
ensure that your migration runs *before* other migrations. This is
|
|
|
|
|
useful, for example, to make third-party apps' migrations run *after*
|
|
|
|
|
your :setting:`AUTH_USER_MODEL` replacement.
|
|
|
|
|
|
|
|
|
|
To achieve this, place all migrations that should depend on yours in
|
|
|
|
|
the ``run_before`` attribute on your ``Migration`` class::
|
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
...
|
|
|
|
|
|
|
|
|
|
run_before = [
|
|
|
|
|
('third_party_app', '0001_do_awesome'),
|
|
|
|
|
]
|
|
|
|
|
|
|
|
|
|
Prefer using ``dependencies`` over ``run_before`` when possible. You should
|
|
|
|
|
only use ``run_before`` if it is undesirable or impractical to specify
|
|
|
|
|
``dependencies`` in the migration which you want to run after the one you are
|
|
|
|
|
writing.
|
2016-04-03 23:20:35 +08:00
|
|
|
|
|
2016-04-06 23:04:56 +08:00
|
|
|
|
Migrating data between third-party apps
|
|
|
|
|
=======================================
|
2016-04-03 23:20:35 +08:00
|
|
|
|
|
2016-04-06 23:04:56 +08:00
|
|
|
|
You can use a data migration to move data from one third-party application to
|
|
|
|
|
another.
|
|
|
|
|
|
|
|
|
|
If you plan to remove the old app later, you'll need to set the ``dependencies``
|
|
|
|
|
property based on whether or not the old app is installed. Otherwise, you'll
|
|
|
|
|
have missing dependencies once you uninstall the old app. Similarly, you'll
|
|
|
|
|
need to catch :exc:`LookupError` in the ``apps.get_model()`` call that
|
|
|
|
|
retrieves models from the old app. This approach allows you to deploy your
|
|
|
|
|
project anywhere without first installing and then uninstalling the old app.
|
|
|
|
|
|
|
|
|
|
Here's a sample migration:
|
2016-04-03 23:20:35 +08:00
|
|
|
|
|
2018-09-11 01:00:34 +08:00
|
|
|
|
.. code-block:: python
|
2022-05-31 13:40:54 +08:00
|
|
|
|
:caption: ``myapp/migrations/0124_move_old_app_to_new_app.py``
|
2016-04-03 23:20:35 +08:00
|
|
|
|
|
|
|
|
|
from django.apps import apps as global_apps
|
|
|
|
|
from django.db import migrations
|
|
|
|
|
|
2016-04-06 23:04:56 +08:00
|
|
|
|
def forwards(apps, schema_editor):
|
|
|
|
|
try:
|
|
|
|
|
OldModel = apps.get_model('old_app', 'OldModel')
|
|
|
|
|
except LookupError:
|
|
|
|
|
# The old app isn't installed.
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
NewModel = apps.get_model('new_app', 'NewModel')
|
|
|
|
|
NewModel.objects.bulk_create(
|
|
|
|
|
NewModel(new_attribute=old_object.old_attribute)
|
|
|
|
|
for old_object in OldModel.objects.all()
|
|
|
|
|
)
|
2016-04-03 23:20:35 +08:00
|
|
|
|
|
|
|
|
|
class Migration(migrations.Migration):
|
|
|
|
|
operations = [
|
2016-04-06 23:04:56 +08:00
|
|
|
|
migrations.RunPython(forwards, migrations.RunPython.noop),
|
2016-04-03 23:20:35 +08:00
|
|
|
|
]
|
|
|
|
|
dependencies = [
|
|
|
|
|
('myapp', '0123_the_previous_migration'),
|
2016-04-06 23:04:56 +08:00
|
|
|
|
('new_app', '0001_initial'),
|
2016-04-03 23:20:35 +08:00
|
|
|
|
]
|
|
|
|
|
|
2016-04-06 23:04:56 +08:00
|
|
|
|
if global_apps.is_installed('old_app'):
|
|
|
|
|
dependencies.append(('old_app', '0001_initial'))
|
2016-04-03 23:20:35 +08:00
|
|
|
|
|
2016-04-06 23:04:56 +08:00
|
|
|
|
Also consider what you want to happen when the migration is unapplied. You
|
|
|
|
|
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
|
2016-04-03 23:20:35 +08:00
|
|
|
|
:mod:`~django.db.migrations.operations.RunPython` operation accordingly.
|
2016-08-24 05:35:42 +08:00
|
|
|
|
|
2020-03-04 01:51:39 +08:00
|
|
|
|
.. _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
|
2020-05-26 00:05:22 +08:00
|
|
|
|
table name while telling the migration autodetector that the new model has
|
2020-03-04 01:51:39 +08:00
|
|
|
|
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),
|
|
|
|
|
),
|
|
|
|
|
]
|
|
|
|
|
|
2016-08-24 05:35:42 +08:00
|
|
|
|
Changing an unmanaged model to managed
|
|
|
|
|
======================================
|
|
|
|
|
|
|
|
|
|
If you want to change an unmanaged model (:attr:`managed=False
|
|
|
|
|
<django.db.models.Options.managed>`) to managed, you must remove
|
|
|
|
|
``managed=False`` and generate a migration before making other schema-related
|
|
|
|
|
changes to the model, since schema changes that appear in the migration that
|
|
|
|
|
contains the operation to change ``Meta.managed`` may not be applied.
|