Мы все использовали определения отношений в FastAPI и писали схемы для имитации действия таблиц соединения SQL.

Но если вы работаете с большим объемом данных, вы быстро понимаете, что он очень быстро становится очень медленным.

Итак, мы определяем наши модели примерно так

class User(Base):
    __tablename__ = "users"

    user_id = Column(Integer, primary_key=True, nullable=False)
    name = Column(String, nullable=True)
    email = Column(String, nullable=False)

class Blog(Base):
    __tablename__ = "blogs"

    blog_id = Column(Integer, primary_key=True, nullable=False)
    title = Column(String, nullable=True)
    description = Column(String, nullable=False)
    creator_id = Column(Integer, ForeignKey('users.user_id'), nullable=False)

    creator = relationship('users')

И для этого мы бы определили схему ответа как таковую

class UserBase(BaseModel):
    user_id: int
    name: str
    email: str

class BlogOutput(BaseModel):
    blog_id: int
    title: str
    description: str
    creator: UserBase
    
    class Config:
        orm_mode: True

Теперь, когда мы используем BlogOutput в качестве модели ответа, мы получим смоделированный результат таблицы соединений между пользователем и блогом.

Почему я говорю смоделированный? Когда я пробовал это с гораздо большим объемом данных, я увидел, что это становится очень медленным. После дальнейшего изучения я узнал: FastAPI здесь на самом деле не выполняет соединение таблиц, после того, как он получает список Creator_id, он снова индивидуально запрашивает базу данных для пользователя, что замедляет весь процесс.

Как этого избежать?

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

class User(Base):
    __tablename__ = "users"

    user_id = Column(Integer, primary_key=True, nullable=False)
    name = Column(String, nullable=True)
    email = Column(String, nullable=False)

class Blog(Base):
    __tablename__ = "blogs"

    blog_id = Column(Integer, primary_key=True, nullable=False)
    title = Column(String, nullable=True)
    description = Column(String, nullable=False)
    creator_id = Column(Integer, ForeignKey('users.user_id'), nullable=False)

    creator = relationship('users', lazy="joined")

Мы добавляем ленивый параметр как объединенный в определение нашего отношения. Это всегда будет извлекать строки из таблицы User, когда вы запрашиваете, по сути, таблицу соединений. Это делает такие запросы экспоненциально быстрее.

На самом деле это не большое изменение, но каким-то образом его так легко упустить из виду в документации, и оно оказывает огромное влияние.

Попробуй сам!

Спасибо за прочтение.