Browse Source

Improved docs on migration reversibility. (#12619)

- Clarify reversibility for RunSQL and RunPython operations.
- Add example for migrate with irreversible migration.

Co-authored-by: Carlton Gibson <carlton.gibson@noumenal.es>
Adam Johnson 5 years ago
parent
commit
b15b3706fe
2 changed files with 34 additions and 10 deletions
  1. 10 5
      docs/ref/migration-operations.txt
  2. 24 5
      docs/topics/migrations.txt

+ 10 - 5
docs/ref/migration-operations.txt

@@ -263,14 +263,18 @@ queries and parameters in the same way as :ref:`cursor.execute()
 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, so
-you can reverse the changes done in the forwards queries::
+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(
-        [("INSERT INTO musician (name) VALUES (%s);", ['Reinhardt'])],
-        [("DELETE FROM musician where name=%s;", ['Reinhardt'])],
+        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 is so you can 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``
@@ -317,7 +321,8 @@ instance of :class:`SchemaEditor
 
 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.
+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

+ 24 - 5
docs/topics/migrations.txt

@@ -347,11 +347,15 @@ Note that this only works given two things:
   that your database doesn't match your models, you'll just get errors when
   migrations try to modify those tables.
 
-Reverting migrations
+.. _reversing-migrations:
+
+Reversing migrations
 ====================
 
-Any migration can be reverted with :djadmin:`migrate` by using the number of
-previous migrations::
+Migrations can be reversed with :djadmin:`migrate` by passing the number of the
+previous migration. For example, to reverse migration ``books.0003``:
+
+.. console::
 
     $ python manage.py migrate books 0002
     Operations to perform:
@@ -360,8 +364,10 @@ previous migrations::
       Rendering model states... DONE
       Unapplying books.0003_auto... OK
 
-If you want to revert all migrations applied for an app, use the name
-``zero``::
+If you want to reverse all migrations applied for an app, use the name
+``zero``:
+
+.. console::
 
     $ python manage.py migrate books zero
     Operations to perform:
@@ -371,6 +377,19 @@ If you want to revert all migrations applied for an app, use the name
       Unapplying books.0002_auto... OK
       Unapplying books.0001_initial... OK
 
+A migration is irreversible if it contains any irreversible operations.
+Attempting to reverse such migrations will raise ``IrreversibleError``:
+
+.. console::
+
+    $ python manage.py migrate books 0002
+    Operations to perform:
+      Target specific migration: 0002_auto, from books
+    Running migrations:
+      Rendering model states... DONE
+      Unapplying books.0003_auto...Traceback (most recent call last):
+    django.db.migrations.exceptions.IrreversibleError: Operation <RunSQL  sql='DROP TABLE demo_books'> in books.0003_auto is not reversible
+
 .. _historical-models:
 
 Historical models