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
 If you want to include literal percent signs in the query, you have to double
 them if you are passing parameters.
 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(
     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
 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
 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``
 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
 The ``reverse_code`` argument is called when unapplying migrations. This
 callable should undo what is done in the ``code`` callable so that the
 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
 The optional ``hints`` argument will be passed as ``**hints`` to the
 :meth:`allow_migrate` method of database routers to assist them in making a
 :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
   that your database doesn't match your models, you'll just get errors when
   migrations try to modify those tables.
   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
     $ python manage.py migrate books 0002
     Operations to perform:
     Operations to perform:
@@ -360,8 +364,10 @@ previous migrations::
       Rendering model states... DONE
       Rendering model states... DONE
       Unapplying books.0003_auto... OK
       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
     $ python manage.py migrate books zero
     Operations to perform:
     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.0002_auto... OK
       Unapplying books.0001_initial... 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:
 
 
 Historical models
 Historical models