0

I need to outsource some of the attribues in the following Django model:

class TextResult(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
    text = models.ForeignKey(Text)
    # following fields will be in the referenced model
    wpm = models.FloatField(default=0.0)
    accuracy = models.FloatField(default=1.0,
                                 validators=[MinValueValidator(0.0),
                                             MaxValueValidator(1.0)])

to a model, that references to the specific data:

class TextResult(models.Model):
    user = models.ForeignKey(settings.AUTH_USER_MODEL, default=1)
    text = models.ForeignKey(Text)
    typing_result = models.ForeignKey(TypingResult)

class TypingResult(models.Model):
    wpm = models.FloatField(default=0.0)
    accuracy = models.FloatField(default=1.0,
                                 validators=[MinValueValidator(0.0),
                                             MaxValueValidator(1.0)])

The problem is, that there is already some data in the database, so I have to migrate the data to the new structure, what is the easiest, cleanest way to achieve that?

  • You create a migration, that create the new table and the foreign key column, then goes through all rows to copy the data to the new table and sets the foreign key, and at the end deletes the old columns from the main table. You should be able to salvage some code from the migration file Django create automatically. – Klaus D. May 24 '17 at 00:19

1 Answers1

1

I would do a 3-step migration.

  1. Create the new fields

1.1. Create TypingResult model and the typing_result = models.ForeignKey(TypingResult, blank=True, null=True) field. Make sure the FK is optional by making it blank-able and null-able

1.2 Checkpoint by migrating

  1. Data Migration

2.1 Create an empty migration using this guide https://docs.djangoproject.com/en/1.11/topics/migrations/#data-migrations and add instructions for data migrations.

2.2 The data migration steps are as follows:

  • Iterate through all TextResult for each of them create a TypingResult with the corresponding data

  • Link the TypingResult to the TextResult through FK

2.3 Run the migration to checkpoint

  1. Cleanup

3.1 Delete the wpm and accuracy fields on the TextResult and make the ForeignKey non-optional.

3.2 Run the migration

Conclusion

This can probably all be done in 1 step, but it's best to understand what is going on. Also adding pdb before a .save() call will allow you to inspect the steps for the data migration

import pdb; pdb.set_trace()
Andrei Cioara
  • 3,404
  • 5
  • 34
  • 62
  • Let me know if you need more step by step help. For the link I referred, I would read all the way to `Accessing models from other apps` – Andrei Cioara May 24 '17 at 02:51
  • Thanks, I was able to solve my problem based on your solution, I thought a little through it, and came to the conclusion that it is better to use inheritance, I created a new question for that, because it is similar but not the same. I used only one migration, since the task was relatively straightforward. You can find the code in my answer there: https://stackoverflow.com/a/44170808/4129587 – Philipp Mildenberger May 25 '17 at 01:22