Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions api_v1/routers.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,33 @@
def register_routers(app: FastAPI) -> None:
"""
Функция по регистрации роутеров

## Args:
app (FastAPI): ASGI приложение.

## Returns:
None

## Example
```python
from fastapi import FastAPI

from config import settings
from api_v1.api_xml.views import router as xml
from api_v1.users.views import router as users


def register_routers(app: FastAPI) -> None:
app.include_router(
router=xml,
prefix=settings.API_PREFIX,
)
# Новый роутер
app.include_router(
router=users,
prefix=settings.API_PREFIX,
)
```
"""
app.include_router(
router=users,
Expand Down
47 changes: 47 additions & 0 deletions app_includes/logs_errors.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,54 @@
def register_errors(app: FastAPI) -> None:
"""
Крючек для логирования различных исключений

## Args:
app (FastAPI): ASGI приложение.

## Returns:
None

## Example
```python
from fastapi import FastAPI, Request
from fastapi.responses import JSONResponse
from fastapi.exceptions import HTTPException
from http import HTTPStatus

from config.setup_logs.logging import logger
from api_v1.api_xml.exeptions import APIFileNotFoundError


def register_errors(app: FastAPI) -> None:
@app.exception_handler(HTTPException)
async def http_error_handler(
request: Request,
exc: HTTPException,
):
logger.opt(exception=True).warning(exc)
response = dict(
status=False,
error_code=exc.status_code,
message=exc.detail,
)
return JSONResponse(response)

# Добавление нового крюка
@app.exception_handler(APIFileNotFoundError)
async def file_not_found_error_handler(
request: Request,
exc: APIFileNotFoundError,
):
logger.opt(exception=True).warning(exc)
response = dict(
status=False,
error_code=exc.status_code,
message=exc.detail,
)
return JSONResponse(response)
```
"""

@app.exception_handler(ValidationError)
async def validation_error_handler(
request: Request,
Expand Down
33 changes: 33 additions & 0 deletions app_includes/middlewares.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,39 @@
def register_middlewares(app: FastAPI) -> None:
"""
Регистрация middleware

## Args:
app (FastAPI): ASGI приложение.

## Returns:
None

## Example
```python
from fastapi.middleware.cors import CORSMiddleware
from fastapi import FastAPI

from config import settings
from middlewares import SomeMiddleware


def register_middlewares(app: FastAPI) -> None:
app.add_middleware(
CORSMiddleware,
allow_origins=[y
settings.CURRENT_ORIGIN,
],
allow_credentials=True,
allow_methods=['*'],
allow_headers=['*'],
)

# Новая регистрация
app.add_middleware(
SomeMiddleware,
*args,
)
```
"""
app.add_middleware(
CORSMiddleware,
Expand Down
56 changes: 55 additions & 1 deletion config/database/db_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,49 @@

class DataBaseHelper:
"""
Вспомогательный класс для работы с Базой Данных
Вспомогательный класс для работы с Базой Данных.

Помогает инициализировать соединение с Базой Данных, а так же
работу с сессиями.

## Инициализация:
:string:`db_url` - Адресс базы данных.
:string:`poolclass` - Пул типа :class:`sqlalchemy.pool.Pool`

## Методы:
:function:`DataBaseHelper.session_geter` - Получение генератора текущей сессии.
:function:`DataBaseHelper.get_scoped_session` - Получение текущей сессии.
:function:`DataBaseHelper.dispose` - Закрытые соединения.

## Примеры:
```python
from fastapi import FastAPI
from contextlib import asynccontextmanager
from config import db_connection, BaseModel


@asynccontextmanager
async def lifespan(app: FastAPI):
# Инициализация соединения для создания таблиц.
async with db_connection.engine.begin() as conn:
await conn.run_sync(BaseModel.metadata.create_all)
yield
await db_connection.dispose()

app = FastApi(lifespan=lifespan)
```
"""
def __init__(self,
db_url: str = DATA_BASE_URL,
poolclass: Pool | None = None,
) -> None:
"""
Args:
db_url (str, optional): Адресс Базы Данных. Defaults to DATA_BASE_URL.

poolclass (Pool | None, optional): Пул типа :class:`sqlalchemy.pool.Pool`.
Defaults to None.
"""
self._db_url = db_url
setup = dict(
url=self._db_url,
Expand All @@ -42,16 +79,33 @@ def __init__(self,
)

async def dispose(self) -> None:
"""
Закрытие соединения
"""
await self.engine.dispose()

def get_scoped_session(self) -> AsyncSession:
"""
Получение сессии
"""
session = async_scoped_session(
session_factory=self.session,
scopefunc=current_task,
)
return session

async def session_geter(self) -> AsyncGenerator[AsyncSession, Any]:
"""
Получение генератора сессии

Returns:
AsyncGenerator[AsyncSession, Any]: Возвращает
генератор с сессиями

Yields:
Iterator[AsyncGenerator[AsyncSession, Any]]: Генератор подает
сессии
"""
session = self.get_scoped_session()
yield session
await session.remove()
Expand Down
43 changes: 42 additions & 1 deletion config/models/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,48 @@


class Base(DeclarativeBase):
"""Базовая модель
"""
Базовая модель для инициализации других моделей.

Данная базовая модель является абстактной, и определяет
базовое поведение других таблиц.

## Определение поведения таблиц:

- Имя любой таблицы приводится к :method:`lower()` и
добаляется `s` к окончанию.

- Для каждой таблицы создается автогенерируемое поле `id` или `uid`,
которое автоинкремирует счетчик интидификатора сущностей.

## Примеры:
```python
from sqlalchemy.orm import Mapped, mapped_column
from sqlalchemy import String
from sqlalchemy.types import LargeBinary
from datetime import date

from config.models import Base


class User(Base):
name: Mapped[str] = mapped_column(String(length=100))
surname: Mapped[str] = mapped_column(String(length=200))
password: Mapped[str] = mapped_column(LargeBinary)
active: Mapped[bool] = mapped_column(default=True)
is_admin: Mapped[bool] = mapped_column(default=False)
create_date: Mapped[datetime] = mapped_column(
insert_default=func.now(),
server_default=func.now(),
)
login_date: Mapped[datetime | None] = mapped_column(
default=None,
server_default=None,
nullable=True,
)
```
По итогу к классу :class:`User` будет добавленно поле `id` или `uid`,
а так же в Базу данных таблица будет с названием `users`.
"""
__abstract__ = True

Expand Down
4 changes: 4 additions & 0 deletions config/setup_logs/logging.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
r"""
Основной файл настройки логирования проектов
"""

import sys
from loguru import logger

Expand Down