What is the difference between a Multi-table inherited model and a simple One-to-one relationship between the same two models?
django, inheritance, model, orm
Solution
1. You don't really get any python inheritance, that is you can't inherit/override methods or attributes from the model class `Place` in your class `Restaurant`:
For instance:
class Place(models.Model):
name = models.CharField(max_length=50)
def get_x(self):
return 'x'
class Restaurant(models.Model):
place = models.OneToOneField(Place)
serves_pizza = models.BooleanField()
a_restaurant = Restaurant()
a_restaurant.get_x() # -> wouldn't work
This means that to obtain the `name` of a restaurant you can't do `a_restaurant.name`, you would need to follow the link: `a_restaurant.place.name`
Also note that when querying a `Place` object with the related `Restaurant`.
a_restaurant.save()
Place.objects.get(pk=a_restaurant.pk) # won't work
You would have to write:
a_restaurant.save()
Place.objects.get(restaurant__pk=a_restaurant.pk)
2 and 3. are almost the same. You do get real python inheritance with these.
a_restaurant = Restaurant()
a_restaurant.get_x() # would actually work and print 'x'
Your model class `Restaurant` inherits everything from `Place`: model fields, normal instance/class attributes, managers, methods... and you can also override almost anything of these: You can't override field attributes, that's not supported.
So now you can get the values of the fields from the parent model directly:`a_restaurant.name` because they are inherited.
Since with these implementation a `Restaurant` is a also `Place` you can query for a `Place` object with `Restaurant` data:
a_restaurant.save()
the_place = Place.objects.get(pk=a_restaurant.pk)
# ^ this works now and returns the equivalent `Place` instance.
the_same_restaurant = the_place.restaurant
The difference between 2 and 3 is easier to see if you give a different name to the field:
class Place(models.Model):
name = models.CharField(max_length=50)
class Restaurant(Place):
where = models.OneToOneField(Place, parent_link=True)
serves_pizza = models.BooleanField()
Works exactly the same but to obtain the parent place of a `Restaurant` the attribute name is `where`:
the_place = a_restaurant.where
with 2 would have been:
the_place = a_restaurant.place_ptr
These means that `place = models.OneToOneField(Place, parent_link=True)` will only change the name of the link to the parent model instance. The default name is `'{lowercase_model_name}_ptr'`.
Last example:
With 1:
place1 = Place.objects.create(name='place_1')
place2 = Place.objects.create(name='place_2')
restaurant1 = Restaurant.objects.create(place=place1, serves_pizza=True)
print Place.objects.all() # prints [place1, place2]
print Restaurant.objects.all() # prints [restaurant1]
With 2-3:
place1 = Place.objects.create(name='place_1')
place2 = Place.objects.create(name='place_2')
restaurant1 = Restaurant.objects.create(name='place_3', serves_pizza=True)
print Place.objects.all() # prints [place1, place2, place3]
print Restaurant.objects.all() # prints [restaurant1]
Hope these helps. It grow a bit too long :/
Problem
What is the differences between these implementations? What does Django differently (beside inheriting Meta `ordering` and `get_latest_by` attribute) ? 1. ``` # models.py from django.db import models class Place(models.Model): name = models.CharField(max_length=50) class Restaurant(models.Model): place = models.OneToOneField(Place) serves_pizza = models.BooleanField() ``` 2. ``` class Place(models.Model): name = models.CharField(max_length=50) class Restaurant(Place): serves_pizza = models.BooleanField() ``` 3. ``` class Place(models.Model): name = models.CharField(max_length=50) class Restaurant(Place): place = models.OneToOneField(Place, parent_link=True) serves_pizza = models.BooleanField() ```