Tortoise-ORM: поля связанных объектов в __str__

Я разрабатываю сервис АПИ используя AIOHTTP, пытаюсь прикрутить какую-нибудь асинхронную ORM, выбор пал на Tortoise-ORM (следующий кандидат Gino). На данный момент возник такой вопрос.

В Django проекте у меня есть много связанных моделей с методами __str__, выглядит это примерно так:

from tortoise.models import Model
from tortoise import fields

class Department(Model):
    id = fields.IntField(pk=True)
    title = fields.TextField()
    upper = fields.ForeignKeyField('models.Department', related_name='children')

    def __str__(self):
        if self.upper is not None:
            return f'{self.id} Department {self.title} of {self.upper.title}'
        else:
            return f'{self.id} Department {self.title}, head'

class Employee(Model):
    id = fields.IntField(pk=True)
    name = fields.TextField()
    dep = fields.ForeignKeyField('models.Department', related_name='employees')

    def __str__(self):
        return f'{self.id}. Employee {self.name} of {self.dep.title}'

Так что каждый объект ссылается на многие другие и показывает их в своём описании. Но Tortoise при этом выдаёт ошибку:

AttributeError: 'QuerySet' object has no attribute 'title'

Кажется, сделать await внутри метода __str__ не получится. Можно ли вообще использовать поля связанных моделей для построения такого описания объекта в Tortoise-ORM?


Ответы (1 шт):

Автор решения: AivanF.

Tortoise-ORM не позволяет автоматически извлекать связанные объекты из БД, пока не будет явно выполнен запрос. Обращения к связанным полям возвращают лишь объект QuerySet без взаимодействия с БД.

Чтобы получить связанные объекты надо использовать методы prefetch_related() или fetch_related() перед работой с объектами, после чего соответствующие поля будут возвращать конкретный объект, а не QuerySet. Документация.

Примеры:

emp_one = await Employee.filter(name="Emp_1").prefetch_related("dep").first()
print(emp_one)

emp_two = await Employee.filter(name="Emp_2").first()
await emp_two.fetch_related("dep")
print(emp_two)

Перевод этого ответа.

→ Ссылка