Search code examples
pythonmysqldjangodjango-modelsdatabase-migration

django model change OneToOneField to ForeignKey with no DownTime


I made one field of my django model as OneToOneField. So, It's not possible to store duplicate FK value. I think changing OneToOneField to ForeignKey is the solution.


Current

class MyModel(models.Model):
    ...
    abc = models.OneToOneField(YourModel, related_name='my_model', blank=True, null=True, on_delete=models.CASCADE)
    ...

Future

class MyModel(models.Model):
    ...
    abc = models.ForeignKey(YourModel, related_name='my_model', blank=True, null=True, on_delete=models.CASCADE)
    ...

The problem is downtime when migrating. This model is an important model in my service, many requests come in even in a moment. It also has many data.
Is there a way to fix this without downtime?

And my service is using mysql 5.6 and django 2.2.


Solution

  • Option a)

    Hmm so DB relation wise I don't see a difference, so what if you just adjust the field in the Model definition and modify the old migration that initially created the field? That way Django should think that there is nothing new to apply and treat the original OneToOne Field as a ForeignKey Field

    Please try that on an a backup first to see if there are maybe additional unique constraints or so that you might have to remove in a custom sql command before you have a real ForeignKey Field.

    Option b)

    Use multiple migrations and deployments.

    • First add a new field (e.g. abc_new that is nullable)
    • Adjust your logic so always both fields are filled for new data and changes
    • Deploy this in a new release
    • Copy the "old" data from abc to abc_new
    • At this point you have two rows that contain the exact same data
    • Create a new release that drops the old abc column and renames abc_new to abc and remove the logic that contained this "sync" logic for the abc_new field