Рефакторинг небольшой
parent
a4af3437ac
commit
ed11efa704
|
@ -0,0 +1,5 @@
|
|||
DB_HOST=localhost
|
||||
DB_PORT=5432
|
||||
DB_USER=postgres
|
||||
DB_PASS=postgres
|
||||
DB_NAME=postgres
|
|
@ -1,20 +1,91 @@
|
|||
from fastapi import FastAPI
|
||||
|
||||
from fastfood.routes import router
|
||||
from fastfood.routers.menu import router as menu_router
|
||||
from fastfood.routers.submenu import router as submenu_router
|
||||
from fastfood.routers.dish import router as dish_router
|
||||
|
||||
|
||||
async def generate_test_data():
|
||||
"""
|
||||
Создание БД и наполнение ее данными
|
||||
"""
|
||||
pass
|
||||
description = """
|
||||
# 🔥🔥🔥Fastfood-API поможет тебе подкрепиться 🔥🔥🔥
|
||||
|
||||
### У нас есть Menu. Ты можеш выбрать блюда из кухни, которая тебе нравится
|
||||
|
||||
## Menu
|
||||
|
||||
Ты можешь **add menu**.
|
||||
|
||||
Ты можешь **read menu**.
|
||||
|
||||
Ты можешь **patch menu**.
|
||||
|
||||
Ты можешь **delete menu**.
|
||||
|
||||
### У нас есть в SubMenu, где ты сможешь найти
|
||||
десерты/напитки/супчики/прочие вкусности
|
||||
|
||||
# SubMenu
|
||||
|
||||
Ты можешь **add submenu into menu**.
|
||||
|
||||
Ты можешь **read submenu**.
|
||||
|
||||
Ты можешь **patch submenu**.
|
||||
|
||||
Ты можешь **delete menu**.
|
||||
|
||||
### У нас есть в Dish, где ты сможешь найти блюдо по вкусу
|
||||
|
||||
# Dish
|
||||
|
||||
Ты можешь **add dish into submenu**.
|
||||
|
||||
Ты можешь **read dish**.
|
||||
|
||||
Ты можешь **patch dish**.
|
||||
|
||||
Ты можешь **delete dish**.
|
||||
|
||||
## Приятного аппетита
|
||||
"""
|
||||
|
||||
|
||||
tags_metadata = [
|
||||
{
|
||||
"name": "menu",
|
||||
"description": "Операции с меню.",
|
||||
},
|
||||
{
|
||||
"name": "submenu",
|
||||
"description": "Подменю и работа с ним",
|
||||
},
|
||||
{
|
||||
"name": "dish",
|
||||
"description": "Блюда и работа с ними"
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
def create_app():
|
||||
"""
|
||||
Создание экземпляра приложения FastAPI и врзврат его
|
||||
Фабрика FastAPI.
|
||||
"""
|
||||
app = FastAPI()
|
||||
app.include_router(router)
|
||||
app = FastAPI(
|
||||
title="Fastfood-API",
|
||||
description=description,
|
||||
version="0.0.1",
|
||||
contact={
|
||||
"name": "Sergey Vanyushkin",
|
||||
"url": "http://pi3c.ru",
|
||||
"email": "pi3c@yandex.ru",
|
||||
},
|
||||
license_info={
|
||||
"name": "MIT license",
|
||||
"url": "https://mit-license.org/",
|
||||
},
|
||||
openapi_tags=tags_metadata,
|
||||
)
|
||||
app.include_router(menu_router)
|
||||
app.include_router(submenu_router)
|
||||
app.include_router(dish_router)
|
||||
|
||||
return app
|
||||
|
|
185
fastfood/crud.py
185
fastfood/crud.py
|
@ -1,185 +0,0 @@
|
|||
from re import sub
|
||||
from uuid import UUID
|
||||
from sqlalchemy import delete, func, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import models, schemas
|
||||
from fastfood.dbase import async_engine
|
||||
|
||||
|
||||
async def create_db_and_tables():
|
||||
async with async_engine.begin() as conn:
|
||||
await conn.run_sync(models.Base.metadata.drop_all)
|
||||
await conn.run_sync(models.Base.metadata.create_all)
|
||||
|
||||
|
||||
class Crud:
|
||||
@staticmethod
|
||||
async def get_menus(session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.Menu)
|
||||
result = await session.execute(query)
|
||||
return result.scalars().all()
|
||||
|
||||
@staticmethod
|
||||
async def create_menu_item(menu: schemas.MenuBase, session: AsyncSession):
|
||||
async with session:
|
||||
new_menu = models.Menu(**menu.model_dump())
|
||||
session.add(new_menu)
|
||||
await session.commit()
|
||||
await session.refresh(new_menu)
|
||||
return new_menu
|
||||
|
||||
@staticmethod
|
||||
async def get_menu_item(menu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.Menu).where(models.Menu.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(models.SubMenu.id).label("counter")).filter(models.SubMenu.parent_menu == menu_id)
|
||||
counter = await session.execute(submenu_query)
|
||||
|
||||
dish_query = (
|
||||
select(func.count(models.Dish.id))
|
||||
.join(models.SubMenu)
|
||||
.filter(models.Dish.parent_submenu == models.SubMenu.id)
|
||||
.filter(models.SubMenu.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
|
||||
async def update_menu_item(menu_id: UUID,
|
||||
menu: schemas.MenuBase,
|
||||
session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = update(models.Menu).where(models.Menu.id == menu_id).values(**menu.model_dump())
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
qr = select(models.Menu).where(models.Menu.id == menu_id)
|
||||
updated_menu = await session.execute(qr)
|
||||
return updated_menu.scalars().one()
|
||||
|
||||
@staticmethod
|
||||
async def delete_menu_item(menu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = delete(models.Menu).where(models.Menu.id == menu_id)
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
|
||||
@staticmethod
|
||||
async def get_submenus(menu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.SubMenu).where(models.SubMenu.parent_menu == menu_id)
|
||||
submenus = await session.execute(query)
|
||||
return submenus.scalars().all()
|
||||
|
||||
@staticmethod
|
||||
async def create_submenu_item(
|
||||
menu_id: UUID, submenu: schemas.MenuBase, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
new_submenu = models.SubMenu(**submenu.model_dump())
|
||||
new_submenu.parent_menu = menu_id
|
||||
session.add(new_submenu)
|
||||
await session.flush()
|
||||
await session.commit()
|
||||
return new_submenu
|
||||
|
||||
@staticmethod
|
||||
async def get_submenu_item(
|
||||
menu_id: UUID, submenu_id: UUID, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = select(models.SubMenu).where(models.SubMenu.id == submenu_id)
|
||||
submenu = await session.execute(query)
|
||||
submenu = submenu.scalars().one_or_none()
|
||||
if submenu is None:
|
||||
return None
|
||||
|
||||
dish_query = (
|
||||
select(func.count(models.Dish.id))
|
||||
.join(models.SubMenu)
|
||||
.filter(models.Dish.parent_submenu == models.SubMenu.id)
|
||||
)
|
||||
dishes = await session.execute(dish_query)
|
||||
submenu.dishes_count = dishes.scalars().one_or_none()
|
||||
|
||||
return submenu
|
||||
|
||||
@staticmethod
|
||||
async def update_submenu_item(
|
||||
submenu_id: UUID,
|
||||
submenu: schemas.MenuBase,
|
||||
session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = update(models.SubMenu).where(models.SubMenu.id == submenu_id).values(**submenu.model_dump())
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
qr = select(models.SubMenu).where(models.SubMenu.id == submenu_id)
|
||||
updated_submenu = await session.execute(qr)
|
||||
return updated_submenu.scalars().one()
|
||||
|
||||
@staticmethod
|
||||
async def delete_submenu_item(submenu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = delete(models.SubMenu).where(models.SubMenu.id == submenu_id)
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
|
||||
@staticmethod
|
||||
async def get_dishes(submenu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.Dish).where(models.Dish.parent_submenu == submenu_id)
|
||||
dishes = await session.execute(query)
|
||||
return dishes.scalars().all()
|
||||
|
||||
@staticmethod
|
||||
async def create_dish_item(
|
||||
submenu_id: UUID, dish: schemas.DishBase, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
new_dish = models.Dish(**dish.model_dump())
|
||||
new_dish.parent_submenu = submenu_id
|
||||
session.add(new_dish)
|
||||
await session.flush()
|
||||
await session.commit()
|
||||
return new_dish
|
||||
|
||||
@staticmethod
|
||||
async def get_dish_item(
|
||||
dish_id: UUID, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = select(models.Dish).where(models.Dish.id == dish_id)
|
||||
submenu = await session.execute(query)
|
||||
return submenu.scalars().one_or_none()
|
||||
|
||||
@staticmethod
|
||||
async def update_dish_item(
|
||||
dish_id: UUID,
|
||||
dish: schemas.DishBase,
|
||||
session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = update(models.Dish).where(models.Dish.id == dish_id).values(**dish.model_dump())
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
qr = select(models.Dish).where(models.Dish.id == dish_id)
|
||||
updated_submenu = await session.execute(qr)
|
||||
return updated_submenu.scalars().one()
|
||||
|
||||
@staticmethod
|
||||
async def delete_dish_item(dish_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = delete(models.Dish).where(models.Dish.id == dish_id)
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
from fastfood import models
|
||||
from fastfood.dbase import async_engine
|
||||
from .menu import MenuCrud
|
||||
from .submenu import SubMenuCrud
|
||||
from .dish import DishCrud
|
||||
|
||||
|
||||
async def create_db_and_tables():
|
||||
async with async_engine.begin() as conn:
|
||||
await conn.run_sync(models.Base.metadata.drop_all)
|
||||
await conn.run_sync(models.Base.metadata.create_all)
|
||||
|
||||
|
||||
class Crud(MenuCrud, SubMenuCrud, DishCrud):
|
||||
pass
|
||||
|
||||
|
||||
crud = Crud()
|
|
@ -0,0 +1,58 @@
|
|||
from uuid import UUID
|
||||
from sqlalchemy import delete, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import models, schemas
|
||||
|
||||
|
||||
class DishCrud:
|
||||
@staticmethod
|
||||
async def get_dishes(submenu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.Dish).where(models.Dish.parent_submenu == submenu_id)
|
||||
dishes = await session.execute(query)
|
||||
return dishes.scalars().all()
|
||||
|
||||
@staticmethod
|
||||
async def create_dish_item(
|
||||
submenu_id: UUID, dish: schemas.DishBase, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
new_dish = models.Dish(**dish.model_dump())
|
||||
new_dish.parent_submenu = submenu_id
|
||||
session.add(new_dish)
|
||||
await session.flush()
|
||||
await session.commit()
|
||||
return new_dish
|
||||
|
||||
@staticmethod
|
||||
async def get_dish_item(
|
||||
dish_id: UUID, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = select(models.Dish).where(models.Dish.id == dish_id)
|
||||
submenu = await session.execute(query)
|
||||
return submenu.scalars().one_or_none()
|
||||
|
||||
@staticmethod
|
||||
async def update_dish_item(
|
||||
dish_id: UUID,
|
||||
dish: schemas.DishBase,
|
||||
session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = update(models.Dish).where(models.Dish.id == dish_id).values(**dish.model_dump())
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
qr = select(models.Dish).where(models.Dish.id == dish_id)
|
||||
updated_submenu = await session.execute(qr)
|
||||
return updated_submenu.scalars().one()
|
||||
|
||||
@staticmethod
|
||||
async def delete_dish_item(dish_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = delete(models.Dish).where(models.Dish.id == dish_id)
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
|
||||
|
|
@ -0,0 +1,67 @@
|
|||
from uuid import UUID
|
||||
from sqlalchemy import delete, func, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import models, schemas
|
||||
|
||||
|
||||
class MenuCrud:
|
||||
@staticmethod
|
||||
async def get_menus(session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.Menu)
|
||||
result = await session.execute(query)
|
||||
return result.scalars().all()
|
||||
|
||||
@staticmethod
|
||||
async def create_menu_item(menu: schemas.MenuBase, session: AsyncSession):
|
||||
async with session:
|
||||
new_menu = models.Menu(**menu.model_dump())
|
||||
session.add(new_menu)
|
||||
await session.commit()
|
||||
await session.refresh(new_menu)
|
||||
return new_menu
|
||||
|
||||
@staticmethod
|
||||
async def get_menu_item(menu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.Menu).where(models.Menu.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(models.SubMenu.id).label("counter")).filter(models.SubMenu.parent_menu == menu_id)
|
||||
counter = await session.execute(submenu_query)
|
||||
|
||||
dish_query = (
|
||||
select(func.count(models.Dish.id))
|
||||
.join(models.SubMenu)
|
||||
.filter(models.Dish.parent_submenu == models.SubMenu.id)
|
||||
.filter(models.SubMenu.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
|
||||
async def update_menu_item(menu_id: UUID,
|
||||
menu: schemas.MenuBase,
|
||||
session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = update(models.Menu).where(models.Menu.id == menu_id).values(**menu.model_dump())
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
qr = select(models.Menu).where(models.Menu.id == menu_id)
|
||||
updated_menu = await session.execute(qr)
|
||||
return updated_menu.scalars().one()
|
||||
|
||||
@staticmethod
|
||||
async def delete_menu_item(menu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = delete(models.Menu).where(models.Menu.id == menu_id)
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
|
||||
|
|
@ -0,0 +1,68 @@
|
|||
from uuid import UUID
|
||||
from sqlalchemy import delete, func, select, update
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import models, schemas
|
||||
|
||||
|
||||
class SubMenuCrud:
|
||||
@staticmethod
|
||||
async def get_submenus(menu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = select(models.SubMenu).where(models.SubMenu.parent_menu == menu_id)
|
||||
submenus = await session.execute(query)
|
||||
return submenus.scalars().all()
|
||||
|
||||
@staticmethod
|
||||
async def create_submenu_item(
|
||||
menu_id: UUID, submenu: schemas.MenuBase, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
new_submenu = models.SubMenu(**submenu.model_dump())
|
||||
new_submenu.parent_menu = menu_id
|
||||
session.add(new_submenu)
|
||||
await session.flush()
|
||||
await session.commit()
|
||||
return new_submenu
|
||||
|
||||
@staticmethod
|
||||
async def get_submenu_item(
|
||||
menu_id: UUID, submenu_id: UUID, session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = select(models.SubMenu).where(models.SubMenu.id == submenu_id)
|
||||
submenu = await session.execute(query)
|
||||
submenu = submenu.scalars().one_or_none()
|
||||
if submenu is None:
|
||||
return None
|
||||
|
||||
dish_query = (
|
||||
select(func.count(models.Dish.id))
|
||||
.join(models.SubMenu)
|
||||
.filter(models.Dish.parent_submenu == models.SubMenu.id)
|
||||
)
|
||||
dishes = await session.execute(dish_query)
|
||||
submenu.dishes_count = dishes.scalars().one_or_none()
|
||||
|
||||
return submenu
|
||||
|
||||
@staticmethod
|
||||
async def update_submenu_item(
|
||||
submenu_id: UUID,
|
||||
submenu: schemas.MenuBase,
|
||||
session: AsyncSession,
|
||||
):
|
||||
async with session:
|
||||
query = update(models.SubMenu).where(models.SubMenu.id == submenu_id).values(**submenu.model_dump())
|
||||
await session.execute(query)
|
||||
await session.commit()
|
||||
qr = select(models.SubMenu).where(models.SubMenu.id == submenu_id)
|
||||
updated_submenu = await session.execute(qr)
|
||||
return updated_submenu.scalars().one()
|
||||
|
||||
@staticmethod
|
||||
async def delete_submenu_item(submenu_id: UUID, session: AsyncSession):
|
||||
async with session:
|
||||
query = delete(models.SubMenu).where(models.SubMenu.id == submenu_id)
|
||||
await session.execute(query)
|
||||
await session.commit()
|
|
@ -0,0 +1,76 @@
|
|||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from uuid import UUID
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import schemas
|
||||
from fastfood.utils import price_converter
|
||||
from fastfood.cruds import crud
|
||||
from fastfood.dbase import get_async_session
|
||||
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes",
|
||||
tags=["dish"],
|
||||
)
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def get_dishes(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session)
|
||||
):
|
||||
result = await crud.get_dishes(submenu_id=submenu_id, session=session)
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/", status_code=201)
|
||||
async def create_dish(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
dish: schemas.DishBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.create_dish_item(
|
||||
submenu_id=submenu_id,
|
||||
dish=dish,
|
||||
session=session,
|
||||
)
|
||||
return price_converter(result)
|
||||
|
||||
|
||||
@router.get("/{dish_id}")
|
||||
async def get_dish(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
dish_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.get_dish_item(
|
||||
dish_id=dish_id, session=session,
|
||||
)
|
||||
if not result:
|
||||
raise HTTPException(status_code=404, detail="dish not found")
|
||||
return price_converter(result)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{dish_id}"
|
||||
)
|
||||
async def update_dish(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
dish_id: UUID,
|
||||
dish: schemas.DishBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.update_dish_item(
|
||||
dish_id=dish_id, dish=dish, session=session,
|
||||
)
|
||||
return price_converter(result)
|
||||
|
||||
|
||||
@router.delete("/{dish_id}")
|
||||
async def delete_dish(menu_id: UUID, submenu_id: UUID, dish_id: UUID, session: AsyncSession = Depends(get_async_session)):
|
||||
await crud.delete_dish_item(dish_id=dish_id, session=session)
|
|
@ -0,0 +1,64 @@
|
|||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from uuid import UUID
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import schemas
|
||||
from fastfood.cruds import crud
|
||||
from fastfood.dbase import get_async_session
|
||||
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/api/v1/menus",
|
||||
tags=["menu"],
|
||||
)
|
||||
|
||||
|
||||
@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
|
||||
|
||||
|
||||
@router.post("/", status_code=201, response_model=schemas.Menu)
|
||||
async def add_menu(
|
||||
menu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.create_menu_item(
|
||||
menu=menu,
|
||||
session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/{menu_id}", response_model=schemas.MenuRead)
|
||||
async def get_menu(
|
||||
menu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.get_menu_item(menu_id=menu_id, session=session)
|
||||
if not result:
|
||||
raise HTTPException(status_code=404, detail="menu not found")
|
||||
return result
|
||||
|
||||
|
||||
@router.patch("/{menu_id}", response_model=schemas.MenuBase)
|
||||
async def update_menu(
|
||||
menu_id: UUID,
|
||||
menu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.update_menu_item(
|
||||
menu_id=menu_id, menu=menu, session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.delete("/{menu_id}")
|
||||
async def delete_menu(
|
||||
menu_id: UUID, session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
await crud.delete_menu_item(menu_id=menu_id, session=session)
|
||||
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from uuid import UUID
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import schemas
|
||||
from fastfood.cruds import crud
|
||||
from fastfood.dbase import get_async_session
|
||||
|
||||
|
||||
router = APIRouter(
|
||||
prefix="/api/v1/menus/{menu_id}/submenus",
|
||||
tags=["submenu"],
|
||||
)
|
||||
|
||||
|
||||
@router.get("/")
|
||||
async def get_submenus(
|
||||
menu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session)
|
||||
):
|
||||
result = await crud.get_submenus(menu_id=menu_id, session=session)
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/", status_code=201)
|
||||
async def create_submenu_item(
|
||||
menu_id: UUID,
|
||||
submenu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.create_submenu_item(
|
||||
menu_id=menu_id,
|
||||
submenu=submenu,
|
||||
session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/{submenu_id}", response_model=schemas.SubMenuRead)
|
||||
async def get_submenu(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.get_submenu_item(
|
||||
menu_id=menu_id, submenu_id=submenu_id, session=session,
|
||||
)
|
||||
if not result:
|
||||
raise HTTPException(status_code=404, detail="submenu not found")
|
||||
return result
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/{submenu_id}",
|
||||
response_model=schemas.MenuBase,
|
||||
)
|
||||
async def update_submenu(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
submenu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.update_submenu_item(
|
||||
submenu_id=submenu_id, submenu=submenu, session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.delete("/{submenu_id}")
|
||||
async def delete_submenu(menu_id: UUID, submenu_id: UUID, session: AsyncSession = Depends(get_async_session)):
|
||||
await crud.delete_submenu_item(submenu_id=submenu_id, session=session)
|
||||
|
||||
|
|
@ -1,183 +0,0 @@
|
|||
from typing import List, Optional
|
||||
from fastapi import APIRouter, Depends, HTTPException
|
||||
from uuid import UUID
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
|
||||
from fastfood import schemas
|
||||
from fastfood.crud import Crud as crud
|
||||
from fastfood.dbase import get_async_session
|
||||
|
||||
|
||||
router = APIRouter()
|
||||
|
||||
|
||||
def price_converter(dish: dict) -> dict:
|
||||
dish.price = str(dish.price)
|
||||
return dish
|
||||
|
||||
|
||||
@router.get("/api/v1/menus", 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
|
||||
|
||||
|
||||
@router.post("/api/v1/menus", status_code=201, response_model=schemas.Menu)
|
||||
async def add_menu(
|
||||
menu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.create_menu_item(
|
||||
menu=menu,
|
||||
session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/api/v1/menus/{menu_id}", response_model=schemas.MenuRead)
|
||||
async def get_menu(
|
||||
menu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.get_menu_item(menu_id=menu_id, session=session)
|
||||
if not result:
|
||||
raise HTTPException(status_code=404, detail="menu not found")
|
||||
return result
|
||||
|
||||
|
||||
@router.patch("/api/v1/menus/{menu_id}", response_model=schemas.MenuBase)
|
||||
async def update_menu(
|
||||
menu_id: UUID,
|
||||
menu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.update_menu_item(
|
||||
menu_id=menu_id, menu=menu, session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.delete("/api/v1/menus/{menu_id}")
|
||||
async def delete_menu(
|
||||
menu_id: UUID, session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
await crud.delete_menu_item(menu_id=menu_id, session=session)
|
||||
|
||||
|
||||
@router.get("/api/v1/menus/{menu_id}/submenus")
|
||||
async def get_submenus(
|
||||
menu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session)
|
||||
):
|
||||
result = await crud.get_submenus(menu_id=menu_id, session=session)
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/api/v1/menus/{menu_id}/submenus", status_code=201)
|
||||
async def create_submenu_item(
|
||||
menu_id: UUID,
|
||||
submenu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.create_submenu_item(
|
||||
menu_id=menu_id,
|
||||
submenu=submenu,
|
||||
session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.get("/api/v1/menus/{menu_id}/submenus/{submenu_id}", response_model=schemas.SubMenuRead)
|
||||
async def get_submenu(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.get_submenu_item(
|
||||
menu_id=menu_id, submenu_id=submenu_id, session=session,
|
||||
)
|
||||
if not result:
|
||||
raise HTTPException(status_code=404, detail="submenu not found")
|
||||
return result
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/api/v1/menus/{menu_id}/submenus/{submenu_id}",
|
||||
response_model=schemas.MenuBase,
|
||||
)
|
||||
async def update_submenu(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
submenu: schemas.MenuBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.update_submenu_item(
|
||||
submenu_id=submenu_id, submenu=submenu, session=session,
|
||||
)
|
||||
return result
|
||||
|
||||
|
||||
@router.delete("/api/v1/menus/{menu_id}/submenus/{submenu_id}")
|
||||
async def delete_submenu(menu_id: UUID, submenu_id: UUID, session: AsyncSession = Depends(get_async_session)):
|
||||
await crud.delete_submenu_item(submenu_id=submenu_id, session=session)
|
||||
|
||||
|
||||
@router.get("/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes")
|
||||
async def get_dishes(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session)
|
||||
):
|
||||
result = await crud.get_dishes(submenu_id=submenu_id, session=session)
|
||||
return result
|
||||
|
||||
|
||||
@router.post("/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes", status_code=201)
|
||||
async def create_dish(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
dish: schemas.DishBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.create_dish_item(
|
||||
submenu_id=submenu_id,
|
||||
dish=dish,
|
||||
session=session,
|
||||
)
|
||||
return price_converter(result)
|
||||
|
||||
|
||||
@router.get("/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes/{dish_id}")
|
||||
async def get_dish(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
dish_id: UUID,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.get_dish_item(
|
||||
dish_id=dish_id, session=session,
|
||||
)
|
||||
if not result:
|
||||
raise HTTPException(status_code=404, detail="dish not found")
|
||||
return price_converter(result)
|
||||
|
||||
|
||||
@router.patch(
|
||||
"/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes/{dish_id}"
|
||||
)
|
||||
async def update_dish(
|
||||
menu_id: UUID,
|
||||
submenu_id: UUID,
|
||||
dish_id: UUID,
|
||||
dish: schemas.DishBase,
|
||||
session: AsyncSession = Depends(get_async_session),
|
||||
):
|
||||
result = await crud.update_dish_item(
|
||||
dish_id=dish_id, dish=dish, session=session,
|
||||
)
|
||||
return price_converter(result)
|
||||
|
||||
|
||||
@router.delete("/api/v1/menus/{menu_id}/submenus/{submenu_id}/dishes/{dish_id}")
|
||||
async def delete_dish(menu_id: UUID, submenu_id: UUID, dish_id: UUID, session: AsyncSession = Depends(get_async_session)):
|
||||
await crud.delete_dish_item(dish_id=dish_id, session=session)
|
|
@ -1,5 +1,4 @@
|
|||
from decimal import Decimal
|
||||
from typing import List, Optional
|
||||
from typing import Optional
|
||||
from uuid import UUID
|
||||
|
||||
from pydantic import BaseModel
|
||||
|
@ -21,6 +20,7 @@ class MenuRead(Menu):
|
|||
submenus_count: int
|
||||
dishes_count: int
|
||||
|
||||
|
||||
class SubMenuRead(Menu):
|
||||
dishes_count: int
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
|
||||
def convert_price(dish: dict):
|
||||
def price_converter(dish: dict) -> dict:
|
||||
dish.price = str(dish.price)
|
||||
return dish
|
||||
|
|
22
manage.py
22
manage.py
|
@ -3,12 +3,12 @@ import sys
|
|||
|
||||
import uvicorn
|
||||
|
||||
from fastfood.crud import create_db_and_tables
|
||||
from fastfood.cruds import create_db_and_tables
|
||||
|
||||
|
||||
def run_app():
|
||||
"""
|
||||
Запуск
|
||||
Запуск FastAPI
|
||||
"""
|
||||
uvicorn.run(
|
||||
app="fastfood.app:create_app",
|
||||
|
@ -17,13 +17,15 @@ def run_app():
|
|||
)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if "filldb" in sys.argv:
|
||||
"""Наполнение БД демонстрационными данными"""
|
||||
pass
|
||||
|
||||
if "--run-server" in sys.argv:
|
||||
async def create():
|
||||
async def recreate():
|
||||
"""Удаление и создание таблиц в базе данных для тестирования"""
|
||||
await create_db_and_tables()
|
||||
asyncio.run(create())
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if "--run-server" in sys.argv:
|
||||
run_app()
|
||||
|
||||
if "--run-test-server" in sys.argv:
|
||||
asyncio.run(recreate())
|
||||
run_app()
|
||||
|
|
|
@ -126,6 +126,41 @@ files = [
|
|||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "dnspython"
|
||||
version = "2.5.0"
|
||||
description = "DNS toolkit"
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "dnspython-2.5.0-py3-none-any.whl", hash = "sha256:6facdf76b73c742ccf2d07add296f178e629da60be23ce4b0a9c927b1e02c3a6"},
|
||||
{file = "dnspython-2.5.0.tar.gz", hash = "sha256:a0034815a59ba9ae888946be7ccca8f7c157b286f8455b379c692efb51022a15"},
|
||||
]
|
||||
|
||||
[package.extras]
|
||||
dev = ["black (>=23.1.0)", "coverage (>=7.0)", "flake8 (>=5.0.3)", "mypy (>=1.0.1)", "pylint (>=2.7)", "pytest (>=6.2.5)", "pytest-cov (>=3.0.0)", "sphinx (>=7.0.0)", "twine (>=4.0.0)", "wheel (>=0.41.0)"]
|
||||
dnssec = ["cryptography (>=41)"]
|
||||
doh = ["h2 (>=4.1.0)", "httpcore (>=0.17.3)", "httpx (>=0.25.1)"]
|
||||
doq = ["aioquic (>=0.9.20)"]
|
||||
idna = ["idna (>=2.1)"]
|
||||
trio = ["trio (>=0.14)"]
|
||||
wmi = ["wmi (>=1.5.1)"]
|
||||
|
||||
[[package]]
|
||||
name = "email-validator"
|
||||
version = "2.1.0.post1"
|
||||
description = "A robust email address syntax and deliverability validation library."
|
||||
optional = false
|
||||
python-versions = ">=3.8"
|
||||
files = [
|
||||
{file = "email_validator-2.1.0.post1-py3-none-any.whl", hash = "sha256:c973053efbeddfef924dc0bd93f6e77a1ea7ee0fce935aea7103c7a3d6d2d637"},
|
||||
{file = "email_validator-2.1.0.post1.tar.gz", hash = "sha256:a4b0bd1cf55f073b924258d19321b1f3aa74b4b5a71a42c305575dba920e1a44"},
|
||||
]
|
||||
|
||||
[package.dependencies]
|
||||
dnspython = ">=2.0.0"
|
||||
idna = ">=2.0.0"
|
||||
|
||||
[[package]]
|
||||
name = "exceptiongroup"
|
||||
version = "1.2.0"
|
||||
|
@ -716,4 +751,4 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
|
|||
[metadata]
|
||||
lock-version = "2.0"
|
||||
python-versions = "^3.10"
|
||||
content-hash = "f2b347c9b370a1cf7c178196c0a8298d34de656dc914e03b2cdec5a67384fd03"
|
||||
content-hash = "84fe024aa665ddad3077ca7e73054d1a5cb019a9a3e78af917922433ff4b3d8c"
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,93 @@
|
|||
{
|
||||
"id": "7e7cd612-7f40-491b-8bd6-ba2322a3d0d7",
|
||||
"name": "menu app",
|
||||
"values": [
|
||||
{
|
||||
"key": "LOCAL_URL",
|
||||
"value": "127.0.0.1:8000",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "api_test_menu_id",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "api_test_submenu_id",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "api_test_dish_id",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_menu_id",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_menu_title",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_menu_description",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_submenu_id",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_submenu_title",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_submenu_description",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_dish_id",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_dish_title",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_dish_description",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
},
|
||||
{
|
||||
"key": "target_dish_price",
|
||||
"value": "",
|
||||
"type": "default",
|
||||
"enabled": true
|
||||
}
|
||||
],
|
||||
"_postman_variable_scope": "environment",
|
||||
"_postman_exported_at": "2023-01-12T16:22:10.333Z",
|
||||
"_postman_exported_using": "Postman/10.6.7"
|
||||
}
|
|
@ -13,6 +13,7 @@ uvicorn = "^0.26.0"
|
|||
asyncpg = "^0.29.0"
|
||||
pydantic-settings = "^2.1.0"
|
||||
psycopg2-binary = "^2.9.9"
|
||||
email-validator = "^2.1.0.post1"
|
||||
|
||||
|
||||
[tool.poetry.group.dev.dependencies]
|
||||
|
|
Loading…
Reference in New Issue