views:

145

answers:

1

I created a Django app that had its own internal voting system and a model called Vote to track it. I want to refactor the voting system into its own app so I can reuse it. However, the original app is in production and I need to create a data migration that will take all the Votes and transplant them into the separate app.

How can I get two apps to participate in a migration so that I have access to both their models? Unfortunately, the original and separate apps both have a model named Vote now, so I need to be aware of any conflicts.

+2  A: 

Have you tried db.rename_table?

I would start by creating a migration in either the new or old app that looks something like this.

class Migration:

    def forwards(self, orm):
        db.rename_table('old_vote', 'new_vote')    

    def backwards(self, orm):
        db.rename_table('new_vote', 'old_vote')

If that does not work you can migrate each item in a loop with something along these lines:

def forwards(self, orm):
    for old in orm['old.vote'].objects.all():
        # create a new.Vote with old's data
models = {
    'old.vote' = { ... },
    'new.vote' = { ... },
}

Note: You must use orm[...] to access any models outside the app currently being migrated. Otherwise, standard orm.Vote.objects.all() notation works.

istruble
That's some keen lateral thinking! I still need to get content IDs and such to convert the ForeignKey to a GenericForeignKey, but I can do that all from the one app.
Soviut
Also, I thought I had to use the 'orm' wrapper to perform the data migration.
Soviut
You do not need to use the orm wrapper for rename_table (you are leveraging your knowledge of the underlying db structures and going straight to the raw table names). I updated the second example to make it look more like what you would expect in a south migration. The loop code with direct imports of the Vote models was just enough to give you the basic idea.
istruble
Yeah, my main issue was understanding how to access each applications models so I could write the data migration loop.
Soviut
attempting to access the 'old' model using orm.old doesn't work. It always expects the model name and won't accept an app name.
Soviut
It turns out the documentation *very* briefly explains that to get at models outside the app being migrated you can use: orm['app_name.model_name'] add that to your answer and I'll mark it correct.
Soviut
I marked you correct and added it for you.
Soviut
Thanks for the edit. Your update is much simpler than the one I was going to make. As a side note, be careful if your models have a ManyToManyField in them. I think South 0.6.2 is having a hard time getting them right.
istruble
thanks for the heads up.
Soviut