sync
This commit is contained in:
@@ -4,10 +4,6 @@ from pydantic_settings import BaseSettings, SettingsConfigDict
|
||||
class Settings(BaseSettings):
|
||||
DB_HOST: str = "localhost"
|
||||
DB_PORT: int = 5432
|
||||
DB_USER: str = "postrges"
|
||||
DB_PASS: str = "postgres"
|
||||
DB_NAME: str = "postgres"
|
||||
|
||||
POSTGRES_DB: str = "fastfod_db"
|
||||
POSTGRES_PASSWORD: str = "postgres"
|
||||
POSTGRES_USER: str = "postgres"
|
||||
@@ -18,8 +14,9 @@ class Settings(BaseSettings):
|
||||
Возвращает строку подключения к БД необходимую для SQLAlchemy
|
||||
"""
|
||||
return (
|
||||
f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASS}"
|
||||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}"
|
||||
"postgresql+asyncpg://"
|
||||
f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
|
||||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}"
|
||||
)
|
||||
|
||||
@property
|
||||
@@ -28,11 +25,11 @@ class Settings(BaseSettings):
|
||||
Возвращает строку подключения к БД необходимую для SQLAlchemy
|
||||
"""
|
||||
return (
|
||||
f"postgresql+asyncpg://{self.DB_USER}:{self.DB_PASS}"
|
||||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.DB_NAME}_test"
|
||||
"postgresql+asyncpg://"
|
||||
f"{self.POSTGRES_USER}:{self.POSTGRES_PASSWORD}"
|
||||
f"@{self.DB_HOST}:{self.DB_PORT}/{self.POSTGRES_DB}_test"
|
||||
)
|
||||
|
||||
|
||||
model_config = SettingsConfigDict(env_file=".env")
|
||||
|
||||
|
||||
|
@@ -1,8 +1,8 @@
|
||||
from uuid import UUID
|
||||
|
||||
from sqlalchemy import delete, func, select, update
|
||||
from sqlalchemy import delete, distinct, func, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from sqlalchemy.orm import Query, aliased
|
||||
from sqlalchemy.orm import aliased
|
||||
|
||||
from fastfood import models, schemas
|
||||
|
||||
@@ -12,8 +12,8 @@ class MenuCrud:
|
||||
async def get_menus(session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.Menu)
|
||||
result = await session.execute(query)
|
||||
return result.scalars().all()
|
||||
menus = await session.execute(query)
|
||||
return menus
|
||||
|
||||
@staticmethod
|
||||
async def create_menu_item(menu: schemas.MenuBase, session: AsyncSession):
|
||||
@@ -27,55 +27,25 @@ class MenuCrud:
|
||||
@staticmethod
|
||||
async def get_menu_item(menu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
""" Комментарий для проверяющего
|
||||
То что было, оставил закоментированным, удалю в следующей части
|
||||
в pgadmin набросал следующий запрос
|
||||
WITH subq as (
|
||||
SELECT
|
||||
s.id,
|
||||
s.title,
|
||||
s.description,
|
||||
s.parent_menu,
|
||||
count(d.id) as dishes_count
|
||||
FROM submenu s
|
||||
JOIN dish d ON s.id = d.parent_submenu
|
||||
GROUP BY s.id
|
||||
)
|
||||
SELECT
|
||||
m.id,
|
||||
m.title,
|
||||
m.description,
|
||||
count(q.id) AS submenus_count,
|
||||
SUM(q.dishes_count) AS dishes_count
|
||||
FROM menu m
|
||||
JOIN subq q ON m.id = q.parent_menu
|
||||
GROUP BY m.id
|
||||
"""
|
||||
m = aliased(models.Menu)
|
||||
s = aliased(models.SubMenu)
|
||||
d = aliased(models.Dish)
|
||||
|
||||
query = select(m).where(m.id == menu_id)
|
||||
query = (
|
||||
select(
|
||||
m,
|
||||
func.count(distinct(s.id)).label("submenus_count"),
|
||||
func.count(distinct(d.id)).label("dishes_count")
|
||||
)
|
||||
.join(s, s.parent_menu == m.id, isouter=True)
|
||||
.join(d, d.parent_submenu == s.id, isouter=True)
|
||||
.group_by(m.id)
|
||||
.where(m.id == menu_id)
|
||||
)
|
||||
menu = await session.execute(query)
|
||||
menu = menu.scalars().one_or_none()
|
||||
|
||||
if menu is None:
|
||||
return None
|
||||
|
||||
submenu_query = select(
|
||||
func.count(s.id).label("counter")
|
||||
).filter(s.parent_menu == menu_id)
|
||||
counter = await session.execute(submenu_query)
|
||||
|
||||
dish_query = (
|
||||
select(func.count(d.id))
|
||||
.join(s)
|
||||
.filter(d.parent_submenu == s.id)
|
||||
.filter(s.parent_menu == menu_id)
|
||||
)
|
||||
dishes = await session.execute(dish_query)
|
||||
menu.submenus_count = counter.scalars().one_or_none()
|
||||
menu.dishes_count = dishes.scalars().one_or_none()
|
||||
return menu
|
||||
|
||||
@staticmethod
|
||||
@@ -94,7 +64,7 @@ class MenuCrud:
|
||||
await session.commit()
|
||||
qr = select(models.Menu).where(models.Menu.id == menu_id)
|
||||
updated_menu = await session.execute(qr)
|
||||
return updated_menu.scalars().one()
|
||||
return updated_menu
|
||||
|
||||
@staticmethod
|
||||
async def delete_menu_item(menu_id: UUID, session: AsyncSession):
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import uuid
|
||||
from copy import deepcopy
|
||||
from typing import Annotated, List, Optional
|
||||
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy.dialects.postgresql import UUID
|
||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
|
||||
from sqlalchemy.util import hybridproperty
|
||||
|
||||
uuidpk = Annotated[
|
||||
uuid.UUID,
|
||||
@@ -21,6 +23,17 @@ class Base(DeclarativeBase):
|
||||
title: Mapped[str_25]
|
||||
description: Mapped[Optional[str]]
|
||||
|
||||
def __eq__(self, other):
|
||||
classes_match = isinstance(other, self.__class__)
|
||||
a, b = deepcopy(self.__dict__), deepcopy(other.__dict__)
|
||||
a.pop('_sa_instance_state', None)
|
||||
b.pop('_sa_instance_state', None)
|
||||
attrs_match = (a == b)
|
||||
return classes_match and attrs_match
|
||||
|
||||
def __ne__(self, other):
|
||||
return not self.__eq__(other)
|
||||
|
||||
|
||||
class Menu(Base):
|
||||
__tablename__ = "menu"
|
||||
@@ -28,10 +41,21 @@ class Menu(Base):
|
||||
submenus: Mapped[List["SubMenu"]] = relationship(
|
||||
"SubMenu",
|
||||
backref="menu",
|
||||
lazy="dynamic",
|
||||
lazy="selectin",
|
||||
cascade="all, delete",
|
||||
)
|
||||
|
||||
@hybridproperty
|
||||
def submenus_count(self):
|
||||
return len(self.submenus)
|
||||
|
||||
@hybridproperty
|
||||
def dishes_count(self):
|
||||
counter = 0
|
||||
for sub in self.submenus:
|
||||
counter += len(sub.dishes)
|
||||
return counter
|
||||
|
||||
|
||||
class SubMenu(Base):
|
||||
__tablename__ = "submenu"
|
||||
@@ -42,10 +66,14 @@ class SubMenu(Base):
|
||||
dishes: Mapped[List["Dish"]] = relationship(
|
||||
"Dish",
|
||||
backref="submenu",
|
||||
lazy="dynamic",
|
||||
lazy="selectin",
|
||||
cascade="all, delete",
|
||||
)
|
||||
|
||||
@hybridproperty
|
||||
def dishes_count(self):
|
||||
return len(self.dishes)
|
||||
|
||||
|
||||
class Dish(Base):
|
||||
__tablename__ = "dish"
|
||||
|
@@ -17,7 +17,7 @@ router = APIRouter(
|
||||
@router.get("/", response_model=Optional[List[schemas.Menu]])
|
||||
async def get_menus(session: AsyncSession = Depends(get_async_session)):
|
||||
result = await crud.get_menus(session=session)
|
||||
return result
|
||||
return result.scalars().all()
|
||||
|
||||
|
||||
@router.post("/", status_code=201, response_model=schemas.Menu)
|
||||
@@ -54,7 +54,7 @@ async def update_menu(
|
||||
menu=menu,
|
||||
session=session,
|
||||
)
|
||||
return result
|
||||
return result.scalars().one()
|
||||
|
||||
|
||||
@router.delete("/{menu_id}")
|
||||
|
Reference in New Issue
Block a user