"""Модель UserBackground — своя картинка пользователя для замены фона видео. В БД хранится только путь к файлу относительно `MEDIA_ROOT` (`backgrounds/{user_id}/{background_id}.{ext}`) — ровно тот же приём, что и у аватаров (`users.avatar_path`, `services/avatars.py`): «чтобы не грузили БД» (требование оператора). Сами файлы лежат на диске в томе `media`, который nginx раздаёт напрямую по `location /media/`. Лимит на число картинок (`MAX_BACKGROUNDS_PER_USER`) проверяется в сервисе, а не ограничением БД: он про политику продукта, а не про целостность данных, и администратор может захотеть его поменять. """ import uuid from datetime import datetime from sqlalchemy import DateTime, ForeignKey, Index, String, func, text from sqlalchemy.dialects.postgresql import UUID from sqlalchemy.orm import Mapped, mapped_column from models.base import Base class UserBackground(Base): """Загруженная пользователем картинка фона.""" __tablename__ = "user_backgrounds" __table_args__ = ( # Выборка всегда одна и та же — «все фоны этого пользователя, свежие # сверху» (`services/backgrounds.py::list_backgrounds`), и она же # считает лимит при загрузке. Index("ix_user_backgrounds_user_created", "user_id", "created_at"), ) id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), primary_key=True, server_default=text("gen_random_uuid()") ) user_id: Mapped[uuid.UUID] = mapped_column( UUID(as_uuid=True), ForeignKey("users.id", ondelete="CASCADE"), nullable=False ) # Путь относительно `MEDIA_ROOT`: `backgrounds/{user_id}/{id}.{ext}`. path: Mapped[str] = mapped_column(String(512), nullable=False) created_at: Mapped[datetime] = mapped_column( DateTime(timezone=True), nullable=False, server_default=func.now() )