Текст задания из LMS
Источник: lms.itcareerhub.de — Python Advanced 5: Flask: SQLAlchemy
Задача 1: Создайте экземпляр движка для подключения к SQLite базе данных в памяти.
Задача 2: Создайте сессию для взаимодействия с базой данных, используя созданный движок.
Задача 3: Определите модель продукта Product со следующими типами колонок:
id: числовой идентификаторname: строка (макс. 100 символов)price: числовое значение с фиксированной точностьюin_stock: логическое значение
Задача 4: Определите связанную модель категории Category со следующими типами колонок:
id: числовой идентификаторname: строка (макс. 100 символов)description: строка (макс. 255 символов)
Задача 5: Установите связь между таблицами Product и Category с помощью колонки category_id.
Подготовка окружения
Шаг 0: Создать папку проекта
# В терминале (PowerShell или CMD):
mkdir python-advanced-practice
cd python-advanced-practice
Шаг 1: Инициализировать git-репозиторий
git init
git checkout -b lesson/05-sqlalchemy-models
Шаг 2: Создать виртуальное окружение
# Создать venv в папке .venv
python -m venv .venv
# Активировать (Windows PowerShell):
.venv\Scripts\activate
# Активировать (Mac/Linux):
source .venv/bin/activate
(.venv).
Шаг 3: Установить зависимости
pip install sqlalchemy
# Зафиксировать зависимости
pip freeze > requirements.txt
Шаг 4: Создать .gitignore
# Создать файл .gitignore с содержимым:
.venv/
__pycache__/
*.pyc
*.db
Пошаговое решение
Создайте файл models.py в папке проекта. Ниже — полное решение с объяснением логики каждого шага.
Шаг 1: Импорты и создание движка (Задача 1)
Логика: движок — это точка подключения к БД. SQLite в памяти (:memory:) — самый простой вариант для учебных задач: не нужно создавать файл, данные исчезнут после завершения программы.
from sqlalchemy import create_engine, String, Boolean, ForeignKey
from sqlalchemy.types import Numeric
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship, Session
# Задача 1: движок для SQLite в памяти
# "sqlite:///:memory:" — три двоеточия, затем :memory:
engine = create_engine("sqlite:///:memory:", echo=True)
# echo=True — выводить в консоль SQL-запросы (полезно для обучения)
Шаг 2: Базовый класс и объявление моделей
Логика: DeclarativeBase — основа системы ORM. Все модели наследуют от Base. SQLAlchemy отслеживает все подклассы Base и знает, какие таблицы нужно создать.
# Базовый класс — от него наследуют все модели
class Base(DeclarativeBase):
pass
Шаг 3: Модель Category (Задача 4)
Логика: Category объявляем ПЕРВОЙ, потому что Product будет ссылаться на неё через ForeignKey. Хотя SQLAlchemy умеет разбираться с порядком, хорошая практика — объявлять «родительские» таблицы первыми.
# Задача 4: модель категории
class Category(Base):
__tablename__ = "categories" # имя таблицы в БД (обязательно)
id: Mapped[int] = mapped_column(primary_key=True)
# String(100) — VARCHAR(100) в SQL
name: Mapped[str] = mapped_column(String(100), nullable=False)
# description может быть пустым — nullable=True (по умолчанию)
description: Mapped[str | None] = mapped_column(String(255))
# Задача 5: обратная сторона связи
# Category.products — список всех продуктов этой категории
products: Mapped[list["Product"]] = relationship(back_populates="category")
def __repr__(self) -> str:
return f"Category(id={self.id}, name={self.name!r})"
Шаг 4: Модель Product с ForeignKey (Задачи 3 и 5)
Логика: Numeric(10, 2) — тип для денег с фиксированной точностью: 10 цифр всего, 2 после запятой. Это точнее, чем Float (который иногда теряет точность). ForeignKey указывает на столбец в другой таблице.
# Задача 3: модель продукта
class Product(Base):
__tablename__ = "products"
id: Mapped[int] = mapped_column(primary_key=True)
name: Mapped[str] = mapped_column(String(100), nullable=False)
# Задача 3: числовое значение с фиксированной точностью
# Numeric(10, 2): максимум 10 цифр, из них 2 после запятой
# Например: 12345678.99
price: Mapped[float] = mapped_column(Numeric(10, 2), default=0.00)
# Задача 3: логическое значение (True/False)
in_stock: Mapped[bool] = mapped_column(Boolean, default=True)
# Задача 5: внешний ключ — ссылка на id в таблице categories
# ВАЖНО: "categories.id" — имя ТАБЛИЦЫ (из __tablename__), не класса
category_id: Mapped[int | None] = mapped_column(ForeignKey("categories.id"))
# Задача 5: навигационная связь
# Product.category — объект Category (или None, если нет категории)
category: Mapped["Category | None"] = relationship(back_populates="products")
def __repr__(self) -> str:
return f"Product(id={self.id}, name={self.name!r}, price={self.price})"
Шаг 5: Создание таблиц и сессия (Задача 2)
Логика: create_all создаёт таблицы в БД по описанным моделям. Для SQLite в памяти это обязательно сделать ДО добавления данных. Сессия — это «единица работы»: набор операций, которые либо все выполняются, либо откатываются вместе.
# Создать все таблицы (categories и products)
Base.metadata.create_all(engine)
# Задача 2: создать сессию
# Рекомендуется использовать контекстный менеджер (with)
# чтобы сессия закрывалась автоматически
with Session(engine) as session:
# Создаём категории
electronics = Category(
name="Электроника",
description="Устройства и гаджеты"
)
food = Category(
name="Продукты",
description="Еда и напитки"
)
session.add_all([electronics, food])
# flush() — отправляет SQL в БД, но без COMMIT
# нужно, чтобы получить id категорий до создания продуктов
session.flush()
# Создаём продукты со ссылкой на категорию
products = [
Product(
name="Ноутбук",
price=55000.00,
in_stock=True,
category=electronics
),
Product(
name="Хлеб",
price=65.50,
in_stock=True,
category=food
),
Product(
name="Наушники",
price=8900.00,
in_stock=False,
category=electronics
),
]
session.add_all(products)
session.commit() # фиксируем всё в БД
print("Данные добавлены:")
for p in products:
cat_name = p.category.name if p.category else "—"
print(f" {p.name}: {p.price} руб., категория: {cat_name}, в наличии: {p.in_stock}")
Проверка в VS Code
Открыть проект
- Откройте VS Code.
- Меню File → Open Folder → выберите папку
python-advanced-practice. - VS Code предложит установить рекомендуемые расширения — нажмите Install All.
Выбрать интерпретатор
- Нажмите Ctrl+Shift+P → введите Python: Select Interpreter.
- Выберите интерпретатор из
.venv(он должен быть помечен как «Recommended»).
Запустить файл
Вариант 1 — через терминал:
# В терминале VS Code (Ctrl+`)
python models.py
Вариант 2 — через F5 (отладчик).
Настройка launch.json для отладки (F5)
Создайте файл .vscode/launch.json:
{
"version": "0.2.0",
"configurations": [
{
"name": "Python: models.py",
"type": "debugpy",
"request": "launch",
"program": "${workspaceFolder}/models.py",
"console": "integratedTerminal",
"env": {
"PYTHONPATH": "${workspaceFolder}"
}
}
]
}
После создания файла нажмите F5 — программа запустится в режиме отладки.
Точки останова (Breakpoints)
- Откройте
models.pyв VS Code. - Кликните на номер строки слева от кода — появится красная точка (breakpoint).
- Нажмите F5 — выполнение остановится на этой строке.
- В панели «Variables» (левая панель) можно смотреть значения переменных.
- F10 — шаг вперёд (Step Over). F11 — войти в функцию (Step Into). F5 — продолжить до следующего breakpoint.
Консоль отладки (Debug Console)
При остановке на breakpoint откройте вкладку Debug Console (снизу). Там можно вводить Python-выражения и видеть значения:
# В Debug Console (когда программа остановлена):
electronics.id # → 1
len(products) # → 3
products[0].name # → 'Ноутбук'
Типичные ошибки при выполнении ДЗ
Ошибка: ModuleNotFoundError: No module named 'sqlalchemy'
Причина: sqlalchemy не установлена или venv не активирован.
# Убедитесь, что venv активирован (должно быть (.venv) в строке)
.venv\Scripts\activate # Windows
source .venv/bin/activate # Mac/Linux
pip install sqlalchemy
Ошибка: OperationalError — no such table
Причина: забыли Base.metadata.create_all(engine) до сессии. Смотрите раздел ошибок.
Ошибка: ForeignKey не работает
Причина: в строке ForeignKey используется имя класса вместо имени таблицы. Правильно: ForeignKey("categories.id"), а не ForeignKey("Category.id").
Ошибка: price показывает много знаков после запятой
Причина: вы используете Float вместо Numeric(10, 2). Float — число с плавающей точкой (приблизительное), Numeric — точное десятичное число. Для денег всегда используйте Numeric.
# Неверно (может дать 65.4999999...)
price: Mapped[float] = mapped_column(Float)
# Верно (гарантированно 65.50)
from sqlalchemy.types import Numeric
price: Mapped[float] = mapped_column(Numeric(10, 2))
Как сдать задание
- Убедитесь, что
models.pyзапускается без ошибок. - Добавьте файлы в git и создайте коммит:
git add models.py requirements.txt .gitignore git commit -m "lesson 05: SQLAlchemy models — Product, Category, ForeignKey" - Загрузите на GitHub:
git push origin lesson/05-sqlalchemy-models - Скопируйте ссылку на репозиторий и вставьте в LMS как ответ на задание.