Add Django model parent class to existing an existing model for multi-table inheritance
Asked Answered
D

2

5

The Django Docs uses this example to demonstrate multi-table inheritance:

from django.db import models

class Place(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)

class Restaurant(Place):
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

If I had initially built the Restaurant class like so:

class Restaurant(models.Model):
    name = models.CharField(max_length=50)
    address = models.CharField(max_length=80)
    serves_hot_dogs = models.BooleanField(default=False)
    serves_pizza = models.BooleanField(default=False)

and then after a bunch of Restaurant objects have already been created, I realize it would have been better to use MTI, is there a good way to create the parent Place class after the fact and migrate the data?

Dulaney answered 3/5, 2016 at 19:39 Comment(4)
Do you mean better in the means of code readability or performance? Maybe you should take a look at this post: #23467077Nertie
I am not very sure about you question, if you want to have parent model object and dont want to have table created for it you could use. 'class Meta: Abstract = True'Ghiberti
I mean I want to transition my current structure to use multi-table inheritance. For example, I'd like to now add an Office model which also has a name and address and I want all addresses to be unique; so I want to add the Place and the Office class and migrate my existing Restaurant data to use the new data structure.Dulaney
@Amar: abstract must be written all-lowercase.Subtitle
D
5
  1. Add the new models but keep the old one as well. Make migrations.

  2. Write a custom migration to copy the data from the Restaurant model to the NewRestaurant model.

  3. If necessary, change over any foreign key fields in other models from Restaurant to NewRestaurant and make migrations.

  4. If necessary, change everywhere in the app that the Restaurant class is used to use the NewRestaurant class.

  5. Delete the old restaurant model and make migrations.

  6. Rename the new restaurant model to Restaurant so everything works again with the new structure. Make migrations.

Dulaney answered 4/5, 2016 at 14:23 Comment(2)
I have a question - how do you keep the import of NewRestaurant in migration from p.2 if NewRestaurant later will be renamed?Keyboard
@Keyboard You do not make direct import to your app code from your migration, that is not maintenable for the reason you pinpointed, instead you would use MyModel = apps.get_model('app','MyModel'). Django will be able to run your code in its historical context, see more at docs.djangoproject.com/fr/3.2/ref/migration-operations/…Moreland
C
4

Easy way: create fake IntegerField called <parent_model>_ptr in child model, populate it, and then remove it and add parent model at the same time.

Here is a complete article: http://www.johnborwick.com/blog/2013/08/using-south-to-change-a-django-models-parent-class/. It's about South, but the idea works with modern Django as well.

Cogswell answered 25/7, 2017 at 15:12 Comment(2)
Thank you for sharing this. I will be sure to try this the next time I run across this issueDulaney
Lifesaver! Thank you so much!Varanasi

© 2022 - 2024 — McMap. All rights reserved.