from sqlalchemy import BigInteger, String, Text, Numeric, Integer, DateTime, Boolean, ForeignKey, Table, Column, Date from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship from datetime import datetime, date from typing import Optional, List class Base(DeclarativeBase): pass # Many-to-Many таблицы books_book_authors = Table( 'books_book_authors', Base.metadata, Column('id', BigInteger, primary_key=True), Column('book_id', BigInteger, ForeignKey('books_book.id')), Column('author_id', BigInteger, ForeignKey('books_author.id')) ) books_book_genres = Table( 'books_book_genres', Base.metadata, Column('id', BigInteger, primary_key=True), Column('book_id', BigInteger, ForeignKey('books_book.id')), Column('genre_id', BigInteger, ForeignKey('books_genre.id')) ) # Many-to-Many для любимых жанров пользователя users_user_favorite_genres = Table( 'users_user_favorite_genres', Base.metadata, Column('id', BigInteger, primary_key=True), Column('user_id', BigInteger, ForeignKey('users_user.id')), Column('genre_id', BigInteger, ForeignKey('books_genre.id')) ) class User(Base): """ Модель пользователя из Django приложения 'users' Таблица: users_user """ __tablename__ = 'users_user' # Стандартные поля Django AbstractUser id: Mapped[int] = mapped_column(BigInteger, primary_key=True) password: Mapped[str] = mapped_column(String(128)) last_login: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True) is_superuser: Mapped[bool] = mapped_column(Boolean, default=False) username: Mapped[str] = mapped_column(String(150), unique=True) first_name: Mapped[str] = mapped_column(String(150), default='') last_name: Mapped[str] = mapped_column(String(150), default='') email: Mapped[str] = mapped_column(String(254), unique=True) is_staff: Mapped[bool] = mapped_column(Boolean, default=False) is_active: Mapped[bool] = mapped_column(Boolean, default=True) date_joined: Mapped[datetime] = mapped_column(DateTime) # Дополнительные поля из модели users.User phone: Mapped[str] = mapped_column(String(20), default='') avatar: Mapped[Optional[str]] = mapped_column(String(100), nullable=True) birth_date: Mapped[Optional[date]] = mapped_column(Date, nullable=True) about: Mapped[str] = mapped_column(Text, default='') telegram_id: Mapped[Optional[int]] = mapped_column(BigInteger, unique=True, nullable=True) is_verified: Mapped[bool] = mapped_column(Boolean, default=False) last_activity: Mapped[Optional[datetime]] = mapped_column(DateTime, nullable=True) # Relationships favorites: Mapped[List["Favorite"]] = relationship(back_populates="user") favorite_genres: Mapped[List["Genre"]] = relationship( secondary=users_user_favorite_genres, back_populates="users" ) class Author(Base): __tablename__ = 'books_author' id: Mapped[int] = mapped_column(BigInteger, 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(BigInteger, primary_key=True) name: Mapped[str] = mapped_column(String(100)) books: Mapped[List["Book"]] = relationship(secondary=books_book_genres, back_populates="genres") users: Mapped[List[User]] = relationship( secondary=users_user_favorite_genres, back_populates="favorite_genres" ) class Book(Base): __tablename__ = 'books_book' id: Mapped[int] = mapped_column(BigInteger, 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) updated_at: Mapped[datetime] = mapped_column(DateTime) 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(BigInteger, primary_key=True) user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey('users_user.id')) book_id: Mapped[int] = mapped_column(BigInteger, ForeignKey('books_book.id')) created_at: Mapped[datetime] = mapped_column(DateTime) user: Mapped[User] = relationship(back_populates="favorites") book: Mapped[Book] = relationship(back_populates="favorites") class UserPreferences(Base): """ Настройки пользователя из Django приложения 'users' Таблица: users_userpreferences """ __tablename__ = 'users_userpreferences' id: Mapped[int] = mapped_column(BigInteger, primary_key=True) user_id: Mapped[int] = mapped_column(BigInteger, ForeignKey('users_user.id'), unique=True) created_at: Mapped[datetime] = mapped_column(DateTime) updated_at: Mapped[datetime] = mapped_column(DateTime) language: Mapped[str] = mapped_column(String(10), default='ru') theme: Mapped[str] = mapped_column(String(20), default='light') email_notifications: Mapped[bool] = mapped_column(Boolean, default=True) telegram_notifications: Mapped[bool] = mapped_column(Boolean, default=False) show_email: Mapped[bool] = mapped_column(Boolean, default=False) show_phone: Mapped[bool] = mapped_column(Boolean, default=False)