28

I'm using multi-table-inheritance, and want to know how to create an inherited type from an instance of the superclass.

Using the example given in the documentation:

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

Now when you create a Restaurant, you automatically make a Place, which is fine, and the behaviour I expect and want.

But what if I make a Place, and later decide I want to convert to a specific type (like Restaurant). How do you create a Restaurant, using an existing Place?

4
  • 3
    possible duplicate of Django model inheritance: create sub-instance of existing instance (downcast)? Commented Mar 22, 2012 at 12:47
  • I saw that question and answer, but was confused because I thought that problem had to do with authentication (because a User is a bit more of a special object) Commented Mar 22, 2012 at 13:00
  • I upvoted your duplication remark, however... the question refering to is about Users, which might be confusing. I find this example of places and restaurants (stolen from the Django Documentations) more clear and resembling my problem.... but in base it's the same problem. Commented Mar 22, 2012 at 13:08
  • See code.djangoproject.com/ticket/7623 Commented Jun 19, 2014 at 16:22

3 Answers 3

32

Multi-table inheritance is just OneToOneField relation between Place and Restaurant.

place = Place.objects.get(id=1) # Create a restaurant using existing Place restaurant = Resturant(place_ptr=place) # this might be needed to not delete the data: restaurant.__dict__.update(place.__dict__) restaurant.save() 
Sign up to request clarification or add additional context in comments.

3 Comments

This will cause restaurant.name to be emptied. Because restaurant.save() will update the Place with name='' (because restaurant = Resturant())... there must be a better way...
You should add restaurant.__dict__.update(place.__dict__), see Daniel Roseman's answer.
Ok, the combination of the answer of secator and addition of jpic does the trick...
13
place = Place.objects.get(id=1) # Create a restaurant using existing Place place.__class__ = Restaurant place.save() restaurant = place 

Comments

10

While undocumented, this seems to do the trick:

restaurant(place_ptr=place).save_base(raw=True) 

This solves the problem without using any hacks and is the shortest solution, also in terms of processing, using Django APIs.

While searching for this solution, I also found a slightly longer one, but using documented APIs. It is basically the same as Mariusz answer, also see this answer for more details:

from django.forms.models import model_to_dict restaurant(place_ptr=place, **model_to_dict(place)).save() 

However, this second one is more risky due to limited field set returned by the model_to_dict (see again the answer explaining the differences among various methods presented). Naturally, it also generates more DB calls because it writes to both tables.

1 Comment

restaurant(place_ptr=place).save_base(raw=True) Worked like a charm, thank you!

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.