📝 Практикум 2: 15 задач

4 Pydantic-моделирование + 4 Pydantic «найди ошибку» + 7 SQLAlchemy

⚡ Все 15 задач — кратко

Pydantic — моделирование:

  1. Event (title, date, location) — дата не в прошлом
  2. UserProfile (username, password, email) — min_length=8, EmailStr
  3. Transaction (amount, transaction_type, currency) — condecimal/Decimal gt=0, pattern debit|credit
  4. Appointment (patient_name, appointment_date) — не ранее чем через 24ч

Pydantic — найди ошибку:

  1. Product price=-100 — ValidationError из field_validator
  2. User email="aliceexample.com" без @ — EmailStr ValidationError
  3. Account balance="100" при validate_assignment — тип не float
  4. Item() без price с gt=0 — обязательное поле

SQLAlchemy:

  1. Engine для MySQL (mysql+pymysql)
  2. Engine для SQLite :memory: с echo/логированием
  3. Модель User (id PK, name String(50), age Integer)
  4. User + Post — one-to-many
  5. User + Address — one-to-many
  6. Сессия: add/commit/delete/query для User + Address
  7. Анализ 4 ошибок в коде (Person/Pet без Base, без bind=engine, String без длины)

Решения →

Блок 1: Pydantic — моделирование

Задачи 1–4: создайте Pydantic-модели на современном API (v2). Используйте @field_validator с @classmethod, Annotated[..., Field(...)], ConfigDict.

Задача 1: Определение модели события

Создайте модель Event, которая включает поля:

  • title (строка)
  • date (дата и время события)
  • location (строка)

Добавьте валидацию, чтобы дата события не была в прошлом.

Задача 2: Создание модели для пользователя с настройками

Определите модель UserProfile с полями:

  • username (строка)
  • password (строка)
  • email (строка с валидацией email)

Используйте Field для добавления описаний и настройки валидации пароля (должен быть не менее 8 символов). Добавьте пример значений в схему модели.

Задача 3: Модель для управления транзакциями

Разработайте модель Transaction для управления финансовыми операциями. Модель должна содержать:

  • amount (десятичное число, больше нуля)
  • transaction_type (строка, принимает значения "debit" или "credit")
  • currency (строка, ровно 3 символа)

Настройте автоматическое обрезание пробелов в строковых полях.

Задача 4: Модель с расширенной валидацией даты

Создайте модель Appointment для записи на приём, которая включает patient_name (строка), appointment_date (дата и время), и проверку, что запись не может быть установлена ранее, чем через 24 часа от текущего момента.

Блок 2: Pydantic — найди ошибку

Задачи 5–8: в каждом фрагменте кода содержится одна ошибка. Найдите её, объясните причину и предложите исправление. Фрагменты кода приведены из материалов занятия.

Задача 5: Product с ценой -100

Найдите и объясните ошибку в коде ниже:

from pydantic import BaseModel, field_validator

class Product(BaseModel):
    name: str
    price: float

    @field_validator('price')
    def check_price(cls, value):
        if value <= 0:
            raise ValueError("Price must be positive")
        return value

product = Product(name="Laptop", price=-100)

Задача 6: User с невалидным email

Найдите и объясните ошибку в коде ниже:

from pydantic import BaseModel, EmailStr

class User(BaseModel):
    name: str
    email: EmailStr

user = User(name="Alice", email="aliceexample.com")

Задача 7: Account с validate_assignment и строкой "100"

Найдите и объясните ошибку в коде ниже:

from pydantic import BaseModel

class Account(BaseModel):
    username: str
    balance: float = 0

    class Config:
        validate_assignment = True

acc = Account(username="john_doe", balance="100")

Задача 8: Item() без обязательного price

Найдите и объясните ошибку в коде ниже:

from pydantic import BaseModel, Field

class Item(BaseModel):
    name: str = Field(default=None)
    price: float = Field(gt=0)

item = Item()

Блок 3: SQLAlchemy

Задачи 9–15: используйте SQLAlchemy 2.x (DeclarativeBase, Mapped/mapped_column, with Session(engine)). Примеры устаревшего синтаксиса смотрите в Старый vs Новый.

Задача 9: Создание движка для MySQL

Создайте экземпляр движка для подключения к MySQL базе данных через PyMySQL.

Задача 10: Настройка движка SQLite с логированием

Напишите код для создания движка SQLAlchemy с подключением к базе данных SQLite, который будет располагаться в памяти, и настройте вывод логов всех операций с базой данных на экран.

Задача 11: Определение модели User

Создайте модель User с полями:

  • id (целочисленный тип, первичный ключ)
  • name (строковый тип, длина до 50 символов)
  • age (целочисленный тип)

Задача 12: Моделирование User + Post (один ко многим)

Определите две модели, User и Post, где пользователь может иметь много постов (один ко многим). Используйте декларативный базовый класс и задайте связь через relationship.

Задача 13: Моделирование User + Address (один ко многим)

Определите две модели: User и Address, где User может иметь множество Address. Используйте декларативный базовый класс.

Задача 14: Работа с сессией — add/commit/delete/query

Используя ранее определённые модели User и Address, создайте нового пользователя и адрес, добавьте их в базу данных с помощью сессии, затем удалите пользователя и проверьте изменения.

Задача 15: Анализ ошибок

Найдите и исправьте все ошибки в следующем коде:

from sqlalchemy import Column, ForeignKey, Integer, String, create_engine
from sqlalchemy.orm import relationship, sessionmaker
from sqlalchemy.ext.declarative import declarative_base

engine = create_engine('sqlite:///example.db')

class Person():
    __tablename__ = 'persons'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    pets = relationship("Pet", back_populates="owner")

class Pet():
    __tablename__ = 'pets'
    id = Column(Integer, primary_key=True)
    name = Column(String, nullable=False)
    owner_id = Column(Integer, ForeignKey('persons.id'))
    owner = relationship("Person", back_populates="pets")

Base.metadata.create_all(engine)
Session = sessionmaker()
session = Session()

new_person = Person(name='Alice')
new_pet = Pet(name='Fido', owner=new_person)
session.add(new_person)
session.add(new_pet)
session.commit()
session.close()

Перечислите все найденные ошибки и напишите исправленный код на SQLAlchemy 2.x.