Django 1.7: How to migrate data between two external apps

305 views
Skip to first unread message

John-Scott

unread,
Dec 13, 2014, 12:26:17 PM12/13/14
to django...@googlegroups.com
Say I decided to switch from a third party app foo-tags to app bar-tags. Their Tag models are mostly identical so I just need to move the data from foo-tag to bar-tag. Since I don't control their migrations, I'd need to create a migration in one of my own apps:

./manage.py makemigrations my_app --empty

In this migration I'd need to explicitly list the dependencies on these external apps (otherwise was getting errors that the foo and bar apps were not available in the app registry):

# -*- coding: utf-8 -*-
from __future__ import unicode_literals

from django.db import models, migrations

def migrate_tags(apps, schema_editor):
   
FooTag = apps.get_model('foo_tag', 'FooTag')
   
BarTag = apps.get_model('bar_tag', 'BarTag')
   
for old_tag in FooTag.objects.all():
        new_tag
= BarTag.objects.create(name=old_tag.name)

class Migration(migrations.Migration):
    dependencies
= [
       
('my_app', '0001_initial'),
       
('foo_tag', '0001_initial'),
       
('bar_tag', '0001_initial'),
   
]

    operations
= [
        migrations
.RunPython(migrate_tags)
   
]


The migration itself works as expected. However if I now remove foo_tag from INSTALLED_APPS, Django will now give an error:

KeyError: "Migration my_app.0002_auto_20141212_1951 dependencies reference nonexistent parent node ('foo_tag', '0001_initial')"

What's the correct way to handle migrating data between 3rd party apps where one of the apps is eventually removed?

Thanks,
John-Scott

Markus Holtermann

unread,
Dec 16, 2014, 9:05:35 AM12/16/14
to django...@googlegroups.com
Hey John-Scott,

I'm afraid but I don't see an obvious solution. There are 2 ways you could work on the issue, I don't like either:

1. remove all references to the "foo_tag" app from all migration files

2. make use of the MIGRATION_MODULES settings:

2.1. create a package "path.to.foo_tag_legacy"
2.2. inside create an empty migration "0001_initial"
2.3. define MIGRATION_MODULES={"foo_tag": "path.to.foo_tag_legacy"}

As said, both seem ugly to me. I don't know which way I'd proceed.

You might get it working by squashing migrations, but certainly not without manually writing those migration files.

/Markus

John-Scott

unread,
Dec 17, 2014, 12:01:05 AM12/17/14
to django...@googlegroups.com
My 'solution' was very smelly:
  • created the migration in 'my_app' as mentioned in my previous post
  • pushed this change to production to run
  • removed 'foo_tag' from INSTALLED_APPS *AND* deleted the migration file (which meant also manually deleting the history of this migration from the django_migrations table).
It was hard to hold my nose through this experience but it worked. Would be great to have a general solution that could be shared with others but in the meantime, I'll settle for being able to get on with the rest of my life.

Markus Holtermann

unread,
Dec 17, 2014, 10:47:26 AM12/17/14
to django...@googlegroups.com
I agree, a general "here's how you should do it" section in the docs should be added. Would you mind opening a ticket on https://code.djangoproject.com/ where you state the problem (e.g. link to this discussion). Thanks.

/Markus

John-Scott

unread,
Dec 17, 2014, 6:30:42 PM12/17/14
to django...@googlegroups.com
Thanks for your replies Markus!

I've added a ticket here https://code.djangoproject.com/ticket/24016
Reply all
Reply to author
Forward
0 new messages