Добавление выдач

This commit is contained in:
2025-12-20 11:06:13 +03:00
parent 3473c31f73
commit 09b7cb17a5
16 changed files with 153 additions and 15 deletions
+1 -1
View File
@@ -3,7 +3,7 @@ from typing import Optional
# Конфигурация
USERNAME = "admin"
PASSWORD = "n_ElBL9LTfTTgZSqHShqOg"
PASSWORD = "7WaVlcj8EWzEbbdab9kqRw"
BASE_URL = "http://localhost:8000"
+1
View File
@@ -1,3 +1,4 @@
"""Модуль моделей"""
from .db import *
from .dto import *
from .enums import *
+3
View File
@@ -5,6 +5,7 @@ from sqlmodel import Field, Relationship
from library_service.models.dto.book import BookBase
from library_service.models.db.links import AuthorBookLink, GenreBookLink
from library_service.models.enums import BookStatus
if TYPE_CHECKING:
from .author import Author
@@ -14,9 +15,11 @@ if TYPE_CHECKING:
class Book(BookBase, table=True):
"""Модель книги в базе данных"""
id: int | None = Field(default=None, primary_key=True, index=True)
status: BookStatus = Field(default=BookStatus.ACTIVE)
authors: List["Author"] = Relationship(
back_populates="books", link_model=AuthorBookLink
)
genres: List["Genre"] = Relationship(
back_populates="books", link_model=GenreBookLink
)
loans: List["BookUserLink"] = Relationship(sa_relationship_kwargs={"cascade": "all, delete"})
+18
View File
@@ -1,4 +1,5 @@
"""Модуль связей между сущностями в БД"""
from datetime import datetime
from sqlmodel import SQLModel, Field
@@ -22,3 +23,20 @@ class UserRoleLink(SQLModel, table=True):
user_id: int | None = Field(default=None, foreign_key="users.id", primary_key=True)
role_id: int | None = Field(default=None, foreign_key="roles.id", primary_key=True)
class BookUserLink(SQLModel, table=True):
"""
Модель истории выдачи книг (Loan).
Связывает книгу и пользователя с фиксацией времени.
"""
__tablename__ = "book_loans"
id: int | None = Field(default=None, primary_key=True, index=True)
book_id: int = Field(foreign_key="book.id")
user_id: int = Field(foreign_key="users.id")
borrowed_at: datetime = Field(default_factory=datetime.utcnow)
due_date: datetime
returned_at: datetime | None = Field(default=None)
+1
View File
@@ -26,3 +26,4 @@ class User(UserBase, table=True):
# Связи
roles: List["Role"] = Relationship(back_populates="users", link_model=UserRoleLink)
loans: List["BookUserLink"] = Relationship(sa_relationship_kwargs={"cascade": "all, delete"})
+15 -7
View File
@@ -4,9 +4,10 @@ from .genre import GenreBase, GenreCreate, GenreList, GenreRead, GenreUpdate
from .book import BookBase, BookCreate, BookList, BookRead, BookUpdate
from .role import RoleBase, RoleCreate, RoleList, RoleRead, RoleUpdate
from .user import UserBase, UserCreate, UserList, UserRead, UserUpdate, UserLogin
from .loan import LoanBase, LoanCreate, LoanList, LoanRead, LoanUpdate
from .token import Token, TokenData
from .combined import (AuthorWithBooks, GenreWithBooks, BookWithAuthors, BookWithGenres,
BookWithAuthorsAndGenres, BookFilteredList)
BookWithAuthorsAndGenres, BookFilteredList, BookStatusUpdate, LoanWithBook)
__all__ = [
"AuthorBase",
@@ -20,11 +21,24 @@ __all__ = [
"BookRead",
"BookList",
"BookFilteredList",
"BookStatusUpdate",
"GenreBase",
"GenreCreate",
"GenreUpdate",
"GenreRead",
"GenreList",
"LoanBase",
"LoanCreate",
"LoanUpdate",
"LoanRead",
"LoanList",
"LoanWithBook",
"UserBase",
"UserCreate",
"UserUpdate",
"UserRead",
"UserList",
"UserLogin",
"RoleBase",
"RoleCreate",
"RoleUpdate",
@@ -32,10 +46,4 @@ __all__ = [
"RoleList",
"Token",
"TokenData",
"UserBase",
"UserCreate",
"UserRead",
"UserUpdate",
"UserList",
"UserLogin",
]
+4 -3
View File
@@ -1,11 +1,10 @@
"""Модуль DTO-моделей книг"""
from typing import List, TYPE_CHECKING
from typing import List
from pydantic import ConfigDict
from sqlmodel import SQLModel
if TYPE_CHECKING:
from .combined import BookWithAuthorsAndGenres
from library_service.models.enums import BookStatus
class BookBase(SQLModel):
@@ -29,11 +28,13 @@ class BookUpdate(SQLModel):
"""Модель книги для обновления"""
title: str | None = None
description: str | None = None
status: BookStatus | None = None
class BookRead(BookBase):
"""Модель книги для чтения"""
id: int
status: BookStatus
class BookList(SQLModel):
+9
View File
@@ -5,6 +5,7 @@ from sqlmodel import SQLModel, Field
from .author import AuthorRead
from .genre import GenreRead
from .book import BookRead
from .loan import LoanRead
class AuthorWithBooks(SQLModel):
@@ -50,3 +51,11 @@ class BookFilteredList(SQLModel):
"""Список книг с фильтрацией"""
books: List[BookWithAuthorsAndGenres]
total: int
class LoanWithBook(LoanRead):
"""Модель выдачи, включающая данные о книге"""
book: BookRead
class BookStatusUpdate(SQLModel):
"""Модель для ручного изменения статуса библиотекарем"""
status: str
+35
View File
@@ -0,0 +1,35 @@
"""Модуль DTO-моделей для выдачи книг"""
from typing import List
from datetime import datetime
from sqlmodel import SQLModel
class LoanBase(SQLModel):
"""Базовая модель выдачи"""
book_id: int
user_id: int
due_date: datetime
class LoanCreate(LoanBase):
"""Модель для создания записи о выдаче"""
pass
class LoanUpdate(SQLModel):
"""Модель для обновления записи о выдаче"""
returned_at: datetime | None = None
class LoanRead(LoanBase):
"""Модель чтения записи о выдаче"""
id: int
borrowed_at: datetime
returned_at: datetime | None = None
class LoanList(SQLModel):
"""Список выдач"""
loans: List[LoanRead]
total: int
+10
View File
@@ -0,0 +1,10 @@
"""Модуль перечислений (Enums)"""
from enum import Enum
class BookStatus(str, Enum):
"""Статусы книги"""
ACTIVE = "active"
BORROWED = "borrowed"
RESERVED = "reserved"
RESTORATION = "restoration"
WRITTEN_OFF = "written_off"
+1
View File
@@ -20,6 +20,7 @@ if config.config_file_name is not None:
# add your model's MetaData object here
# for 'autogenerate' support
from library_service.models.enums import *
from library_service.models.db import *
target_metadata = SQLModel.metadata
+51
View File
@@ -0,0 +1,51 @@
"""Loans
Revision ID: 02ed6e775351
Revises: b838606ad8d1
Create Date: 2025-12-20 10:36:30.853896
"""
from typing import Sequence, Union
from alembic import op
import sqlalchemy as sa
import sqlmodel
# revision identifiers, used by Alembic.
revision: str = '02ed6e775351'
down_revision: Union[str, None] = 'b838606ad8d1'
branch_labels: Union[str, Sequence[str], None] = None
depends_on: Union[str, Sequence[str], None] = None
def upgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
book_status_enum = sa.Enum('active', 'borrowed', 'reserved', 'restoration', 'written_off', name='bookstatus')
book_status_enum.create(op.get_bind())
op.create_table('book_loans',
sa.Column('id', sa.Integer(), nullable=False),
sa.Column('book_id', sa.Integer(), nullable=False),
sa.Column('user_id', sa.Integer(), nullable=False),
sa.Column('borrowed_at', sa.DateTime(), nullable=False),
sa.Column('due_date', sa.DateTime(), nullable=False),
sa.Column('returned_at', sa.DateTime(), nullable=True),
sa.ForeignKeyConstraint(['book_id'], ['book.id'], ),
sa.ForeignKeyConstraint(['user_id'], ['users.id'], ),
sa.PrimaryKeyConstraint('id')
)
op.create_index(op.f('ix_book_loans_id'), 'book_loans', ['id'], unique=False)
op.add_column('book', sa.Column('status', book_status_enum, nullable=False, server_default='active'))
op.drop_index(op.f('ix_roles_name'), table_name='roles')
# ### end Alembic commands ###
def downgrade() -> None:
# ### commands auto generated by Alembic - please adjust! ###
op.create_index(op.f('ix_roles_name'), 'roles', ['name'], unique=True)
op.drop_column('book', 'status')
op.drop_index(op.f('ix_book_loans_id'), table_name='book_loans')
op.drop_table('book_loans')
book_status_enum = sa.Enum('active', 'borrowed', 'reserved', 'restoration', 'written_off', name='bookstatus')
book_status_enum.drop(op.get_bind())
# ### end Alembic commands ###
+1 -1
View File
@@ -1,4 +1,4 @@
"""genres
"""Genres
Revision ID: 9d7a43ac5dfc
Revises: d266fdc61e99
+1 -1
View File
@@ -1,4 +1,4 @@
"""auth
"""Auth
Revision ID: b838606ad8d1
Revises: 9d7a43ac5dfc
+1 -1
View File
@@ -1,4 +1,4 @@
"""init
"""Init
Revision ID: d266fdc61e99
Revises: