Как в SQLAlchemy используется модуль typing для аннотации типов

Ответ

В SQLAlchemy модуль typing используется для статической типизации, что значительно улучшает работу с IDE (автодополнение, подсветка ошибок) и позволяет проводить проверку кода с помощью инструментов вроде mypy.

Основное применение — аннотация моделей и типов возвращаемых значений из запросов.

SQLAlchemy 2.0+ (рекомендуемый подход)

В современных версиях SQLAlchemy используется декларативный стиль с аннотациями типов. Для связи между атрибутом Python и колонкой в БД используются Mapped и mapped_column.

from typing import List, Optional
from sqlalchemy import create_engine, String
from sqlalchemy.orm import Mapped, mapped_column, Session, declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'

    # Аннотации типов для колонок
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(50))
    age: Mapped[Optional[int]] # Для nullable-полей используется Optional

# Аннотация типов в функциях
def get_all_users(session: Session) -> List[User]:
    """Функция возвращает список объектов User."""
    return session.query(User).all()

def get_user_by_id(session: Session, user_id: int) -> Optional[User]:
    """Функция возвращает один объект User или None."""
    return session.query(User).get(user_id)

Ключевые моменты:

  • Mapped[<python_type>]: Указывает, что атрибут класса сопоставлен с колонкой в базе данных.
  • Optional[<python_type>]: Используется для колонок, которые могут иметь значение NULL (nullable=True).
  • List[<Model>]: Применяется для аннотации результатов, возвращающих несколько записей (например, после .all()).

Ответ 18+ 🔞

А, ну это же про типизацию в SQLAlchemy, блядь! Ну, слушай, тут всё просто, как три копейки, только с припиздью.

Вот смотри, в SQLAlchemy модуль typing — это типа такой костыль для твоего IDE, чтобы он не тупил, как мартышлюшка, и понимал, что ты вообще делаешь. Автодополнение летит, ошибки подсвечивает — красота, ёпта! А ещё mypy этим пользуется, чтобы тебе мозги не выносить раньше времени.

SQLAlchemy 2.0+ (нормальный, современный подход)

Сейчас всё делают через декларативку и эти ваши аннотации. Чтобы связать питонячье поле с колонкой в базе, юзают Mapped и mapped_column. Не путай, а то будет пиздец.

from typing import List, Optional
from sqlalchemy import create_engine, String
from sqlalchemy.orm import Mapped, mapped_column, Session, declarative_base

Base = declarative_base()

class User(Base):
    __tablename__ = 'users'

    # Вот тут вся магия типизации и происходит
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(50))
    age: Mapped[Optional[int]] # А это для полей, где может быть NULL, понимаешь?

# И в функциях тоже аннотируем, чтобы не было сюрпризов
def get_all_users(session: Session) -> List[User]:
    """Функция возвращает список объектов User."""
    return session.query(User).all()

def get_user_by_id(session: Session, user_id: int) -> Optional[User]:
    """Функция возвращает один объект User или None."""
    return session.query(User).get(user_id)

Что тут важно, блядь:

  • Mapped[<python_type>]: Это типа приказ: «Эй, это поле мапится на колонку в базе, запомни!».
  • Optional[<python_type>]: Это для тех самых полей, где может быть NULL. Без этого mypy начнёт орать, как сука.
  • List[<Model>]: Когда функция возвращает кучу записей, например, после .all(). Так и пишем — список юзеров, а не просто хуй с горы.

Вот и вся философия. Сделаешь по-старому, без типов — сам себя наебешь потом, когда проект разрастётся до овердохуища строк.