Commit b7ea494d authored by rixx's avatar rixx Committed by Russell Keith-Magee
Browse files

Fixed #24016 -- Added documentation about third-party app data migrations

There was confusion about how to migrate data from third-party

applications when you are going to uninstall the application later on.

Thanks to Markus, Marten and Sergei for help and review.
parent b0803d64
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -713,6 +713,7 @@ answer newbie questions, and generally made Django that much better:
    Tim Graham <timograham@gmail.com>
    Tim Heap <tim@timheap.me>
    Tim Saylor <tim.saylor@gmail.com>
    Tobias Kunze <rixx@cutebit.de>
    Tobias McNulty <http://www.caktusgroup.com/blog>
    tobias@neuyork.de
    Todd O'Bryan <toddobryan@mac.com>
+61 −0
Original line number Diff line number Diff line
@@ -271,3 +271,64 @@ Prefer using ``dependencies`` over ``run_before`` when possible. You should
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
=============================================

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.

.. snippet::
    :filename: myapp/migrations/0124_ensure_dependencies.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):
        try:
            OldModel = apps.get_model('old_external', 'OldModel')
        except LookupError:
            return

        NewModel = apps.get_model('new_external', '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.

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
:mod:`~django.db.migrations.operations.RunPython` operation accordingly.