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.
This commit is contained in:
rixx 2016-04-03 17:20:35 +02:00 committed by Russell Keith-Magee
parent b0803d64c4
commit b7ea494d65
2 changed files with 62 additions and 0 deletions

View File

@ -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>

View File

@ -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.