mirror of
https://github.com/wowlikon/LiB.git
synced 2026-02-04 04:31:09 +00:00
Добавление выдач
This commit is contained in:
@@ -3,7 +3,7 @@ from typing import Optional
|
|||||||
|
|
||||||
# Конфигурация
|
# Конфигурация
|
||||||
USERNAME = "admin"
|
USERNAME = "admin"
|
||||||
PASSWORD = "n_ElBL9LTfTTgZSqHShqOg"
|
PASSWORD = "7WaVlcj8EWzEbbdab9kqRw"
|
||||||
BASE_URL = "http://localhost:8000"
|
BASE_URL = "http://localhost:8000"
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
"""Модуль моделей"""
|
"""Модуль моделей"""
|
||||||
from .db import *
|
from .db import *
|
||||||
from .dto import *
|
from .dto import *
|
||||||
|
from .enums import *
|
||||||
@@ -5,6 +5,7 @@ from sqlmodel import Field, Relationship
|
|||||||
|
|
||||||
from library_service.models.dto.book import BookBase
|
from library_service.models.dto.book import BookBase
|
||||||
from library_service.models.db.links import AuthorBookLink, GenreBookLink
|
from library_service.models.db.links import AuthorBookLink, GenreBookLink
|
||||||
|
from library_service.models.enums import BookStatus
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
if TYPE_CHECKING:
|
||||||
from .author import Author
|
from .author import Author
|
||||||
@@ -14,9 +15,11 @@ if TYPE_CHECKING:
|
|||||||
class Book(BookBase, table=True):
|
class Book(BookBase, table=True):
|
||||||
"""Модель книги в базе данных"""
|
"""Модель книги в базе данных"""
|
||||||
id: int | None = Field(default=None, primary_key=True, index=True)
|
id: int | None = Field(default=None, primary_key=True, index=True)
|
||||||
|
status: BookStatus = Field(default=BookStatus.ACTIVE)
|
||||||
authors: List["Author"] = Relationship(
|
authors: List["Author"] = Relationship(
|
||||||
back_populates="books", link_model=AuthorBookLink
|
back_populates="books", link_model=AuthorBookLink
|
||||||
)
|
)
|
||||||
genres: List["Genre"] = Relationship(
|
genres: List["Genre"] = Relationship(
|
||||||
back_populates="books", link_model=GenreBookLink
|
back_populates="books", link_model=GenreBookLink
|
||||||
)
|
)
|
||||||
|
loans: List["BookUserLink"] = Relationship(sa_relationship_kwargs={"cascade": "all, delete"})
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
"""Модуль связей между сущностями в БД"""
|
"""Модуль связей между сущностями в БД"""
|
||||||
|
from datetime import datetime
|
||||||
from sqlmodel import SQLModel, Field
|
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)
|
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)
|
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)
|
||||||
@@ -26,3 +26,4 @@ class User(UserBase, table=True):
|
|||||||
|
|
||||||
# Связи
|
# Связи
|
||||||
roles: List["Role"] = Relationship(back_populates="users", link_model=UserRoleLink)
|
roles: List["Role"] = Relationship(back_populates="users", link_model=UserRoleLink)
|
||||||
|
loans: List["BookUserLink"] = Relationship(sa_relationship_kwargs={"cascade": "all, delete"})
|
||||||
|
|||||||
@@ -4,9 +4,10 @@ from .genre import GenreBase, GenreCreate, GenreList, GenreRead, GenreUpdate
|
|||||||
from .book import BookBase, BookCreate, BookList, BookRead, BookUpdate
|
from .book import BookBase, BookCreate, BookList, BookRead, BookUpdate
|
||||||
from .role import RoleBase, RoleCreate, RoleList, RoleRead, RoleUpdate
|
from .role import RoleBase, RoleCreate, RoleList, RoleRead, RoleUpdate
|
||||||
from .user import UserBase, UserCreate, UserList, UserRead, UserUpdate, UserLogin
|
from .user import UserBase, UserCreate, UserList, UserRead, UserUpdate, UserLogin
|
||||||
|
from .loan import LoanBase, LoanCreate, LoanList, LoanRead, LoanUpdate
|
||||||
from .token import Token, TokenData
|
from .token import Token, TokenData
|
||||||
from .combined import (AuthorWithBooks, GenreWithBooks, BookWithAuthors, BookWithGenres,
|
from .combined import (AuthorWithBooks, GenreWithBooks, BookWithAuthors, BookWithGenres,
|
||||||
BookWithAuthorsAndGenres, BookFilteredList)
|
BookWithAuthorsAndGenres, BookFilteredList, BookStatusUpdate, LoanWithBook)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
"AuthorBase",
|
"AuthorBase",
|
||||||
@@ -20,11 +21,24 @@ __all__ = [
|
|||||||
"BookRead",
|
"BookRead",
|
||||||
"BookList",
|
"BookList",
|
||||||
"BookFilteredList",
|
"BookFilteredList",
|
||||||
|
"BookStatusUpdate",
|
||||||
"GenreBase",
|
"GenreBase",
|
||||||
"GenreCreate",
|
"GenreCreate",
|
||||||
"GenreUpdate",
|
"GenreUpdate",
|
||||||
"GenreRead",
|
"GenreRead",
|
||||||
"GenreList",
|
"GenreList",
|
||||||
|
"LoanBase",
|
||||||
|
"LoanCreate",
|
||||||
|
"LoanUpdate",
|
||||||
|
"LoanRead",
|
||||||
|
"LoanList",
|
||||||
|
"LoanWithBook",
|
||||||
|
"UserBase",
|
||||||
|
"UserCreate",
|
||||||
|
"UserUpdate",
|
||||||
|
"UserRead",
|
||||||
|
"UserList",
|
||||||
|
"UserLogin",
|
||||||
"RoleBase",
|
"RoleBase",
|
||||||
"RoleCreate",
|
"RoleCreate",
|
||||||
"RoleUpdate",
|
"RoleUpdate",
|
||||||
@@ -32,10 +46,4 @@ __all__ = [
|
|||||||
"RoleList",
|
"RoleList",
|
||||||
"Token",
|
"Token",
|
||||||
"TokenData",
|
"TokenData",
|
||||||
"UserBase",
|
|
||||||
"UserCreate",
|
|
||||||
"UserRead",
|
|
||||||
"UserUpdate",
|
|
||||||
"UserList",
|
|
||||||
"UserLogin",
|
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,11 +1,10 @@
|
|||||||
"""Модуль DTO-моделей книг"""
|
"""Модуль DTO-моделей книг"""
|
||||||
from typing import List, TYPE_CHECKING
|
from typing import List
|
||||||
|
|
||||||
from pydantic import ConfigDict
|
from pydantic import ConfigDict
|
||||||
from sqlmodel import SQLModel
|
from sqlmodel import SQLModel
|
||||||
|
|
||||||
if TYPE_CHECKING:
|
from library_service.models.enums import BookStatus
|
||||||
from .combined import BookWithAuthorsAndGenres
|
|
||||||
|
|
||||||
|
|
||||||
class BookBase(SQLModel):
|
class BookBase(SQLModel):
|
||||||
@@ -29,11 +28,13 @@ class BookUpdate(SQLModel):
|
|||||||
"""Модель книги для обновления"""
|
"""Модель книги для обновления"""
|
||||||
title: str | None = None
|
title: str | None = None
|
||||||
description: str | None = None
|
description: str | None = None
|
||||||
|
status: BookStatus | None = None
|
||||||
|
|
||||||
|
|
||||||
class BookRead(BookBase):
|
class BookRead(BookBase):
|
||||||
"""Модель книги для чтения"""
|
"""Модель книги для чтения"""
|
||||||
id: int
|
id: int
|
||||||
|
status: BookStatus
|
||||||
|
|
||||||
|
|
||||||
class BookList(SQLModel):
|
class BookList(SQLModel):
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ from sqlmodel import SQLModel, Field
|
|||||||
from .author import AuthorRead
|
from .author import AuthorRead
|
||||||
from .genre import GenreRead
|
from .genre import GenreRead
|
||||||
from .book import BookRead
|
from .book import BookRead
|
||||||
|
from .loan import LoanRead
|
||||||
|
|
||||||
|
|
||||||
class AuthorWithBooks(SQLModel):
|
class AuthorWithBooks(SQLModel):
|
||||||
@@ -50,3 +51,11 @@ class BookFilteredList(SQLModel):
|
|||||||
"""Список книг с фильтрацией"""
|
"""Список книг с фильтрацией"""
|
||||||
books: List[BookWithAuthorsAndGenres]
|
books: List[BookWithAuthorsAndGenres]
|
||||||
total: int
|
total: int
|
||||||
|
|
||||||
|
class LoanWithBook(LoanRead):
|
||||||
|
"""Модель выдачи, включающая данные о книге"""
|
||||||
|
book: BookRead
|
||||||
|
|
||||||
|
class BookStatusUpdate(SQLModel):
|
||||||
|
"""Модель для ручного изменения статуса библиотекарем"""
|
||||||
|
status: str
|
||||||
@@ -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
|
||||||
@@ -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"
|
||||||
@@ -20,6 +20,7 @@ if config.config_file_name is not None:
|
|||||||
|
|
||||||
# add your model's MetaData object here
|
# add your model's MetaData object here
|
||||||
# for 'autogenerate' support
|
# for 'autogenerate' support
|
||||||
|
from library_service.models.enums import *
|
||||||
from library_service.models.db import *
|
from library_service.models.db import *
|
||||||
|
|
||||||
target_metadata = SQLModel.metadata
|
target_metadata = SQLModel.metadata
|
||||||
|
|||||||
@@ -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,4 +1,4 @@
|
|||||||
"""genres
|
"""Genres
|
||||||
|
|
||||||
Revision ID: 9d7a43ac5dfc
|
Revision ID: 9d7a43ac5dfc
|
||||||
Revises: d266fdc61e99
|
Revises: d266fdc61e99
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""auth
|
"""Auth
|
||||||
|
|
||||||
Revision ID: b838606ad8d1
|
Revision ID: b838606ad8d1
|
||||||
Revises: 9d7a43ac5dfc
|
Revises: 9d7a43ac5dfc
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
"""init
|
"""Init
|
||||||
|
|
||||||
Revision ID: d266fdc61e99
|
Revision ID: d266fdc61e99
|
||||||
Revises:
|
Revises:
|
||||||
|
|||||||
Reference in New Issue
Block a user