123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660 |
- ====================
- Migration Operations
- ====================
- .. module:: django.db.migrations.operations
- Migration files are composed of one or more ``Operation``\s, objects that
- declaratively record what the migration should do to your database.
- Django also uses these ``Operation`` objects to work out what your models
- looked like historically, and to calculate what changes you've made to
- your models since the last migration so it can automatically write
- your migrations; that's why they're declarative, as it means Django can
- easily load them all into memory and run through them without touching
- the database to work out what your project should look like.
- There are also more specialized ``Operation`` objects which are for things like
- :ref:`data migrations <data-migrations>` and for advanced manual database
- manipulation. You can also write your own ``Operation`` classes if you want
- to encapsulate a custom change you commonly make.
- If you need an empty migration file to write your own ``Operation`` objects
- into, use ``python manage.py makemigrations --empty yourappname``, but be aware
- that manually adding schema-altering operations can confuse the migration
- autodetector and make resulting runs of :djadmin:`makemigrations` output
- incorrect code.
- All of the core Django operations are available from the
- ``django.db.migrations.operations`` module.
- For introductory material, see the :doc:`migrations topic guide
- </topics/migrations>`.
- Schema Operations
- =================
- ``CreateModel``
- ---------------
- .. class:: CreateModel(name, fields, options=None, bases=None, managers=None)
- Creates a new model in the project history and a corresponding table in the
- database to match it.
- ``name`` is the model name, as would be written in the ``models.py`` file.
- ``fields`` is a list of 2-tuples of ``(field_name, field_instance)``.
- The field instance should be an unbound field (so just
- ``models.CharField(...)``, rather than a field taken from another model).
- ``options`` is an optional dictionary of values from the model's ``Meta`` class.
- ``bases`` is an optional list of other classes to have this model inherit from;
- it can contain both class objects as well as strings in the format
- ``"appname.ModelName"`` if you want to depend on another model (so you inherit
- from the historical version). If it's not supplied, it defaults to inheriting
- from the standard ``models.Model``.
- ``managers`` takes a list of 2-tuples of ``(manager_name, manager_instance)``.
- The first manager in the list will be the default manager for this model during
- migrations.
- ``DeleteModel``
- ---------------
- .. class:: DeleteModel(name)
- Deletes the model from the project history and its table from the database.
- ``RenameModel``
- ---------------
- .. class:: RenameModel(old_name, new_name)
- Renames the model from an old name to a new one.
- You may have to manually add
- this if you change the model's name and quite a few of its fields at once; to
- the autodetector, this will look like you deleted a model with the old name
- and added a new one with a different name, and the migration it creates will
- lose any data in the old table.
- ``AlterModelTable``
- -------------------
- .. class:: AlterModelTable(name, table)
- Changes the model's table name (the :attr:`~django.db.models.Options.db_table`
- option on the ``Meta`` subclass).
- ``AlterModelTableComment``
- --------------------------
- .. class:: AlterModelTableComment(name, table_comment)
- Changes the model's table comment (the
- :attr:`~django.db.models.Options.db_table_comment` option on the ``Meta``
- subclass).
- ``AlterUniqueTogether``
- -----------------------
- .. class:: AlterUniqueTogether(name, unique_together)
- Changes the model's set of unique constraints (the
- :attr:`~django.db.models.Options.unique_together` option on the ``Meta``
- subclass).
- ``AlterIndexTogether``
- ----------------------
- .. class:: AlterIndexTogether(name, index_together)
- Changes the model's set of custom indexes (the ``index_together`` option on the
- ``Meta`` subclass).
- .. warning::
- ``AlterIndexTogether`` is officially supported only for pre-Django 4.2
- migration files. For backward compatibility reasons, it's still part of the
- public API, and there's no plan to deprecate or remove it, but it should
- not be used for new migrations. Use
- :class:`~django.db.migrations.operations.AddIndex` and
- :class:`~django.db.migrations.operations.RemoveIndex` operations instead.
- ``AlterOrderWithRespectTo``
- ---------------------------
- .. class:: AlterOrderWithRespectTo(name, order_with_respect_to)
- Makes or deletes the ``_order`` column needed for the
- :attr:`~django.db.models.Options.order_with_respect_to` option on the ``Meta``
- subclass.
- ``AlterModelOptions``
- ---------------------
- .. class:: AlterModelOptions(name, options)
- Stores changes to miscellaneous model options (settings on a model's ``Meta``)
- like ``permissions`` and ``verbose_name``. Does not affect the database, but
- persists these changes for :class:`RunPython` instances to use. ``options``
- should be a dictionary mapping option names to values.
- ``AlterModelManagers``
- ----------------------
- .. class:: AlterModelManagers(name, managers)
- Alters the managers that are available during migrations.
- ``AddField``
- ------------
- .. class:: AddField(model_name, name, field, preserve_default=True)
- Adds a field to a model. ``model_name`` is the model's name, ``name`` is
- the field's name, and ``field`` is an unbound Field instance (the thing
- you would put in the field declaration in ``models.py`` - for example,
- ``models.IntegerField(null=True)``.
- The ``preserve_default`` argument indicates whether the field's default
- value is permanent and should be baked into the project state (``True``),
- or if it is temporary and just for this migration (``False``) - usually
- because the migration is adding a non-nullable field to a table and needs
- a default value to put into existing rows. It does not affect the behavior
- of setting defaults in the database directly - Django never sets database
- defaults and always applies them in the Django ORM code.
- .. warning::
- On older databases, adding a field with a default value may cause a full
- rewrite of the table. This happens even for nullable fields and may have a
- negative performance impact. To avoid that, the following steps should be
- taken.
- * Add the nullable field without the default value and run the
- :djadmin:`makemigrations` command. This should generate a migration with
- an ``AddField`` operation.
- * Add the default value to your field and run the :djadmin:`makemigrations`
- command. This should generate a migration with an ``AlterField``
- operation.
- ``RemoveField``
- ---------------
- .. class:: RemoveField(model_name, name)
- Removes a field from a model.
- Bear in mind that when reversed, this is actually adding a field to a model.
- The operation is reversible (apart from any data loss, which is irreversible)
- if the field is nullable or if it has a default value that can be used to
- populate the recreated column. If the field is not nullable and does not have a
- default value, the operation is irreversible.
- .. admonition:: PostgreSQL
- ``RemoveField`` will also delete any additional database objects that are
- related to the removed field (like views, for example). This is because the
- resulting ``DROP COLUMN`` statement will include the ``CASCADE`` clause to
- ensure `dependent objects outside the table are also dropped`_.
- .. _dependent objects outside the table are also dropped: https://www.postgresql.org/docs/current/sql-altertable.html#SQL-ALTERTABLE-PARMS-CASCADE
- ``AlterField``
- --------------
- .. class:: AlterField(model_name, name, field, preserve_default=True)
- Alters a field's definition, including changes to its type,
- :attr:`~django.db.models.Field.null`, :attr:`~django.db.models.Field.unique`,
- :attr:`~django.db.models.Field.db_column` and other field attributes.
- The ``preserve_default`` argument indicates whether the field's default
- value is permanent and should be baked into the project state (``True``),
- or if it is temporary and just for this migration (``False``) - usually
- because the migration is altering a nullable field to a non-nullable one and
- needs a default value to put into existing rows. It does not affect the
- behavior of setting defaults in the database directly - Django never sets
- database defaults and always applies them in the Django ORM code.
- Note that not all changes are possible on all databases - for example, you
- cannot change a text-type field like ``models.TextField()`` into a number-type
- field like ``models.IntegerField()`` on most databases.
- ``RenameField``
- ---------------
- .. class:: RenameField(model_name, old_name, new_name)
- Changes a field's name (and, unless :attr:`~django.db.models.Field.db_column`
- is set, its column name).
- ``AddIndex``
- ------------
- .. class:: AddIndex(model_name, index)
- Creates an index in the database table for the model with ``model_name``.
- ``index`` is an instance of the :class:`~django.db.models.Index` class.
- ``RemoveIndex``
- ---------------
- .. class:: RemoveIndex(model_name, name)
- Removes the index named ``name`` from the model with ``model_name``.
- ``RenameIndex``
- ---------------
- .. class:: RenameIndex(model_name, new_name, old_name=None, old_fields=None)
- Renames an index in the database table for the model with ``model_name``.
- Exactly one of ``old_name`` and ``old_fields`` can be provided. ``old_fields``
- is an iterable of the strings, often corresponding to fields of
- ``index_together`` (pre-Django 5.1 option).
- On databases that don't support an index renaming statement (SQLite and MariaDB
- < 10.5.2), the operation will drop and recreate the index, which can be
- expensive.
- ``AddConstraint``
- -----------------
- .. class:: AddConstraint(model_name, constraint)
- Creates a :doc:`constraint </ref/models/constraints>` in the database table for
- the model with ``model_name``.
- ``RemoveConstraint``
- --------------------
- .. class:: RemoveConstraint(model_name, name)
- Removes the constraint named ``name`` from the model with ``model_name``.
- ``AlterConstraint``
- -------------------
- .. versionadded:: 5.2
- .. class:: AlterConstraint(model_name, name, constraint)
- Alters the constraint named ``name`` of the model with ``model_name`` with the
- new ``constraint`` without affecting the database.
- Special Operations
- ==================
- ``RunSQL``
- ----------
- .. class:: RunSQL(sql, reverse_sql=None, state_operations=None, hints=None, elidable=False)
- Allows running of arbitrary SQL on the database - useful for more advanced
- features of database backends that Django doesn't support directly.
- ``sql``, and ``reverse_sql`` if provided, should be strings of SQL to run on
- the database. On most database backends (all but PostgreSQL), Django will
- split the SQL into individual statements prior to executing them.
- .. warning::
- On PostgreSQL and SQLite, only use ``BEGIN`` or ``COMMIT`` in your SQL in
- :ref:`non-atomic migrations <non-atomic-migrations>`, to avoid breaking
- Django's transaction state.
- You can also pass a list of strings or 2-tuples. The latter is used for passing
- queries and parameters in the same way as :ref:`cursor.execute()
- <executing-custom-sql>`. These three operations are equivalent::
- migrations.RunSQL("INSERT INTO musician (name) VALUES ('Reinhardt');")
- migrations.RunSQL([("INSERT INTO musician (name) VALUES ('Reinhardt');", None)])
- migrations.RunSQL([("INSERT INTO musician (name) VALUES (%s);", ["Reinhardt"])])
- If you want to include literal percent signs in the query, you have to double
- them if you are passing parameters.
- The ``reverse_sql`` queries are executed when the migration is unapplied. They
- should undo what is done by the ``sql`` queries. For example, to undo the above
- insertion with a deletion::
- migrations.RunSQL(
- sql=[("INSERT INTO musician (name) VALUES (%s);", ["Reinhardt"])],
- reverse_sql=[("DELETE FROM musician where name=%s;", ["Reinhardt"])],
- )
- If ``reverse_sql`` is ``None`` (the default), the ``RunSQL`` operation is
- irreversible.
- The ``state_operations`` argument allows you to supply operations that are
- equivalent to the SQL in terms of project state. For example, if you are
- manually creating a column, you should pass in a list containing an ``AddField``
- operation here so that the autodetector still has an up-to-date state of the
- model. If you don't, when you next run ``makemigrations``, it won't see any
- operation that adds that field and so will try to run it again. For example::
- migrations.RunSQL(
- "ALTER TABLE musician ADD COLUMN name varchar(255) NOT NULL;",
- state_operations=[
- migrations.AddField(
- "musician",
- "name",
- models.CharField(max_length=255),
- ),
- ],
- )
- The optional ``hints`` argument will be passed as ``**hints`` to the
- :meth:`allow_migrate` method of database routers to assist them in making
- routing decisions. See :ref:`topics-db-multi-db-hints` for more details on
- database hints.
- The optional ``elidable`` argument determines whether or not the operation will
- be removed (elided) when :ref:`squashing migrations <migration-squashing>`.
- .. attribute:: RunSQL.noop
- Pass the ``RunSQL.noop`` attribute to ``sql`` or ``reverse_sql`` when you
- want the operation not to do anything in the given direction. This is
- especially useful in making the operation reversible.
- ``RunPython``
- -------------
- .. class:: RunPython(code, reverse_code=None, atomic=None, hints=None, elidable=False)
- Runs custom Python code in a historical context. ``code`` (and ``reverse_code``
- if supplied) should be callable objects that accept two arguments; the first is
- an instance of ``django.apps.registry.Apps`` containing historical models that
- match the operation's place in the project history, and the second is an
- instance of :class:`SchemaEditor
- <django.db.backends.base.schema.BaseDatabaseSchemaEditor>`.
- The ``reverse_code`` argument is called when unapplying migrations. This
- callable should undo what is done in the ``code`` callable so that the
- migration is reversible. If ``reverse_code`` is ``None`` (the default), the
- ``RunPython`` operation is irreversible.
- The optional ``hints`` argument will be passed as ``**hints`` to the
- :meth:`allow_migrate` method of database routers to assist them in making a
- routing decision. See :ref:`topics-db-multi-db-hints` for more details on
- database hints.
- The optional ``elidable`` argument determines whether or not the operation will
- be removed (elided) when :ref:`squashing migrations <migration-squashing>`.
- You are advised to write the code as a separate function above the ``Migration``
- class in the migration file, and pass it to ``RunPython``. Here's an example of
- using ``RunPython`` to create some initial objects on a ``Country`` model::
- from django.db import migrations
- def forwards_func(apps, schema_editor):
- # We get the model from the versioned app registry;
- # if we directly import it, it'll be the wrong version
- Country = apps.get_model("myapp", "Country")
- db_alias = schema_editor.connection.alias
- Country.objects.using(db_alias).bulk_create(
- [
- Country(name="USA", code="us"),
- Country(name="France", code="fr"),
- ]
- )
- def reverse_func(apps, schema_editor):
- # forwards_func() creates two Country instances,
- # so reverse_func() should delete them.
- Country = apps.get_model("myapp", "Country")
- db_alias = schema_editor.connection.alias
- Country.objects.using(db_alias).filter(name="USA", code="us").delete()
- Country.objects.using(db_alias).filter(name="France", code="fr").delete()
- class Migration(migrations.Migration):
- dependencies = []
- operations = [
- migrations.RunPython(forwards_func, reverse_func),
- ]
- This is generally the operation you would use to create
- :ref:`data migrations <data-migrations>`, run
- custom data updates and alterations, and anything else you need access to an
- ORM and/or Python code for.
- Much like :class:`RunSQL`, ensure that if you change schema inside here you're
- either doing it outside the scope of the Django model system (e.g. triggers)
- or that you use :class:`SeparateDatabaseAndState` to add in operations that will
- reflect your changes to the model state - otherwise, the versioned ORM and
- the autodetector will stop working correctly.
- By default, ``RunPython`` will run its contents inside a transaction on
- databases that do not support DDL transactions (for example, MySQL and
- Oracle). This should be safe, but may cause a crash if you attempt to use
- the ``schema_editor`` provided on these backends; in this case, pass
- ``atomic=False`` to the ``RunPython`` operation.
- On databases that do support DDL transactions (SQLite and PostgreSQL),
- ``RunPython`` operations do not have any transactions automatically added
- besides the transactions created for each migration. Thus, on PostgreSQL, for
- example, you should avoid combining schema changes and ``RunPython`` operations
- in the same migration or you may hit errors like ``OperationalError: cannot
- ALTER TABLE "mytable" because it has pending trigger events``.
- If you have a different database and aren't sure if it supports DDL
- transactions, check the ``django.db.connection.features.can_rollback_ddl``
- attribute.
- If the ``RunPython`` operation is part of a :ref:`non-atomic migration
- <non-atomic-migrations>`, the operation will only be executed in a transaction
- if ``atomic=True`` is passed to the ``RunPython`` operation.
- .. warning::
- ``RunPython`` does not magically alter the connection of the models for you;
- any model methods you call will go to the default database unless you
- give them the current database alias (available from
- ``schema_editor.connection.alias``, where ``schema_editor`` is the second
- argument to your function).
- .. staticmethod:: RunPython.noop
- Pass the ``RunPython.noop`` method to ``code`` or ``reverse_code`` when
- you want the operation not to do anything in the given direction. This is
- especially useful in making the operation reversible.
- ``SeparateDatabaseAndState``
- ----------------------------
- .. class:: SeparateDatabaseAndState(database_operations=None, state_operations=None)
- A highly specialized operation that lets you mix and match the database
- (schema-changing) and state (autodetector-powering) aspects of operations.
- It accepts two lists of operations. When asked to apply state, it will use the
- ``state_operations`` list (this is a generalized version of :class:`RunSQL`'s
- ``state_operations`` argument). When asked to apply changes to the database, it
- will use the ``database_operations`` list.
- If the actual state of the database and Django's view of the state get out of
- sync, this can break the migration framework, even leading to data loss. It's
- worth exercising caution and checking your database and state operations
- carefully. You can use :djadmin:`sqlmigrate` and :djadmin:`dbshell` to check
- your database operations. You can use :djadmin:`makemigrations`, especially
- with :option:`--dry-run<makemigrations --dry-run>`, to check your state
- operations.
- For an example using ``SeparateDatabaseAndState``, see
- :ref:`changing-a-manytomanyfield-to-use-a-through-model`.
- Operation category
- ==================
- .. versionadded:: 5.1
- .. currentmodule:: django.db.migrations.operations.base
- .. class:: OperationCategory
- Categories of migration operation used by the :djadmin:`makemigrations`
- command to display meaningful symbols.
- .. attribute:: ADDITION
- *Symbol*: ``+``
- .. attribute:: REMOVAL
- *Symbol*: ``-``
- .. attribute:: ALTERATION
- *Symbol*: ``~``
- .. attribute:: PYTHON
- *Symbol*: ``p``
- .. attribute:: SQL
- *Symbol*: ``s``
- .. attribute:: MIXED
- *Symbol*: ``?``
- .. _writing-your-own-migration-operation:
- Writing your own
- ================
- Operations have a relatively simple API, and they're designed so that you can
- easily write your own to supplement the built-in Django ones. The basic
- structure of an ``Operation`` looks like this::
- from django.db.migrations.operations.base import Operation
- class MyCustomOperation(Operation):
- # If this is False, it means that this operation will be ignored by
- # sqlmigrate; if true, it will be run and the SQL collected for its output.
- reduces_to_sql = False
- # If this is False, Django will refuse to reverse past this operation.
- reversible = False
- # This categorizes the operation. The corresponding symbol will be
- # displayed by the makemigrations command.
- category = OperationCategory.ADDITION
- def __init__(self, arg1, arg2):
- # Operations are usually instantiated with arguments in migration
- # files. Store the values of them on self for later use.
- pass
- def state_forwards(self, app_label, state):
- # The Operation should take the 'state' parameter (an instance of
- # django.db.migrations.state.ProjectState) and mutate it to match
- # any schema changes that have occurred.
- pass
- def database_forwards(self, app_label, schema_editor, from_state, to_state):
- # The Operation should use schema_editor to apply any changes it
- # wants to make to the database.
- pass
- def database_backwards(self, app_label, schema_editor, from_state, to_state):
- # If reversible is True, this is called when the operation is reversed.
- pass
- def describe(self):
- # This is used to describe what the operation does.
- return "Custom Operation"
- @property
- def migration_name_fragment(self):
- # Optional. A filename part suitable for automatically naming a
- # migration containing this operation, or None if not applicable.
- return "custom_operation_%s_%s" % (self.arg1, self.arg2)
- You can take this template and work from it, though we suggest looking at the
- built-in Django operations in ``django.db.migrations.operations`` - they cover
- a lot of the example usage of semi-internal aspects of the migration framework
- like ``ProjectState`` and the patterns used to get historical models, as well
- as ``ModelState`` and the patterns used to mutate historical models in
- ``state_forwards()``.
- Some things to note:
- * You don't need to learn too much about ``ProjectState`` to write migrations;
- just know that it has an ``apps`` property that gives access to an app
- registry (which you can then call ``get_model`` on).
- * ``database_forwards`` and ``database_backwards`` both get two states passed
- to them; these represent the difference the ``state_forwards`` method would
- have applied, but are given to you for convenience and speed reasons.
- * If you want to work with model classes or model instances from the
- ``from_state`` argument in ``database_forwards()`` or
- ``database_backwards()``, you must render model states using the
- ``clear_delayed_apps_cache()`` method to make related models available::
- def database_forwards(self, app_label, schema_editor, from_state, to_state):
- # This operation should have access to all models. Ensure that all models are
- # reloaded in case any are delayed.
- from_state.clear_delayed_apps_cache()
- ...
- * ``to_state`` in the database_backwards method is the *older* state; that is,
- the one that will be the current state once the migration has finished reversing.
- * You might see implementations of ``references_model`` on the built-in
- operations; this is part of the autodetection code and does not matter for
- custom operations.
- .. warning::
- For performance reasons, the :class:`~django.db.models.Field` instances in
- ``ModelState.fields`` are reused across migrations. You must never change
- the attributes on these instances. If you need to mutate a field in
- ``state_forwards()``, you must remove the old instance from
- ``ModelState.fields`` and add a new instance in its place. The same is true
- for the :class:`~django.db.models.Manager` instances in
- ``ModelState.managers``.
- As an example, let's make an operation that loads PostgreSQL extensions (which
- contain some of PostgreSQL's more exciting features). Since there's no model
- state changes, all it does is run one command::
- from django.db.migrations.operations.base import Operation
- class LoadExtension(Operation):
- reversible = True
- def __init__(self, name):
- self.name = name
- def state_forwards(self, app_label, state):
- pass
- def database_forwards(self, app_label, schema_editor, from_state, to_state):
- schema_editor.execute("CREATE EXTENSION IF NOT EXISTS %s" % self.name)
- def database_backwards(self, app_label, schema_editor, from_state, to_state):
- schema_editor.execute("DROP EXTENSION %s" % self.name)
- def describe(self):
- return "Creates extension %s" % self.name
- @property
- def migration_name_fragment(self):
- return "create_extension_%s" % self.name
|