I want to move the field honk and it’s data from one model to another using South:
class Foo(models.Model):
foofield = models.CharField()
honk = models.PositiveIntegerField()
class Bar(models.Model):
barfield = models.CharField()
I’ve done this before, using 3 separate migrations:
- A schema migration, adding honk to Bar
- A data migration, copying all Foo.honk data to Bar.honk
- Another schema migration, dropping honk from Foo
Can I do these three steps in a single migration?
I’ve already learnt that there isn’t much of a difference between schema and data migrations in South, so I figured perhaps something like this might work (which is the three migrations above just munged into one):
class Migration(DataMigration):
def forwards(self, orm):
# add column
db.add_column('myapp_bar', 'honk', self.gf('django.db.models.fields.PositiveIntegerField')(default='0'), keep_default=False)
# copy data
for foo in Foo.objects.all():
# find the right bar here and then ...
bar.honk = foo.honk
bar.save()
# remove old column
db.delete_column('myapp_foo', 'honk')
Will this work or will it fail because my (South frozen) orm doesn’t know about Bar.honk yet? Or am I doing it wrong and there’s a nicer way to do this sort of thing in a single migration?
Since this question earned me a Tumbleweed badge, I’ve dug in and tried it myself. Here’s what I’ve found out.
No you can’t merge these migrations
Because the ORM freeze only contains the schema you are migrating to. So in the above example, foo.honk wouldn’t be accessible during the data migration (the for loop), because it is deleted during the schema migration, so it isn’t in the frozen ORM. Additionally you’ll get DatabaseError exceptions if you try to access data because the columns in the database don’t yet match the ones of the model (i.e. if you try to access anything before a db.add_column).
Looks like there’s no simple shortcut and doing something like this does take the 3 migrations mentioned above.