From 7c3074e8fec4edd5c446bdf2abf407ca752732cc Mon Sep 17 00:00:00 2001
From: wowlikon
Date: Fri, 23 Jan 2026 01:31:50 +0300
Subject: [PATCH] =?UTF-8?q?=D0=94=D0=BE=D0=B1=D0=B0=D0=B2=D0=BB=D0=B5?=
=?UTF-8?q?=D0=BD=D0=B8=D0=B5=20=D0=BA=D0=BE=D0=BB=D0=B8=D1=87=D0=B5=D1=81?=
=?UTF-8?q?=D1=82=D0=B2=D0=B0=20=D1=81=D1=82=D1=80=D0=B0=D0=BD=D0=B8=D1=86?=
=?UTF-8?q?=20=D0=BA=D0=BD=D0=B8=D0=B3=D0=B0=D0=BC?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
---
.env | 2 +-
library_service/models/dto/book.py | 16 +++++-
library_service/models/dto/misc.py | 3 ++
library_service/static/page/book.js | 6 +++
library_service/static/page/books.js | 5 ++
library_service/static/page/create_book.js | 7 +++
library_service/static/page/edit_book.js | 4 ++
library_service/static/utils.js | 4 +-
library_service/templates/book.html | 4 ++
library_service/templates/books.html | 4 ++
library_service/templates/create_book.html | 16 ++++++
library_service/templates/edit_book.html | 17 +++++++
.../a585fd97b88c_recovery_codes_and_totp.py | 2 +-
.../versions/a8e40ab24138_role_payroll.py | 51 +++++++++++++------
.../versions/c5dfc16bdc66_book_page_count.py | 32 ++++++++++++
15 files changed, 152 insertions(+), 21 deletions(-)
create mode 100644 migrations/versions/c5dfc16bdc66_book_page_count.py
diff --git a/.env b/.env
index 7dd5499..824cbba 100644
--- a/.env
+++ b/.env
@@ -1,5 +1,5 @@
# Postgres
-POSTGRES_HOST="db"
+POSTGRES_HOST="localhost"
POSTGRES_PORT="5432"
POSTGRES_USER="postgres"
POSTGRES_PASSWORD="postgres"
diff --git a/library_service/models/dto/book.py b/library_service/models/dto/book.py
index 514ad4f..e06b485 100644
--- a/library_service/models/dto/book.py
+++ b/library_service/models/dto/book.py
@@ -1,43 +1,55 @@
"""Модуль DTO-моделей книг"""
+
from typing import List
from pydantic import ConfigDict
-from sqlmodel import SQLModel
+from sqlmodel import SQLModel, Field
from library_service.models.enums import BookStatus
class BookBase(SQLModel):
"""Базовая модель книги"""
+
title: str
description: str
+ page_count: int = Field(gt=0)
model_config = ConfigDict( # pyright: ignore
json_schema_extra={
- "example": {"title": "book_title", "description": "book_description"}
+ "example": {
+ "title": "book_title",
+ "description": "book_description",
+ "page_count": 1,
+ }
}
)
class BookCreate(BookBase):
"""Модель книги для создания"""
+
pass
class BookUpdate(SQLModel):
"""Модель книги для обновления"""
+
title: str | None = None
description: str | None = None
+ page_count: int | None = None
status: BookStatus | None = None
class BookRead(BookBase):
"""Модель книги для чтения"""
+
id: int
status: BookStatus
class BookList(SQLModel):
"""Список книг"""
+
books: List[BookRead]
total: int
diff --git a/library_service/models/dto/misc.py b/library_service/models/dto/misc.py
index d859a97..dcbd7c5 100644
--- a/library_service/models/dto/misc.py
+++ b/library_service/models/dto/misc.py
@@ -37,6 +37,7 @@ class BookWithAuthors(SQLModel):
id: int
title: str
description: str
+ page_count: int
authors: List[AuthorRead] = Field(default_factory=list)
@@ -46,6 +47,7 @@ class BookWithGenres(SQLModel):
id: int
title: str
description: str
+ page_count: int
status: BookStatus | None = None
genres: List[GenreRead] = Field(default_factory=list)
@@ -56,6 +58,7 @@ class BookWithAuthorsAndGenres(SQLModel):
id: int
title: str
description: str
+ page_count: int
status: BookStatus | None = None
authors: List[AuthorRead] = Field(default_factory=list)
genres: List[GenreRead] = Field(default_factory=list)
diff --git a/library_service/static/page/book.js b/library_service/static/page/book.js
index 899b1a3..ef4145a 100644
--- a/library_service/static/page/book.js
+++ b/library_service/static/page/book.js
@@ -234,6 +234,12 @@ $(document).ready(() => {
function renderBook(book) {
$("#book-title").text(book.title);
$("#book-id").text(`ID: ${book.id}`);
+ if (book.page_count && book.page_count > 0) {
+ $("#book-page-count-value").text(book.page_count);
+ $("#book-page-count-text").removeClass("hidden");
+ } else {
+ $("#book-page-count-text").addClass("hidden");
+ }
$("#book-authors-text").text(
book.authors.map((a) => a.name).join(", ") || "Автор неизвестен",
);
diff --git a/library_service/static/page/books.js b/library_service/static/page/books.js
index 9f67490..2fef73f 100644
--- a/library_service/static/page/books.js
+++ b/library_service/static/page/books.js
@@ -180,6 +180,11 @@ $(document).ready(() => {
clone.querySelector(".book-title").textContent = book.title;
clone.querySelector(".book-authors").textContent =
book.authors.map((a) => a.name).join(", ") || "Автор неизвестен";
+ if (book.page_count && book.page_count > 0) {
+ const pageEl = clone.querySelector(".book-page-count");
+ pageEl.querySelector(".page-count-value").textContent = book.page_count;
+ pageEl.classList.remove("hidden");
+ }
clone.querySelector(".book-desc").textContent = book.description || "";
const statusConfig = getStatusConfig(book.status);
diff --git a/library_service/static/page/create_book.js b/library_service/static/page/create_book.js
index 699e0fb..736baec 100644
--- a/library_service/static/page/create_book.js
+++ b/library_service/static/page/create_book.js
@@ -235,18 +235,25 @@ $(document).ready(() => {
const title = $("#book-title").val().trim();
const description = $("#book-description").val().trim();
+ const pageCount = parseInt($("#book-page-count").val()) || null;
if (!title) {
Utils.showToast("Введите название книги", "error");
return;
}
+ if (!parseInt(pageCount)) {
+ Utils.showToast("Введите количество страниц", "error");
+ return;
+ }
+
setLoading(true);
try {
const bookPayload = {
title: title,
description: description || null,
+ page_count: pageCount ? parseInt(pageCount) : null,
};
const createdBook = await Api.post("/api/books/", bookPayload);
diff --git a/library_service/static/page/edit_book.js b/library_service/static/page/edit_book.js
index 0bb3cc9..28f578d 100644
--- a/library_service/static/page/edit_book.js
+++ b/library_service/static/page/edit_book.js
@@ -23,6 +23,7 @@ $(document).ready(() => {
const $titleInput = $("#book-title");
const $descInput = $("#book-description");
const $statusSelect = $("#book-status");
+ const $pagesInput = $("#book-page-count");
const $submitBtn = $("#submit-btn");
const $submitText = $("#submit-text");
const $loadingSpinner = $("#loading-spinner");
@@ -69,6 +70,7 @@ $(document).ready(() => {
function populateForm(book) {
$titleInput.val(book.title);
$descInput.val(book.description || "");
+ $pagesInput.val(book.page_count);
$statusSelect.val(book.status);
updateCounters();
}
@@ -329,6 +331,7 @@ $(document).ready(() => {
const title = $titleInput.val().trim();
const description = $descInput.val().trim();
+ const pages = $pagesInput.val();
const status = $statusSelect.val();
if (!title) {
@@ -340,6 +343,7 @@ $(document).ready(() => {
if (title !== originalBook.title) payload.title = title;
if (description !== (originalBook.description || ""))
payload.description = description || null;
+ if (pageCount !== originalBook.page_count) payload.page_count = pages;
if (status !== originalBook.status) payload.status = status;
if (Object.keys(payload).length === 0) {
diff --git a/library_service/static/utils.js b/library_service/static/utils.js
index 93476a5..febad3d 100644
--- a/library_service/static/utils.js
+++ b/library_service/static/utils.js
@@ -19,8 +19,8 @@ const StorageHelper = {
const Utils = {
escapeHtml: (text) => {
- if (!text) return "";
- return text.replace(
+ if (text === null || text === undefined) return "";
+ return String(text).replace(
/[&<>"']/g,
(m) =>
({
diff --git a/library_service/templates/book.html b/library_service/templates/book.html
index a3b16af..b26a545 100644
--- a/library_service/templates/book.html
+++ b/library_service/templates/book.html
@@ -107,6 +107,10 @@
id="book-authors-text"
class="text-lg text-gray-600 font-medium mb-6"
>
+
+ Количество страниц:
+
+
Авторы:
+
+ Страниц:
+
+
diff --git a/library_service/templates/create_book.html b/library_service/templates/create_book.html
index 06f866d..f42dce7 100644
--- a/library_service/templates/create_book.html
+++ b/library_service/templates/create_book.html
@@ -69,6 +69,22 @@
>
+
+
+
+
diff --git a/library_service/templates/edit_book.html b/library_service/templates/edit_book.html
index 976961a..c79fd51 100644
--- a/library_service/templates/edit_book.html
+++ b/library_service/templates/edit_book.html
@@ -78,6 +78,23 @@
+
+
+
+
+