michel.iamit
michel.iamit

Reputation: 5906

Django model inheritance: Create a subclass using existing super class

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?

Upvotes: 28

Views: 14476

Answers (3)

Mariusz Jamro
Mariusz Jamro

Reputation: 31643

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()

Upvotes: 32

velis
velis

Reputation: 10025

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.

Upvotes: 10

Davide Callegari
Davide Callegari

Reputation: 494

place = Place.objects.get(id=1)

# Create a restaurant using existing Place
place.__class__ = Restaurant
place.save()
restaurant = place

Upvotes: 13

Related Questions