💻 Примеры: CRUD и запросы (SQLAlchemy 2.x)

🎯 Все примеры — рабочий код, основан на лекции + SQLAlchemy 2.x

⚡ Минимальный пример CRUD

from sqlalchemy import create_engine, select, String, Integer, desc
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session

engine = create_engine("sqlite:///:memory:")

class Base(DeclarativeBase): pass

class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(50))
    age: Mapped[int] = mapped_column(Integer)

Base.metadata.create_all(engine)

with Session(engine) as session:
    # Create
    session.add_all([User(name="Alice", age=30), User(name="Bob", age=22)])
    session.commit()

    # Read
    users = session.scalars(select(User)).all()
    print(users)

    # Update
    user = session.get(User, 1)
    user.age = 35
    session.commit()

    # Delete
    user = session.get(User, 2)
    session.delete(user)
    session.commit()

Пример 0: Подготовка модели и тестовых данных

Во всех примерах используется модель User и набор данных из лекции.

from sqlalchemy import create_engine, select, String, Integer, and_, or_, not_, desc
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, Session

# Движок — SQLite в памяти (удобно для обучения)
engine = create_engine("sqlite:///:memory:", echo=False)

class Base(DeclarativeBase):
    pass

class User(Base):
    __tablename__ = "users"
    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(50))
    age: Mapped[int] = mapped_column(Integer)

    def __repr__(self) -> str:
        return f"User(id={self.id}, name={self.name!r}, age={self.age})"

Base.metadata.create_all(engine)

# Тестовые данные из лекции
with Session(engine) as session:
    session.add_all([
        User(name='Bob',   age=22),
        User(name='David', age=27),
        User(name='Alice', age=30),
        User(name='Ann',   age=17),
        User(name='Ann',   age=27),
    ])
    session.commit()
print("Данные добавлены.")

Пример 1: Create — добавление пользователей

# Добавление одного пользователя
with Session(engine) as session:
    new_user = User(name="Alice", age=30)
    session.add(new_user)
    session.commit()
    print(f"Создан: {new_user.id}, {new_user.name}")  # id присваивается после commit

# Добавление нескольких пользователей
with Session(engine) as session:
    session.add_all([
        User(name='Bob',   age=22),
        User(name='David', age=27),
    ])
    session.commit()

Пример 2: Read — чтение по первичному ключу

with Session(engine) as session:
    user = session.get(User, 1)   # по id=1
    if user:
        print(user.name, user.age)
    else:
        print("Пользователь не найден")

Пример 3: Read — выборка всех записей

with Session(engine) as session:
    users = session.scalars(select(User)).all()
    for user in users:
        print(user.name, user.age)

Пример 4: Update — обновление данных

with Session(engine) as session:
    user = session.get(User, 1)
    if user:
        user.age = 35           # меняем атрибут
        session.commit()        # SQLAlchemy генерирует UPDATE

    # Проверяем результат
    user = session.get(User, 1)
    print(user.name, user.age)  # Alice 35

Пример 5: Delete — удаление пользователя

with Session(engine) as session:
    user = session.get(User, 1)
    if user:
        session.delete(user)
        session.commit()
        print("Deleted")
    else:
        print("User with id 1 isn't found")

Пример 6: Методы извлечения — .all(), .first(), .one(), .one_or_none()

with Session(engine) as session:
    # .all() — список всех
    users = session.scalars(select(User)).all()
    print(".all():", users)

    # .first() — первый или None
    user = session.scalars(select(User)).first()
    print(".first():", user)

    # .one() — ровно один (выбросит исключение при 0 или >1)
    stmt = select(User).where(User.id == 3)
    user = session.scalars(stmt).one()
    print(".one():", user)

    # .one_or_none() — один или None (выбросит при >1)
    stmt = select(User).where(User.id == 3)
    user = session.scalars(stmt).one_or_none()
    print(".one_or_none():", user)

Пример 7: Фильтрация — сравнения

with Session(engine) as session:
    # Пользователи старше 25 лет
    stmt = select(User).where(User.age > 25)
    users = session.scalars(stmt).all()
    print("Старше 25:")
    for user in users:
        print(f"  {user.id}, {user.name}, {user.age}")

Пример 8: Фильтрация — like(), between(), in_()

with Session(engine) as session:
    # like: имена на "A"
    stmt = select(User).where(User.name.like('A%'))
    users = session.scalars(stmt).all()
    print("Имена на A:", [u.name for u in users])

    # between: id от 2 до 4
    stmt = select(User).where(User.id.between(2, 4))
    users = session.scalars(stmt).all()
    print("ID 2-4:", [(u.id, u.name) for u in users])

    # in_: имена из списка
    names = ["Alice", "Bob"]
    stmt = select(User).where(User.name.in_(names))
    users = session.scalars(stmt).all()
    print("Alice или Bob:", [u.name for u in users])

Пример 9: Логические условия — and_(), or_(), not_()

with Session(engine) as session:
    # AND: возраст от 20 до 23
    stmt = select(User).where(and_(User.age > 20, User.age < 23))
    users = session.scalars(stmt).all()
    print("Возраст 20-23:", users)

    # OR: старше 30 ИЛИ имя David
    stmt = select(User).where(or_(User.age > 30, User.name == 'David'))
    users = session.scalars(stmt).all()
    print("Старше 30 или David:", users)

    # NOT: не David
    stmt = select(User).where(not_(User.name == 'David'))
    users = session.scalars(stmt).all()
    print("Не David:", users)

Пример 10: Сортировка

with Session(engine) as session:
    # Возраст: по возрастанию
    stmt = select(User).order_by(User.age)
    users = session.scalars(stmt).all()
    print("По возрасту (ASC):")
    for u in users:
        print(f"  {u.id}, {u.name}, {u.age}")

    # Возраст: по убыванию
    stmt = select(User).order_by(desc(User.age))
    users = session.scalars(stmt).all()
    print("По возрасту (DESC):")
    for u in users:
        print(f"  {u.id}, {u.name}, {u.age}")

    # Многоуровневая: возраст DESC, имя ASC
    stmt = select(User).order_by(desc(User.age), User.name)
    users = session.scalars(stmt).all()
    print("Возраст DESC + имя ASC:")
    for u in users:
        print(f"  {u.id}, {u.name}, {u.age}")
Ожидаемый вывод сортировки с данными из лекции:
Возраст DESC: Alice(30), David(27), Ann(27), Bob(22), Ann(17)
После добавления Ann(27) и David(27) многоуровневая сортировка разместит Ann перед David (алфавитный порядок).