initial commit
This commit is contained in:
15
database/__init__.py
Normal file
15
database/__init__.py
Normal file
@@ -0,0 +1,15 @@
|
||||
"""Модуль для работы с базой данных"""
|
||||
from database.connection import get_session, async_session_maker, engine
|
||||
from database.models import User, Book, Author, Genre, Favorite
|
||||
|
||||
__all__ = [
|
||||
'get_session',
|
||||
'async_session_maker',
|
||||
'engine',
|
||||
'User',
|
||||
'Book',
|
||||
'Author',
|
||||
'Genre',
|
||||
'Favorite'
|
||||
]
|
||||
|
||||
22
database/connection.py
Normal file
22
database/connection.py
Normal file
@@ -0,0 +1,22 @@
|
||||
from sqlalchemy.ext.asyncio import create_async_engine, AsyncSession, async_sessionmaker
|
||||
from config import DATABASE_URL
|
||||
import logging
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
engine = create_async_engine(DATABASE_URL, echo=False, pool_pre_ping=True)
|
||||
async_session_maker = async_sessionmaker(engine, class_=AsyncSession, expire_on_commit=False)
|
||||
|
||||
|
||||
async def get_session() -> AsyncSession:
|
||||
"""Получить асинхронную сессию БД"""
|
||||
async with async_session_maker() as session:
|
||||
try:
|
||||
yield session
|
||||
except Exception as e:
|
||||
logger.error(f"Ошибка в сессии БД: {e}")
|
||||
await session.rollback()
|
||||
raise
|
||||
finally:
|
||||
await session.close()
|
||||
|
||||
95
database/models.py
Normal file
95
database/models.py
Normal file
@@ -0,0 +1,95 @@
|
||||
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")
|
||||
|
||||
Reference in New Issue
Block a user