В чем разница между унаследованной моделью с несколькими таблицами и простой зависимостью "один к одному" между двумя одинаковыми моделями?

В чем разница между этими реализациями? Что Django по-разному (помимо наследования атрибутов Meta ordering и get_latest_by)?

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

Ответы

Ответ 1

1. На самом деле вы не наследуете наследование python, то есть вы не можете наследовать/переопределять методы или атрибуты из класса модели Place в своем классе Restaurant:

Например:

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

Это означает, что для получения name в ресторане вы не можете сделать a_restaurant.name, вам нужно будет перейти по ссылке: a_restaurant.place.name

Также обратите внимание, что при запросе объекта Place с соответствующим Restaurant.

a_restaurant.save()
Place.objects.get(pk=a_restaurant.pk)  # won't work

Вам нужно будет написать:

a_restaurant.save()
Place.objects.get(restaurant__pk=a_restaurant.pk)

2 и 3. почти одинаковы. Вы получаете реальное наследование python с этими.

a_restaurant = Restaurant()
a_restaurant.get_x() # would actually work and print 'x'

Ваш класс модели Restaurant наследует все от Place: поля модели, нормальные атрибуты экземпляра/класса, менеджеры, методы... и вы также можете переопределить почти все: Вы не можете переопределять атрибуты полей, которые не поддерживаются.

Итак, теперь вы можете напрямую получить значения полей из родительской модели: a_restaurant.name, потому что они наследуются.

Поскольку с этой реализацией a Restaurant является а также Place, вы можете запросить объект Place с данными Restaurant:

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

Различие между 2 и 3 легче увидеть, если вы укажете другое имя в поле:

class Place(models.Model):
    name = models.CharField(max_length=50)

class Restaurant(Place):
    where = models.OneToOneField(Place, parent_link=True)
    serves_pizza = models.BooleanField()

Работает точно так же, но для получения родительского места Restaurant имя атрибута where:

the_place = a_restaurant.where

с 2:

the_place = a_restaurant.place_ptr

Это означает, что place = models.OneToOneField(Place, parent_link=True) изменит имя ссылки на экземпляр родительской модели. Имя по умолчанию '{lowercase_model_name}_ptr'.


Последний пример:

С 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]

С 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]

Надеюсь, что это поможет. Он слишком длинный:/

Ответ 2

1 - для создания ресторана вам нужно создать место, после создания ресторана, после ссылки, 2 - затем создание ресторана, новое место, созданное и связанное автоматически, 3 - вы переименовали родительскую ссылку в место.

Используя Наследование моделей с помощью типов контента, вы можете перечислить все Cafes, Restaurants, Bars и т.д., итерации на Place.objects.all()