В Django существует два вида подклассов моделей - абстрактные базовые классы; и наследование нескольких таблиц.
Абстрактные базовые классы никогда не используются сами по себе и не имеют таблицы базы данных или какой-либо другой формы идентификации. Это просто способ сокращения кода путем группировки наборов общих полей в коде , а не в базе данных.
Например:
class Address(models.Model):
street = ...
city = ...
class Meta:
abstract = True
class Employee(Address):
name = ...
class Employer(Address):
employees = ...
company_name = ...
Это надуманный пример, но, как вы можете видеть, Employee
не является Address
и не является Employer
. Они оба содержат поля, относящиеся к адресу. В этом примере только две таблицы; Employee
и Employer
- и оба они содержат все поля адреса. Адрес работодателя нельзя сравнивать с адресом сотрудника на уровне базы данных - адрес не имеет собственного ключа.
Теперь, с наследованием нескольких таблиц (удалите реферат = True из адреса), у адреса есть таблица для себя. Это приведет к 3 отдельным таблицам; Address
, Employer
и Employee
. И у работодателя, и у сотрудника будет уникальный внешний ключ (OneToOneField) для адреса.
Теперь вы можете обращаться к адресу, не беспокоясь о его типе.
for address in Address.objects.all():
try:
print address.employer
except Employer.DoesNotExist: # must have been an employee
print address.employee
Каждый адрес будет иметь свой собственный первичный ключ, что означает, что он может быть сохранен в четвертой таблице самостоятельно:
class FakeAddresses(models.Model):
address = models.ForeignKey(Address)
note = ...
Наследование нескольких таблиц - это то, что вам нужно, если вам нужно работать с объектами типа Post
, не беспокоясь о том, что это за тип Post. При доступе к любому из полей Post из подкласса будет происходить дополнительная нагрузка; но накладные расходы будут минимальными. Это уникальное индексное соединение, которое должно быть невероятно быстрым.
Просто убедитесь, что если вам нужен доступ к Post
, вы используете select_related
в наборе запросов.
Events.objects.select_related(depth=1)
Это позволит избежать дополнительных запросов для извлечения родительских данных, но приведет к возникновению соединения. Поэтому используйте только select related, если вам нужна почта.
Две последние заметки; если сообщение может быть как объявлением, так и событием, то вам нужно сделать традиционную вещь и связать сообщение с помощью ForeignKey. В этом случае подклассы работать не будут.
И последнее: если соединения являются критически важными для производительности между родителем и потомками, вам следует использовать абстрактное наследование; и используйте общие отношения для ссылки на абстрактные сообщения из таблицы, которая гораздо менее критична для производительности.
Родовые отношения по сути хранят данные следующим образом:
class GenericRelation(models.Model):
model = ...
model_key = ...
DeletedPosts(models.Model):
post = models.ForeignKey(GenericRelation)
Присоединение в SQL будет намного сложнее (вам поможет django), но оно также будет менее производительным, чем простое объединение OneToOne. Вам следует идти по этому пути только в том случае, если присоединения OneToOne серьезно снижают производительность вашего приложения, что, вероятно, маловероятно.