from sqlalchemy import BigInteger, String, Text, Numeric, Integer, DateTime, Boolean, ForeignKey, Table, Column from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship from datetime import datetime from typing import Optional, List class Base(DeclarativeBase): pass # Many-to-Many таблицы books_book_authors = Table( 'books_book_authors', Base.metadata, Column('id', Integer, primary_key=True), Column('book_id', Integer, ForeignKey('books_book.id')), Column('author_id', Integer, ForeignKey('books_author.id')) ) books_book_genres = Table( 'books_book_genres', Base.metadata, Column('id', Integer, primary_key=True), Column('book_id', Integer, ForeignKey('books_book.id')), Column('genre_id', Integer, ForeignKey('books_genre.id')) ) class User(Base): __tablename__ = 'auth_user' id: Mapped[int] = mapped_column(Integer, primary_key=True) username: Mapped[str] = mapped_column(String(150), unique=True) email: Mapped[str] = mapped_column(String(254), unique=True) password: Mapped[str] = mapped_column(String(128)) telegram_id: Mapped[Optional[int]] = mapped_column(BigInteger, unique=True, nullable=True) first_name: Mapped[Optional[str]] = mapped_column(String(150), nullable=True) last_name: Mapped[Optional[str]] = mapped_column(String(150), nullable=True) is_active: Mapped[bool] = mapped_column(Boolean, default=True) is_staff: Mapped[bool] = mapped_column(Boolean, default=False) is_superuser: Mapped[bool] = mapped_column(Boolean, default=False) date_joined: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) last_login: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True) favorites: Mapped[List["Favorite"]] = relationship(back_populates="user") class Author(Base): __tablename__ = 'books_author' id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(255)) books: Mapped[List["Book"]] = relationship(secondary=books_book_authors, back_populates="authors") class Genre(Base): __tablename__ = 'books_genre' id: Mapped[int] = mapped_column(Integer, primary_key=True) name: Mapped[str] = mapped_column(String(100)) books: Mapped[List["Book"]] = relationship(secondary=books_book_genres, back_populates="genres") class Book(Base): __tablename__ = 'books_book' id: Mapped[int] = mapped_column(Integer, primary_key=True) title: Mapped[str] = mapped_column(String(500)) description: Mapped[Optional[str]] = mapped_column(Text, nullable=True) cover_url: Mapped[Optional[str]] = mapped_column(String(500), nullable=True) average_rating: Mapped[Optional[float]] = mapped_column(Numeric(3, 2), nullable=True) rating_count: Mapped[int] = mapped_column(Integer, default=0) language: Mapped[Optional[str]] = mapped_column(String(10), nullable=True) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) updated_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow, onupdate=datetime.utcnow) deleted_at: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True) authors: Mapped[List[Author]] = relationship(secondary=books_book_authors, back_populates="books") genres: Mapped[List[Genre]] = relationship(secondary=books_book_genres, back_populates="books") favorites: Mapped[List["Favorite"]] = relationship(back_populates="book") class Favorite(Base): __tablename__ = 'books_favorite' id: Mapped[int] = mapped_column(Integer, primary_key=True) user_id: Mapped[int] = mapped_column(Integer, ForeignKey('auth_user.id')) book_id: Mapped[int] = mapped_column(Integer, ForeignKey('books_book.id')) created_at: Mapped[datetime] = mapped_column(DateTime, default=datetime.utcnow) user: Mapped[User] = relationship(back_populates="favorites") book: Mapped[Book] = relationship(back_populates="favorites")