Отчёт по лабораторной работе №1: Реализация серверного приложения FastAPI
1. Цель работы
Целью данной работы является разработка асинхронного серверного приложения на фреймворке FastAPI для автоматизации организации хакатонов. В ходе работы решались задачи проектирования реляционной базы данных (6 таблиц), настройки асинхронного ORM-взаимодействия через SQLModel, реализации системы миграций Alembic, а также создания защищенного модуля аутентификации на базе JWT и хэширования паролей.
2. Стек технологий и структура проекта
При разработке использовались следующие инструменты: - Python 3.11+ и FastAPI. - SQLModel — гибрид SQLAlchemy и Pydantic для работы с БД. - PostgreSQL 15 + asyncpg (асинхронный драйвер). - Alembic — управление версиями схемы БД. - Adminer — веб-интерфейс для администрирования PostgreSQL. - Passlib (bcrypt) — хэширование паролей. - PyJWT (jose) — создание и валидация токенов. - Docker & Docker Compose — контейнеризация всей инфраструктуры.
3. Инфраструктура: Docker и Adminer
Для удобства разработки и соблюдения идентичности сред используется Docker Compose. В систему добавлен Adminer — легковесный инструмент для визуального контроля таблиц БД.
Фрагмент конфигурации docker-compose.yml:
services:
db:
image: postgres:15
container_name: hackathon_db
restart: always
environment:
POSTGRES_USER: ${POSTGRES_USER}
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_DB: ${POSTGRES_DB}
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
app:
build: .
container_name: hackathon_app
volumes:
- .:/code
ports:
- "8000:8000"
environment:
DATABASE_URL: postgresql+asyncpg://${POSTGRES_USER}:${POSTGRES_PASSWORD}@db:5432/${POSTGRES_DB}
depends_on:
- db
adminer:
container_name: adminer
image: adminer
restart: always
ports:
- "1000:8080"
С помощью Adminer производился визуальный контроль структуры таблиц и проверка корректности записи данных при выполнении CRUD-операций.

4. Модели данных (SQLModel)
Реализовано 6 взаимосвязанных таблиц. Выполнено требование по реализации ассоциативной сущности с дополнительным полем (role_in_team).
Ассоциативная сущность (M2M связь Участник <-> Команда):
class TeamUserLink(SQLModel, table=True):
team_id: Optional[int] = Field(default=None, foreign_key="team.id", primary_key=True)
user_id: Optional[int] = Field(default=None, foreign_key="user.id", primary_key=True)
# Дополнительное поле связи (Requirement)
role_in_team: str = Field(default="developer")
Связи One-to-Many (Хакатон <-> Задачи):
В моделях настроены обратные ссылки Relationship для автоматической навигации по объектам.
class Hackathon(HackathonBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
tasks: List["Task"] = Relationship(back_populates="hackathon")
class Task(TaskBase, table=True):
id: Optional[int] = Field(default=None, primary_key=True)
hackathon_id: int = Field(foreign_key="hackathon.id")
hackathon: Hackathon = Relationship(back_populates="tasks")
5. Миграции Alembic
Для асинхронной работы Alembic был настроен файл env.py, импортирующий метаданные SQLModel. Это позволило использовать команду --autogenerate для автоматического отслеживания изменений в классах Python.
История выполненных миграций:
Применение миграций фиксируется в системной таблице alembic_version, что позволяет откатывать базу к любому состоянию.

6. Аутентификация (Задание на 15 баллов)
Реализована полноценная система безопасности на базе JWT (JSON Web Tokens).
- Хэширование: Пароли не хранятся в открытом виде. Используется алгоритм
bcrypt. - JWT: Генерируется токен доступа, содержащий идентификатор пользователя (
sub) и время истечения (exp). - Защита эндпоинтов: Создана функция
get_current_user, которая выступает в роли зависимости (Dependency Injection) для защиты маршрутов.
Листинг создания токена (app/core/security.py):
def create_access_token(data: dict):
to_encode = data.copy()
expire = datetime.utcnow() + timedelta(minutes=settings.ACCESS_TOKEN_EXPIRE_MINUTES)
to_encode.update({"exp": expire})
return jwt.encode(to_encode, settings.SECRET_KEY, algorithm=settings.ALGORITHM)
7. API и вложенные объекты
Все CRUD-операции реализованы в асинхронном режиме с использованием await session.execute(). Реализована функциональность возвращения вложенных объектов (например, Хакатон со всеми его Задачами).
Запрос с подгрузкой зависимостей (app/api/hackathons.py):
@router.get("/{hackathon_id}", response_model=HackathonReadWithTasks)
async def get_hackathon(hackathon_id: int, session: AsyncSession = Depends(get_async_session)):
# selectinload используется для эффективной загрузки связанных данных
result = await session.execute(
select(Hackathon)
.where(Hackathon.id == hackathon_id)
.options(selectinload(Hackathon.tasks))
)
return result.scalar_one_or_none()
Автоматически сгенерированная документация Swagger позволяет тестировать все методы API, включая авторизацию через заголовок Bearer.

8. Выводы
В результате выполнения лабораторной работы создано масштабируемое серверное приложение. Основные итоги: - Спроектирована БД из 6 таблиц с поддержкой Many-to-Many и One-to-Many связей. - Настроена ассоциативная сущность с дополнительным полем роли. - Реализована надежная аутентификация через JWT и Bcrypt. - Обеспечено асинхронное взаимодействие с СУБД PostgreSQL. - Налажена система автоматических миграций Alembic и визуальный контроль через Adminer. - Весь проект упакован в Docker-контейнеры для быстрой развертки.