diff --git a/docs/howto/writing-migrations.txt b/docs/howto/writing-migrations.txt index 6ef6f6e74a2..02c39dff404 100644 --- a/docs/howto/writing-migrations.txt +++ b/docs/howto/writing-migrations.txt @@ -272,63 +272,55 @@ 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. -Migrating data when replacing an external app -============================================= +Migrating data between third-party apps +======================================= -If you plan to move from one external application to another one with a similar -data structure, you can use a data migration. If you plan to remove the old -application later, you will need to set the ``dependencies`` property -dynamically. Otherwise you will have missing dependencies once you uninstall -the old application. +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: .. snippet:: - :filename: myapp/migrations/0124_ensure_dependencies.py + :filename: myapp/migrations/0124_move_old_app_to_new_app.py from django.apps import apps as global_apps from django.db import migrations - def forward(apps, schema_editor): - """ - see below - """ - - class Migration(migrations.Migration): - - operations = [ - migrations.RunPython(forward, migrations.RunPython.noop), - ] - dependencies = [ - ('myapp', '0123_the_previous_migration'), - ('new_external_app', '0001_initial'), - ] - - if global_apps.is_installed('old_external_app'): - dependencies.append(('old_external_app', '0001_initial')) - -In your data migration method, you will need to test for the old application -model: - -.. snippet:: - :filename: myapp/migrations/0124_ensure_dependencies.py - - def forward(apps, schema_editor): + def forwards(apps, schema_editor): try: - OldModel = apps.get_model('old_external', 'OldModel') + OldModel = apps.get_model('old_app', 'OldModel') except LookupError: + # The old app isn't installed. return - NewModel = apps.get_model('new_external', 'NewModel') + 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() ) -This way you can deploy your application anywhere without first installing -and then uninstalling your old external dependency. If the old external -dependency is not installed when the migration runs it will just do nothing -instead of migrating the data. + class Migration(migrations.Migration): + operations = [ + migrations.RunPython(forwards, migrations.RunPython.noop), + ] + dependencies = [ + ('myapp', '0123_the_previous_migration'), + ('new_app', '0001_initial'), + ] -Please take also into consideration what you want to happen when the migration -is unapplied - you could either do nothing or remove some or all data from -the new application model; adjust the second argument of the + if global_apps.is_installed('old_app'): + dependencies.append(('old_app', '0001_initial')) + + + +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 :mod:`~django.db.migrations.operations.RunPython` operation accordingly.