Compare commits
No commits in common. "938d41d1ea50f75b2e268a160e1afa71deff71bc" and "f8eca2e8321de261959e8736a6f8eb0772bf0bb1" have entirely different histories.
938d41d1ea
...
f8eca2e832
70
README.md
70
README.md
|
@ -1,70 +0,0 @@
|
||||||
# fastfood
|
|
||||||
Fastapi веб приложение реализующее api для общепита.
|
|
||||||
|
|
||||||
## Описание
|
|
||||||
Данный проект, это результат выполнения практического домашнего задания интенсива от YLAB Development. Проект реализован на фреймворке fastapi, с использованием sqlalchemy. В качестве базы данных используется postgresql.
|
|
||||||
### Техническое задание
|
|
||||||
|
|
||||||
|
|
||||||
## Возможности
|
|
||||||
В проекте реализованы 3 сущности: Menu, SubMenu и Dish. Для каждого них реализованы 4 метода http запросов: GET, POST, PATCH и DELETE c помощью которых можно управлять данными.
|
|
||||||
Для Menu доступен метод GET возвращающий все его SubMenu. Аналогично для SubMenu реализован метод для возврата всех Dish.
|
|
||||||
|
|
||||||
|
|
||||||
## Зависимости
|
|
||||||
- postgresql Для работы сервиса необходима установленная СУБД. Должна быть создана база данных и пользователь с правами на нее.
|
|
||||||
- poetry - Система управления зависимостями в Python.
|
|
||||||
|
|
||||||
Остальное добавится автоматически на этапе установки.
|
|
||||||
|
|
||||||
## Установка
|
|
||||||
Установите и настройте postgresql согласно офф. документации. Создайте пользователя и бд.
|
|
||||||
|
|
||||||
Установите систему управления зависимостями
|
|
||||||
> `$ pip install poetry`
|
|
||||||
|
|
||||||
Клонируйте репозиторий
|
|
||||||
> `$ git clone https://git.pi3c.ru/pi3c/fastfood.git`
|
|
||||||
|
|
||||||
Перейдите в каталог
|
|
||||||
|
|
||||||
> `$ cd fastfood`
|
|
||||||
|
|
||||||
> `$ poetry install --no-root`
|
|
||||||
|
|
||||||
Создастся виртуальное окружение и установятся зависимости
|
|
||||||
|
|
||||||
## Запуск
|
|
||||||
Запуск проекта возможен в 2х режимах:
|
|
||||||
- Запуск в режиме "prod" с ключем --run-server
|
|
||||||
Подразумевает наличие уже созданных таблиц в базе данных(например с помощью Alembic). Манипуляций со структурой БД не происходит. Данные не удаляются.
|
|
||||||
|
|
||||||
- Запуск в режиме "dev" c ключем --run-test-server
|
|
||||||
В этом случае при каждом запуске проекта все таблицы с данными удаляются из БД и создаются снова согласно описанных моделей.
|
|
||||||
|
|
||||||
|
|
||||||
Для запуска проекта сначала активируем виртуальное окружение
|
|
||||||
|
|
||||||
> `$ poetry shell`
|
|
||||||
|
|
||||||
и запускаем проект в соответстующем режиме
|
|
||||||
|
|
||||||
>`$ python manage.py --ключ`
|
|
||||||
|
|
||||||
вместо этого, так же допускается и другой вариант запуска одной командой без предварительной активации окружения
|
|
||||||
|
|
||||||
>`$ poetry run python manage.py --ключ`
|
|
||||||
|
|
||||||
|
|
||||||
## TODO
|
|
||||||
- Добавить миграции
|
|
||||||
- Провести рефакторинг, много дублирующего кода
|
|
||||||
- Много чего другого :)
|
|
||||||
|
|
||||||
## Авторы
|
|
||||||
- Сергей Ванюшкин <pi3c@yandex.ru>
|
|
||||||
|
|
||||||
## Лицензия
|
|
||||||
Распространяется под [MIT лицензией](https://www.opensource.org/licenses/mit-license.php).
|
|
||||||
Подробнее на русском в файле LICENSE.md
|
|
||||||
|
|
|
@ -1,5 +0,0 @@
|
||||||
DB_HOST=localhost
|
|
||||||
DB_PORT=5432
|
|
||||||
DB_USER=postgres
|
|
||||||
DB_PASS=postgres
|
|
||||||
DB_NAME=postgres
|
|
|
@ -1,87 +1,20 @@
|
||||||
from fastapi import FastAPI
|
from fastapi import FastAPI
|
||||||
|
|
||||||
from fastfood.routers.dish import router as dish_router
|
from fastfood.routes import router
|
||||||
from fastfood.routers.menu import router as menu_router
|
|
||||||
from fastfood.routers.submenu import router as submenu_router
|
|
||||||
|
|
||||||
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 = [
|
async def generate_test_data():
|
||||||
{
|
"""
|
||||||
"name": "menu",
|
Создание БД и наполнение ее данными
|
||||||
"description": "Операции с меню.",
|
"""
|
||||||
},
|
pass
|
||||||
{
|
|
||||||
"name": "submenu",
|
|
||||||
"description": "Подменю и работа с ним",
|
|
||||||
},
|
|
||||||
{"name": "dish", "description": "Блюда и работа с ними"},
|
|
||||||
]
|
|
||||||
|
|
||||||
|
|
||||||
def create_app():
|
def create_app():
|
||||||
"""
|
"""
|
||||||
Фабрика FastAPI.
|
Создание экземпляра приложения FastAPI и врзврат его
|
||||||
"""
|
"""
|
||||||
app = FastAPI(
|
app = FastAPI()
|
||||||
title="Fastfood-API",
|
app.include_router(router)
|
||||||
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
|
return app
|
||||||
|
|
|
@ -6,7 +6,7 @@ class Settings(BaseSettings):
|
||||||
DB_PORT: int = 5432
|
DB_PORT: int = 5432
|
||||||
DB_USER: str = "postrges"
|
DB_USER: str = "postrges"
|
||||||
DB_PASS: str = "postgres"
|
DB_PASS: str = "postgres"
|
||||||
DB_NAME: str = "postgres"
|
DB_NAME: str = "demo_db"
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def DATABASE_URL_asyncpg(self):
|
def DATABASE_URL_asyncpg(self):
|
||||||
|
|
|
@ -1,12 +1,18 @@
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
from sqlalchemy import delete, select, update
|
||||||
from sqlalchemy import delete, func, select, update
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from fastfood import models, schemas
|
from fastfood import models, schemas
|
||||||
|
from fastfood.dbase import async_engine
|
||||||
|
|
||||||
|
|
||||||
class MenuCrud:
|
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
|
@staticmethod
|
||||||
async def get_menus(session: AsyncSession):
|
async def get_menus(session: AsyncSession):
|
||||||
async with session:
|
async with session:
|
||||||
|
@ -28,37 +34,15 @@ class MenuCrud:
|
||||||
async with session:
|
async with session:
|
||||||
query = select(models.Menu).where(models.Menu.id == menu_id)
|
query = select(models.Menu).where(models.Menu.id == menu_id)
|
||||||
menu = await session.execute(query)
|
menu = await session.execute(query)
|
||||||
menu = menu.scalars().one_or_none()
|
return 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
|
@staticmethod
|
||||||
async def update_menu_item(
|
async def update_menu_item(menu_id: UUID,
|
||||||
menu_id: UUID,
|
|
||||||
menu: schemas.MenuBase,
|
menu: schemas.MenuBase,
|
||||||
session: AsyncSession,
|
session: AsyncSession,
|
||||||
):
|
):
|
||||||
async with session:
|
async with session:
|
||||||
query = (
|
query = update(models.Menu).where(models.Menu.id == menu_id).values(**menu.model_dump())
|
||||||
update(models.Menu)
|
|
||||||
.where(models.Menu.id == menu_id)
|
|
||||||
.values(**menu.model_dump())
|
|
||||||
)
|
|
||||||
await session.execute(query)
|
await session.execute(query)
|
||||||
await session.commit()
|
await session.commit()
|
||||||
qr = select(models.Menu).where(models.Menu.id == menu_id)
|
qr = select(models.Menu).where(models.Menu.id == menu_id)
|
|
@ -1,19 +0,0 @@
|
||||||
from fastfood import models
|
|
||||||
from fastfood.dbase import async_engine
|
|
||||||
|
|
||||||
from .dish import DishCrud
|
|
||||||
from .menu import MenuCrud
|
|
||||||
from .submenu import SubMenuCrud
|
|
||||||
|
|
||||||
|
|
||||||
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()
|
|
|
@ -1,64 +0,0 @@
|
||||||
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()
|
|
|
@ -1,77 +0,0 @@
|
||||||
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()
|
|
|
@ -1,10 +1,14 @@
|
||||||
from typing import AsyncGenerator
|
from typing import AsyncGenerator
|
||||||
|
|
||||||
from sqlalchemy.ext.asyncio import (AsyncSession, async_sessionmaker,
|
from sqlalchemy.ext.asyncio import (
|
||||||
create_async_engine)
|
AsyncSession,
|
||||||
|
async_sessionmaker,
|
||||||
|
create_async_engine,
|
||||||
|
)
|
||||||
|
|
||||||
from fastfood.config import settings
|
from fastfood.config import settings
|
||||||
|
|
||||||
|
|
||||||
async_engine = create_async_engine(settings.DATABASE_URL_asyncpg)
|
async_engine = create_async_engine(settings.DATABASE_URL_asyncpg)
|
||||||
async_session_maker = async_sessionmaker(
|
async_session_maker = async_sessionmaker(
|
||||||
async_engine,
|
async_engine,
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
import uuid
|
import uuid
|
||||||
|
from decimal import Decimal
|
||||||
from typing import Annotated, List, Optional
|
from typing import Annotated, List, Optional
|
||||||
|
|
||||||
from sqlalchemy import ForeignKey
|
from sqlalchemy import ForeignKey
|
||||||
|
@ -6,7 +7,7 @@ from sqlalchemy.dialects.postgresql import UUID
|
||||||
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
|
from sqlalchemy.orm import DeclarativeBase, Mapped, mapped_column, relationship
|
||||||
|
|
||||||
uuidpk = Annotated[
|
uuidpk = Annotated[
|
||||||
uuid.UUID,
|
int,
|
||||||
mapped_column(
|
mapped_column(
|
||||||
UUID(as_uuid=True),
|
UUID(as_uuid=True),
|
||||||
primary_key=True,
|
primary_key=True,
|
||||||
|
@ -17,40 +18,33 @@ str_25 = Annotated[str, 25]
|
||||||
|
|
||||||
|
|
||||||
class Base(DeclarativeBase):
|
class Base(DeclarativeBase):
|
||||||
id: Mapped[uuidpk]
|
pass
|
||||||
title: Mapped[str_25]
|
|
||||||
description: Mapped[Optional[str]]
|
|
||||||
|
|
||||||
|
|
||||||
class Menu(Base):
|
class Menu(Base):
|
||||||
__tablename__ = "menu"
|
__tablename__ = "menu"
|
||||||
|
|
||||||
submenus: Mapped[List["SubMenu"]] = relationship(
|
id: Mapped[uuidpk]
|
||||||
"SubMenu",
|
title: Mapped[str_25]
|
||||||
backref="menu",
|
description: Mapped[Optional[str]]
|
||||||
lazy="dynamic",
|
submenus: Mapped[List["SubMenu"]] = relationship()
|
||||||
cascade="all, delete",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class SubMenu(Base):
|
class SubMenu(Base):
|
||||||
__tablename__ = "submenu"
|
__tablename__ = "submenu"
|
||||||
|
|
||||||
parent_menu: Mapped[uuid.UUID] = mapped_column(
|
id: Mapped[uuidpk]
|
||||||
ForeignKey("menu.id", ondelete="CASCADE")
|
title: Mapped[str_25]
|
||||||
)
|
description: Mapped[Optional[str]]
|
||||||
dishes: Mapped[List["Dish"]] = relationship(
|
parent_menu: Mapped[UUID] = mapped_column(ForeignKey("menu.id"))
|
||||||
"Dish",
|
dishes: Mapped[List["Dish"]] = relationship()
|
||||||
backref="submenu",
|
|
||||||
lazy="dynamic",
|
|
||||||
cascade="all, delete",
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
class Dish(Base):
|
class Dish(Base):
|
||||||
__tablename__ = "dish"
|
__tablename__ = "dish"
|
||||||
|
|
||||||
price: Mapped[float]
|
id: Mapped[uuidpk]
|
||||||
parent_submenu: Mapped[uuid.UUID] = mapped_column(
|
title: Mapped[str_25]
|
||||||
ForeignKey("submenu.id", ondelete="CASCADE")
|
description: Mapped[Optional[str]]
|
||||||
)
|
price: Mapped[Decimal]
|
||||||
|
parent_submenu: Mapped[UUID] = mapped_column(ForeignKey("submenu.id"))
|
||||||
|
|
|
@ -1,80 +0,0 @@
|
||||||
from typing import List, Optional
|
|
||||||
from uuid import UUID
|
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
|
||||||
|
|
||||||
from fastfood import schemas
|
|
||||||
from fastfood.cruds import crud
|
|
||||||
from fastfood.dbase import get_async_session
|
|
||||||
from fastfood.utils import price_converter
|
|
||||||
|
|
||||||
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)
|
|
|
@ -1,76 +0,0 @@
|
||||||
from uuid import UUID
|
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
|
||||||
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,26 +1,23 @@
|
||||||
from typing import List, Optional
|
from typing import List, Optional
|
||||||
from uuid import UUID
|
|
||||||
|
|
||||||
from fastapi import APIRouter, Depends, HTTPException
|
from fastapi import APIRouter, Depends, HTTPException
|
||||||
|
from sqlalchemy import insert, select
|
||||||
|
from uuid import UUID
|
||||||
from sqlalchemy.ext.asyncio import AsyncSession
|
from sqlalchemy.ext.asyncio import AsyncSession
|
||||||
|
|
||||||
from fastfood import schemas
|
from fastfood import models, schemas
|
||||||
from fastfood.cruds import crud
|
from fastfood.crud import Crud as crud
|
||||||
from fastfood.dbase import get_async_session
|
from fastfood.dbase import get_async_session
|
||||||
|
|
||||||
router = APIRouter(
|
router = APIRouter()
|
||||||
prefix="/api/v1/menus",
|
|
||||||
tags=["menu"],
|
|
||||||
)
|
|
||||||
|
|
||||||
|
|
||||||
@router.get("/", response_model=Optional[List[schemas.Menu]])
|
@router.get("/api/v1/menus", response_model=Optional[List[schemas.Menu]])
|
||||||
async def get_menus(session: AsyncSession = Depends(get_async_session)):
|
async def get_menus(session: AsyncSession = Depends(get_async_session)):
|
||||||
result = await crud.get_menus(session=session)
|
result = await crud.get_menus(session=session)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@router.post("/", status_code=201, response_model=schemas.Menu)
|
@router.post("/api/v1/menus", status_code=201, response_model=schemas.Menu)
|
||||||
async def add_menu(
|
async def add_menu(
|
||||||
menu: schemas.MenuBase,
|
menu: schemas.MenuBase,
|
||||||
session: AsyncSession = Depends(get_async_session),
|
session: AsyncSession = Depends(get_async_session),
|
||||||
|
@ -32,7 +29,7 @@ async def add_menu(
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@router.get("/{menu_id}", response_model=schemas.MenuRead)
|
@router.get("/api/v1/menus/{menu_id}", response_model=schemas.Menu)
|
||||||
async def get_menu(
|
async def get_menu(
|
||||||
menu_id: UUID,
|
menu_id: UUID,
|
||||||
session: AsyncSession = Depends(get_async_session),
|
session: AsyncSession = Depends(get_async_session),
|
||||||
|
@ -43,23 +40,16 @@ async def get_menu(
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@router.patch("/{menu_id}", response_model=schemas.MenuBase)
|
@router.patch("/api/v1/menus/{menu_id}", response_model=schemas.MenuBase)
|
||||||
async def update_menu(
|
async def update_menu(
|
||||||
menu_id: UUID,
|
menu_id: UUID,
|
||||||
menu: schemas.MenuBase,
|
menu: schemas.MenuBase,
|
||||||
session: AsyncSession = Depends(get_async_session),
|
session: AsyncSession = Depends(get_async_session),
|
||||||
):
|
):
|
||||||
result = await crud.update_menu_item(
|
result = await crud.update_menu_item(menu_id=menu_id, menu=menu, session=session)
|
||||||
menu_id=menu_id,
|
|
||||||
menu=menu,
|
|
||||||
session=session,
|
|
||||||
)
|
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|
||||||
@router.delete("/{menu_id}")
|
@router.delete("/api/v1/menus/{menu_id}")
|
||||||
async def delete_menu(
|
async def delete_menu(menu_id: UUID, session: AsyncSession = Depends(get_async_session)):
|
||||||
menu_id: UUID,
|
|
||||||
session: AsyncSession = Depends(get_async_session),
|
|
||||||
):
|
|
||||||
await crud.delete_menu_item(menu_id=menu_id, session=session)
|
await crud.delete_menu_item(menu_id=menu_id, session=session)
|
|
@ -1,4 +1,5 @@
|
||||||
from typing import Optional
|
from decimal import Decimal
|
||||||
|
from typing import List, Optional
|
||||||
from uuid import UUID
|
from uuid import UUID
|
||||||
|
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
|
@ -14,20 +15,9 @@ class MenuBase(BaseModel):
|
||||||
|
|
||||||
class Menu(MenuBase):
|
class Menu(MenuBase):
|
||||||
id: UUID
|
id: UUID
|
||||||
|
title: str
|
||||||
|
description: Optional[str]
|
||||||
|
# submenus: Optional[List[SubMenu]]
|
||||||
|
|
||||||
|
class Config:
|
||||||
class MenuRead(Menu):
|
from_attributes = True
|
||||||
submenus_count: int
|
|
||||||
dishes_count: int
|
|
||||||
|
|
||||||
|
|
||||||
class SubMenuRead(Menu):
|
|
||||||
dishes_count: int
|
|
||||||
|
|
||||||
|
|
||||||
class DishBase(MenuBase):
|
|
||||||
price: float
|
|
||||||
|
|
||||||
|
|
||||||
class Dish(DishBase, Menu):
|
|
||||||
pass
|
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
def price_converter(dish: dict) -> dict:
|
|
||||||
dish.price = str(dish.price)
|
|
||||||
return dish
|
|
20
manage.py
20
manage.py
|
@ -3,12 +3,12 @@ import sys
|
||||||
|
|
||||||
import uvicorn
|
import uvicorn
|
||||||
|
|
||||||
from fastfood.cruds import create_db_and_tables
|
from fastfood.crud import create_db_and_tables
|
||||||
|
|
||||||
|
|
||||||
def run_app():
|
def run_app():
|
||||||
"""
|
"""
|
||||||
Запуск FastAPI
|
Запуск
|
||||||
"""
|
"""
|
||||||
uvicorn.run(
|
uvicorn.run(
|
||||||
app="fastfood.app:create_app",
|
app="fastfood.app:create_app",
|
||||||
|
@ -17,15 +17,13 @@ def run_app():
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
async def recreate():
|
|
||||||
"""Удаление и создание таблиц в базе данных для тестирования"""
|
|
||||||
await create_db_and_tables()
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
if "--run-server" in sys.argv:
|
if "filldb" in sys.argv:
|
||||||
run_app()
|
"""Наполнение БД демонстрационными данными"""
|
||||||
|
pass
|
||||||
|
|
||||||
if "--run-test-server" in sys.argv:
|
if "--run-server" in sys.argv:
|
||||||
asyncio.run(recreate())
|
async def create():
|
||||||
|
await create_db_and_tables()
|
||||||
|
asyncio.run(create())
|
||||||
run_app()
|
run_app()
|
||||||
|
|
|
@ -126,41 +126,6 @@ files = [
|
||||||
{file = "colorama-0.4.6.tar.gz", hash = "sha256:08695f5cb7ed6e0531a20572697297273c47b8cae5a63ffc6d6ed5c201be6e44"},
|
{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]]
|
[[package]]
|
||||||
name = "exceptiongroup"
|
name = "exceptiongroup"
|
||||||
version = "1.2.0"
|
version = "1.2.0"
|
||||||
|
@ -324,87 +289,6 @@ files = [
|
||||||
dev = ["pre-commit", "tox"]
|
dev = ["pre-commit", "tox"]
|
||||||
testing = ["pytest", "pytest-benchmark"]
|
testing = ["pytest", "pytest-benchmark"]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "psycopg2-binary"
|
|
||||||
version = "2.9.9"
|
|
||||||
description = "psycopg2 - Python-PostgreSQL Database Adapter"
|
|
||||||
optional = false
|
|
||||||
python-versions = ">=3.7"
|
|
||||||
files = [
|
|
||||||
{file = "psycopg2-binary-2.9.9.tar.gz", hash = "sha256:7f01846810177d829c7692f1f5ada8096762d9172af1b1a28d4ab5b77c923c1c"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:c2470da5418b76232f02a2fcd2229537bb2d5a7096674ce61859c3229f2eb202"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:c6af2a6d4b7ee9615cbb162b0738f6e1fd1f5c3eda7e5da17861eacf4c717ea7"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:75723c3c0fbbf34350b46a3199eb50638ab22a0228f93fb472ef4d9becc2382b"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:83791a65b51ad6ee6cf0845634859d69a038ea9b03d7b26e703f94c7e93dbcf9"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:0ef4854e82c09e84cc63084a9e4ccd6d9b154f1dbdd283efb92ecd0b5e2b8c84"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ed1184ab8f113e8d660ce49a56390ca181f2981066acc27cf637d5c1e10ce46e"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:d2997c458c690ec2bc6b0b7ecbafd02b029b7b4283078d3b32a852a7ce3ddd98"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_i686.whl", hash = "sha256:b58b4710c7f4161b5e9dcbe73bb7c62d65670a87df7bcce9e1faaad43e715245"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_ppc64le.whl", hash = "sha256:0c009475ee389757e6e34611d75f6e4f05f0cf5ebb76c6037508318e1a1e0d7e"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:8dbf6d1bc73f1d04ec1734bae3b4fb0ee3cb2a493d35ede9badbeb901fb40f6f"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-win32.whl", hash = "sha256:3f78fd71c4f43a13d342be74ebbc0666fe1f555b8837eb113cb7416856c79682"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp310-cp310-win_amd64.whl", hash = "sha256:876801744b0dee379e4e3c38b76fc89f88834bb15bf92ee07d94acd06ec890a0"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:ee825e70b1a209475622f7f7b776785bd68f34af6e7a46e2e42f27b659b5bc26"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1ea665f8ce695bcc37a90ee52de7a7980be5161375d42a0b6c6abedbf0d81f0f"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:143072318f793f53819048fdfe30c321890af0c3ec7cb1dfc9cc87aa88241de2"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:c332c8d69fb64979ebf76613c66b985414927a40f8defa16cf1bc028b7b0a7b0"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:f7fc5a5acafb7d6ccca13bfa8c90f8c51f13d8fb87d95656d3950f0158d3ce53"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:977646e05232579d2e7b9c59e21dbe5261f403a88417f6a6512e70d3f8a046be"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:b6356793b84728d9d50ead16ab43c187673831e9d4019013f1402c41b1db9b27"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_i686.whl", hash = "sha256:bc7bb56d04601d443f24094e9e31ae6deec9ccb23581f75343feebaf30423359"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_ppc64le.whl", hash = "sha256:77853062a2c45be16fd6b8d6de2a99278ee1d985a7bd8b103e97e41c034006d2"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:78151aa3ec21dccd5cdef6c74c3e73386dcdfaf19bced944169697d7ac7482fc"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-win32.whl", hash = "sha256:dc4926288b2a3e9fd7b50dc6a1909a13bbdadfc67d93f3374d984e56f885579d"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp311-cp311-win_amd64.whl", hash = "sha256:b76bedd166805480ab069612119ea636f5ab8f8771e640ae103e05a4aae3e417"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:8532fd6e6e2dc57bcb3bc90b079c60de896d2128c5d9d6f24a63875a95a088cf"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:b0605eaed3eb239e87df0d5e3c6489daae3f7388d455d0c0b4df899519c6a38d"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8f8544b092a29a6ddd72f3556a9fcf249ec412e10ad28be6a0c0d948924f2212"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:2d423c8d8a3c82d08fe8af900ad5b613ce3632a1249fd6a223941d0735fce493"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:2e5afae772c00980525f6d6ecf7cbca55676296b580c0e6abb407f15f3706996"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6e6f98446430fdf41bd36d4faa6cb409f5140c1c2cf58ce0bbdaf16af7d3f119"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:c77e3d1862452565875eb31bdb45ac62502feabbd53429fdc39a1cc341d681ba"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_i686.whl", hash = "sha256:cb16c65dcb648d0a43a2521f2f0a2300f40639f6f8c1ecbc662141e4e3e1ee07"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_ppc64le.whl", hash = "sha256:911dda9c487075abd54e644ccdf5e5c16773470a6a5d3826fda76699410066fb"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:57fede879f08d23c85140a360c6a77709113efd1c993923c59fde17aa27599fe"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-win32.whl", hash = "sha256:64cf30263844fa208851ebb13b0732ce674d8ec6a0c86a4e160495d299ba3c93"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp312-cp312-win_amd64.whl", hash = "sha256:81ff62668af011f9a48787564ab7eded4e9fb17a4a6a74af5ffa6a457400d2ab"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:2293b001e319ab0d869d660a704942c9e2cce19745262a8aba2115ef41a0a42a"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:03ef7df18daf2c4c07e2695e8cfd5ee7f748a1d54d802330985a78d2a5a6dca9"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:0a602ea5aff39bb9fac6308e9c9d82b9a35c2bf288e184a816002c9fae930b77"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:8359bf4791968c5a78c56103702000105501adb557f3cf772b2c207284273984"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:275ff571376626195ab95a746e6a04c7df8ea34638b99fc11160de91f2fef503"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_aarch64.whl", hash = "sha256:f9b5571d33660d5009a8b3c25dc1db560206e2d2f89d3df1cb32d72c0d117d52"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_i686.whl", hash = "sha256:420f9bbf47a02616e8554e825208cb947969451978dceb77f95ad09c37791dae"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_ppc64le.whl", hash = "sha256:4154ad09dac630a0f13f37b583eae260c6aa885d67dfbccb5b02c33f31a6d420"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-musllinux_1_1_x86_64.whl", hash = "sha256:a148c5d507bb9b4f2030a2025c545fccb0e1ef317393eaba42e7eabd28eb6041"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-win32.whl", hash = "sha256:68fc1f1ba168724771e38bee37d940d2865cb0f562380a1fb1ffb428b75cb692"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp37-cp37m-win_amd64.whl", hash = "sha256:281309265596e388ef483250db3640e5f414168c5a67e9c665cafce9492eda2f"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:60989127da422b74a04345096c10d416c2b41bd7bf2a380eb541059e4e999980"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-macosx_11_0_arm64.whl", hash = "sha256:246b123cc54bb5361588acc54218c8c9fb73068bf227a4a531d8ed56fa3ca7d6"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:34eccd14566f8fe14b2b95bb13b11572f7c7d5c36da61caf414d23b91fcc5d94"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:18d0ef97766055fec15b5de2c06dd8e7654705ce3e5e5eed3b6651a1d2a9a152"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:d3f82c171b4ccd83bbaf35aa05e44e690113bd4f3b7b6cc54d2219b132f3ae55"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ead20f7913a9c1e894aebe47cccf9dc834e1618b7aa96155d2091a626e59c972"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_aarch64.whl", hash = "sha256:ca49a8119c6cbd77375ae303b0cfd8c11f011abbbd64601167ecca18a87e7cdd"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_i686.whl", hash = "sha256:323ba25b92454adb36fa425dc5cf6f8f19f78948cbad2e7bc6cdf7b0d7982e59"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_ppc64le.whl", hash = "sha256:1236ed0952fbd919c100bc839eaa4a39ebc397ed1c08a97fc45fee2a595aa1b3"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:729177eaf0aefca0994ce4cffe96ad3c75e377c7b6f4efa59ebf003b6d398716"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-win32.whl", hash = "sha256:804d99b24ad523a1fe18cc707bf741670332f7c7412e9d49cb5eab67e886b9b5"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp38-cp38-win_amd64.whl", hash = "sha256:a6cdcc3ede532f4a4b96000b6362099591ab4a3e913d70bcbac2b56c872446f7"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:72dffbd8b4194858d0941062a9766f8297e8868e1dd07a7b36212aaa90f49472"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:30dcc86377618a4c8f3b72418df92e77be4254d8f89f14b8e8f57d6d43603c0f"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:31a34c508c003a4347d389a9e6fcc2307cc2150eb516462a7a17512130de109e"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl", hash = "sha256:15208be1c50b99203fe88d15695f22a5bed95ab3f84354c494bcb1d08557df67"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_ppc64le.manylinux2014_ppc64le.whl", hash = "sha256:1873aade94b74715be2246321c8650cabf5a0d098a95bab81145ffffa4c13876"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3a58c98a7e9c021f357348867f537017057c2ed7f77337fd914d0bedb35dace7"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:4686818798f9194d03c9129a4d9a702d9e113a89cb03bffe08c6cf799e053291"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_i686.whl", hash = "sha256:ebdc36bea43063116f0486869652cb2ed7032dbc59fbcb4445c4862b5c1ecf7f"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_ppc64le.whl", hash = "sha256:ca08decd2697fdea0aea364b370b1249d47336aec935f87b8bbfd7da5b2ee9c1"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:ac05fb791acf5e1a3e39402641827780fe44d27e72567a000412c648a85ba860"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-win32.whl", hash = "sha256:9dba73be7305b399924709b91682299794887cbbd88e38226ed9f6712eabee90"},
|
|
||||||
{file = "psycopg2_binary-2.9.9-cp39-cp39-win_amd64.whl", hash = "sha256:f7ae5d65ccfbebdfa761585228eb4d0df3a8b15cfb53bd953e713e09fbb12957"},
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pydantic"
|
name = "pydantic"
|
||||||
version = "2.5.3"
|
version = "2.5.3"
|
||||||
|
@ -751,4 +635,4 @@ standard = ["colorama (>=0.4)", "httptools (>=0.5.0)", "python-dotenv (>=0.13)",
|
||||||
[metadata]
|
[metadata]
|
||||||
lock-version = "2.0"
|
lock-version = "2.0"
|
||||||
python-versions = "^3.10"
|
python-versions = "^3.10"
|
||||||
content-hash = "84fe024aa665ddad3077ca7e73054d1a5cb019a9a3e78af917922433ff4b3d8c"
|
content-hash = "7d4c2713da8d969278204677c9f1b4790b62a0114fe51a0d973313bf079b871c"
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1,93 +0,0 @@
|
||||||
{
|
|
||||||
"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"
|
|
||||||
}
|
|
|
@ -12,8 +12,6 @@ fastapi = "^0.109.0"
|
||||||
uvicorn = "^0.26.0"
|
uvicorn = "^0.26.0"
|
||||||
asyncpg = "^0.29.0"
|
asyncpg = "^0.29.0"
|
||||||
pydantic-settings = "^2.1.0"
|
pydantic-settings = "^2.1.0"
|
||||||
psycopg2-binary = "^2.9.9"
|
|
||||||
email-validator = "^2.1.0.post1"
|
|
||||||
|
|
||||||
|
|
||||||
[tool.poetry.group.dev.dependencies]
|
[tool.poetry.group.dev.dependencies]
|
||||||
|
|
Loading…
Reference in New Issue