What is the differences between these implementations? What does Django differently (beside inheriting Meta ordering
and get_latest_by
attribute) ?
1 - to create restaurant you need to create place, after create restaurant, after link them, 2 - then creating restaurant, new place created and linked automaticaly, 3 - you renamed parent link to place.
Using Model Inheriting with Content Types you can list all Cafes, Restaurants, Bars, etc iterating on Place.objects.all()
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 :/