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"
|
||||
PASSWORD = "n_ElBL9LTfTTgZSqHShqOg"
|
||||
PASSWORD = "7WaVlcj8EWzEbbdab9kqRw"
|
||||
BASE_URL = "http://localhost:8000"
|
||||
|
||||
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
"""Модуль моделей"""
|
||||
from .db 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.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"})
|
||||
|
||||
@@ -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)
|
||||
@@ -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"})
|
||||
|
||||
@@ -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",
|
||||
]
|
||||
|
||||
@@ -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):
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
# for 'autogenerate' support
|
||||
from library_service.models.enums import *
|
||||
from library_service.models.db import *
|
||||
|
||||
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
|
||||
Revises: d266fdc61e99
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""auth
|
||||
"""Auth
|
||||
|
||||
Revision ID: b838606ad8d1
|
||||
Revises: 9d7a43ac5dfc
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
"""init
|
||||
"""Init
|
||||
|
||||
Revision ID: d266fdc61e99
|
||||
Revises:
|
||||
|
||||
Reference in New Issue
Block a user