Search code examples
djangodjango-migrationsdjango-1.8

Django - How to move attribute to another model and delete it


I have the following scenario:

class C():
    y = models.Integer...
    z = models.Integer...

class D():
    y2 = models.Integer...
    z2 = models.Integer...

I want to copy the data from the attribute y and paste it to y2. Ok, I created a data migration that does the work. In a nutshell:

from greatapp.models import C, D

class Migration(migrations.Migration):

    def move_info_to_class_d(apps, schema_editor):
        objs = C.objects.all()

        for obj in objs.iterator():
            d = D.objects.create(y2=obj.y)

    operations = [
        migrations.RunPython(move_info_to_class_d)
    ]

Notice that I also want to remove the attribute from the class C, so the code would look like this:

class C():
    z = models.Integer...

class D():
    y2 = models.Integer...
    z2 = models.Integer...

Everything looks ok, right? Time to commit.

Oh, wait! The next person who executes this code will get an error, because the data migration is trying to access an attribute that doesn't exist anymore (y in this case).

Does anybody know a workaround (that doesn't need .sql files) to copy the attribute to another model class and then delete it from the source class?


Solution

  • That's why you get the apps argument to the data migration. It holds definitions of the models as they were when you created the data migration.

    So do

    def move_info_to_class_d(apps, schema_editor):
        C = apps.get_model('yourappname', 'C')
        D = apps.get_model('yourappname', 'D')
    
        objs = C.objects.all()
    
        for obj in objs.iterator():
            d = D.objects.create(y2=obj.y)
    

    And it will work fine (as long as you create the migration that removes C.y after this one).

    Edit: oh, and objs.iterator() is unnecessary, objs is already iterable by itself.