Элегантное распространение одной модели Django по нескольким таблицам?
Существует множество документов и обсуждений для того, чтобы несколько моделей имели общие поля в родительском классе/таблице, используя "конкретное" или "многотабличное" наследование:
class Place(models.Model):
...
class Restaurant(Place):
...
Однако я не могу найти много информации об обратном случае использования: разделение полей одной модели на несколько таблиц для экономии затрат на загрузку широких колонок, кроме тех случаев, когда они действительно нужны.
Рассмотрим следующий сценарий:
class Person_Profile(models.Model):
...lots of fields...
class Person_Preferences(models.Model):
...lots of fields...
class Person(Person_Profile, Person_Preferences):
...small set of core fields...
<
- Когда вы создаете Person, два других объекта автоматически создаются и связываются для вас.
- Вы можете получить доступ к полям профиля и предпочтений непосредственно в Person. (
person.some_field
)
Единственное, чего мне не хватает, это как элегантно контролировать, когда Django загружает поля из родительской таблицы, поскольку в настоящее время загрузка Person с помощью p = Person.objects.first()
приводит к тому, что все три таблицы объединяются и выбираются по умолчанию.
Splitted model - Это хорошее решение, только если вы не понимаете идею DataManagers/Queryset.
Разделение полей на модели - хороший подход, если вы используете Meta.abstract = True
. Если вы создаете два реальных класса только для того, чтобы сложить все поля в дочернем классе - вы теряете много времени с джойнами на каждый запрос в БД.
больше здесь: https://docs.djangoproject.com/en/4.1/topics/db/models/#abstract-base-classes
В QuerySet
вы можете определить множество методов. После этого вы можете соединить методы в цепочку.
class Person_Profile(models.Model):
Meta:
abstract = True
...lots of fields...
class Person_Preferences(models.Model):
Meta:
abstract = True
...lots of fields...
class Person(Person_Profile, Person_Preferences):
...small set of core fields...
objects = PersonQueryset.as_manager() # in old django PersonDataManager()
Как может выглядеть PersonDataManager
или PersonQuerySet
:
class PersonQuerySet(QuerySet):
def onlySpecialFields(self, *args, **kwargs):
return self.only(*my_special_only_list)
def deferSpecialFields(self, *args, **kwargs):
return self.defer(*my_special_defer_list)
def skinnyPersons(self, *args, **kwargs):
return self.only('name')
Как вы можете его использовать:
SkinnyPersons_List = Person.objects.filter(name=something).skinnyPersons()
# after that
FirstSkinnyPerson = SkinnyPersons_List.first()
# somethere in code
LastSkinnyPerson = Person.objects.skinnyPersons().last()
Плюсы:
- тип содержимого всегда один и тот же
- у вас нет проблем с родовыми объектами
- вы работаете с одинаковыми ._meta, .app_label и .model_name
- у вас нет новой модели, которая вам не нужна .
- вы используете идею django querysets
конс:
- не найдено