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?

Ryan Allen
  • 5,414
  • 4
  • 26
  • 33
  • Do you mean better in the means of code readability or performance? Maybe you should take a look at this post: http://stackoverflow.com/questions/23466577/should-i-avoid-multi-table-concrete-inheritance-in-django-by-any-means – xtrinch May 03 '16 at 20:09
  • 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' – Amar May 04 '16 at 06:54
  • 1
    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. – Ryan Allen May 04 '16 at 14:15
  • @Amar: `abstract` must be written all-lowercase. – Eugene Gr. Philippov Jul 09 '21 at 02:02

2 Answers2

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.

Ryan Allen
  • 5,414
  • 4
  • 26
  • 33
  • I have a question - how do you keep the import of NewRestaurant in migration from p.2 if NewRestaurant later will be renamed? – GriMel Jul 16 '20 at 14:40
  • @GriMel 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 https://docs.djangoproject.com/fr/3.2/ref/migration-operations/#runpython – Jean Bouvattier Jul 22 '21 at 13:01
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.

MrKsn
  • 1,185
  • 1
  • 16
  • 27