Skip to content

Commit

Permalink
[1.7.x] Fixed #24052 -- Doc'd how to write data migrations with model…
Browse files Browse the repository at this point in the history
…s in multiple apps.

Backport of b089759 from master
  • Loading branch information
akulakov authored and timgraham committed Mar 13, 2015
1 parent 4e8b164 commit 9bb451a
Showing 1 changed file with 16 additions and 53 deletions.
69 changes: 16 additions & 53 deletions docs/topics/migrations.txt
Original file line number Diff line number Diff line change
Expand Up @@ -435,68 +435,31 @@ You can pass a second callable to
want executed when migrating backwards. If this callable is omitted, migrating
backwards will raise an exception.

.. _data-migrations-and-multiple-databases:
Accessing models from other apps
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Data migrations and multiple databases
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
When writing a ``RunPython`` function that uses models from apps other than the
one in which the migration is located, the migration's ``dependencies``
attribute should include the latest migration of each app that is involved,
otherwise you may get an error similar to: ``LookupError: No installed app
with label 'myappname'`` when you try to retrieve the model in the ``RunPython``
function using ``apps.get_model()``.

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):
if not schema_editor.connection.alias == 'default':
return
# Your migration code goes here

class Migration(migrations.Migration):

dependencies = [
# Dependencies to other migrations
]

operations = [
migrations.RunPython(forwards),
]

You can also use your database router's ``allow_migrate()`` method, but keep in
mind that the imported router needs to stay around as long as it is referenced
inside a migration:

.. snippet::
:filename: myapp/dbrouters.py

class MyRouter(object):

def allow_migrate(self, db, model):
return db == 'default'

Then, to leverage this in your migrations, do the following::

from django.db import migrations

from myappname.dbrouters import MyRouter

def forwards(apps, schema_editor):
MyModel = apps.get_model("myappname", "MyModel")
if not MyRouter().allow_migrate(schema_editor.connection.alias, MyModel):
return
# Your migration code goes here
In the following example, we have a migration in ``app1`` which needs to use
models in ``app2``. We aren't concerned with the details of ``move_m1`` other
than the fact it will need to access models from both apps. Therefore we've
added a dependency that specifies the last migration of ``app2``::

class Migration(migrations.Migration):

dependencies = [
# Dependencies to other migrations
('app1', '0001_initial'),
# added dependency to enable using models from app2 in move_m1
('app2', '0004_foobar'),
]

operations = [
migrations.RunPython(forwards),
migrations.RunPython(move_m1),
]

More advanced migrations
Expand Down

0 comments on commit 9bb451a

Please sign in to comment.