From 3dbefda93683ce55228002563ba4b571bd85d375 Mon Sep 17 00:00:00 2001 From: pi3c Date: Sun, 11 Feb 2024 20:10:25 +0300 Subject: [PATCH] =?UTF-8?q?upd:=20=D0=9F=D1=80=D0=B8=D0=BC=D0=B5=D0=BD?= =?UTF-8?q?=D0=B5=D0=BD=D0=B8=D0=B5=20=D1=81=D0=BA=D0=B8=D0=B4=D0=BA=D0=B8?= =?UTF-8?q?=20=D0=B2=20=D0=B2=D1=8B=D0=B2=D0=BE=D0=B4=D0=B5=20API?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- admin/Menu.xlsx | Bin 10342 -> 10342 bytes bg_tasks/bg_task.py | 7 +------ bg_tasks/updater.py | 2 +- fastfood/service/dish.py | 33 +++++++++++++++++++++------------ fastfood/service/summary.py | 34 +++++++++++++++++++++++++++++----- manage.py | 8 ++++---- 6 files changed, 56 insertions(+), 28 deletions(-) diff --git a/admin/Menu.xlsx b/admin/Menu.xlsx index ec412aeca1bdc7ef8f6669f46bba94796b91d531..ac0262075865bd6f07388245aa3a22805f905de4 100644 GIT binary patch delta 5170 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 diff --git a/bg_tasks/bg_task.py b/bg_tasks/bg_task.py index 1ad4aba..c73b51e 100644 --- a/bg_tasks/bg_task.py +++ b/bg_tasks/bg_task.py @@ -22,12 +22,7 @@ celery_app.conf.beat_schedule = { } -celery_task_app = Celery( - 'tasks', broker='amqp://guest:guest@localhost', backend='rpc://' -) - - -@celery_task_app.task +@celery_app.task def periodic_task() -> None: result = loop.run_until_complete(main()) return result diff --git a/bg_tasks/updater.py b/bg_tasks/updater.py index d1cf1e1..339b434 100644 --- a/bg_tasks/updater.py +++ b/bg_tasks/updater.py @@ -26,7 +26,7 @@ async def refresh_cache(disconts: dict): await redis.flushall() for key in disconts.keys(): - await redis.set(f'DISCONT:{str(key)}', disconts[key]) + await redis.set(f'DISCONT:{str(key)}', pickle.dumps(disconts[key])) await redis.set('XLSX_MOD_TIME', pickle.dumps(os.path.getmtime(file))) diff --git a/fastfood/service/dish.py b/fastfood/service/dish.py index 689f4f0..981cf09 100644 --- a/fastfood/service/dish.py +++ b/fastfood/service/dish.py @@ -3,6 +3,7 @@ from uuid import UUID import redis.asyncio as redis # type: ignore from fastapi import BackgroundTasks, Depends +from fastfood import models from fastfood.dbase import get_async_redis_client from fastfood.repository.dish import DishRepository from fastfood.repository.redis import RedisRepository, get_key @@ -21,6 +22,19 @@ class DishService: self.bg_tasks = background_tasks self.key = get_key + async def _get_discont(self, dish) -> dict: + discont = await self.cache.get(f"DISCONT:{str(dish.get('id'))}") + if discont is not None: + discont = float(discont) + dish['price'] = round(dish['price'] - (dish['price'] * discont / 100), 2) + return dish + + async def _convert_dish_to_dict(self, row: models.Dish) -> Dish: + dish = row.__dict__ + dish = await self._get_discont(dish) + dish['price'] = str(dish['price']) + return Dish(**dish) + async def read_dishes(self, menu_id: UUID, submenu_id: UUID) -> list[Dish]: cached_dishes = await self.cache.get( self.key('dishes', menu_id=str(menu_id), submenu_id=str(submenu_id)) @@ -31,9 +45,9 @@ class DishService: data = await self.dish_repo.get_dishes(menu_id, submenu_id) response = [] for row in data: - dish = row.__dict__ - dish['price'] = str(dish['price']) - response.append(Dish(**dish)) + dish = await self._convert_dish_to_dict(row) + response.append(dish) + await self.cache.set( self.key( 'dishes', @@ -57,9 +71,7 @@ class DishService: submenu_id, dish_db, ) - dish = data.__dict__ - dish['price'] = str(dish['price']) - dish = Dish(**dish) + dish = await self._convert_dish_to_dict(data) await self.cache.set( self.key('dish', menu_id=str(menu_id), submenu_id=str(submenu_id)), dish, @@ -86,9 +98,8 @@ class DishService: data = await self.dish_repo.get_dish_item(menu_id, submenu_id, dish_id) if data is None: return None - dish = data.__dict__ - dish['price'] = str(dish['price']) - dish = Dish(**dish) + dish = await self._convert_dish_to_dict(data) + await self.cache.set( self.key( 'dish', @@ -112,9 +123,7 @@ class DishService: if data is None: return None - dish = data.__dict__ - dish['price'] = str(dish['price']) - dish = Dish(**dish) + dish = await self._convert_dish_to_dict(data) await self.cache.set( self.key( diff --git a/fastfood/service/summary.py b/fastfood/service/summary.py index 2c1a412..735c53f 100644 --- a/fastfood/service/summary.py +++ b/fastfood/service/summary.py @@ -20,29 +20,53 @@ class SummaryService: self.bg_tasks = background_tasks async def read_data(self): - def dump_to_schema(schema, obj): + + result = [] + + async def dump_to_schema( + schema, obj + ) -> MenuSummary | SubMenuSummary | DishBase: + """Функция преобразует объект SQLAlchemy к Pydantic модели + + Входящие параметры + schema: Pydantic модель + obj: ORM объект + + Возвращаемые данные + schema: MenuSummary | SubMenuSummary | DishBase + """ obj = obj.__dict__ obj = {k: v for k, v in obj.items() if not k.startswith('_')} + if 'price' in obj.keys(): + discont = await self.cache.get(f"DISCONT:{str(obj.get('id'))}") + + if discont is not None: + discont = float(discont) + obj['price'] = round( + obj['price'] - (obj['price'] * discont / 100), 2 + ) obj['price'] = str(obj['price']) + return schema(**obj) cached_data = await self.cache.get(self.key('summary')) + if cached_data is not None: return cached_data - result = [] data = await self.sum_repo.get_data() + for menu in data: - menus_res = dump_to_schema(MenuSummary, menu) + menus_res = await dump_to_schema(MenuSummary, menu) menus_res.submenus = [] for sub in menu.submenus: - sub_res = dump_to_schema(SubMenuSummary, sub) + sub_res = await dump_to_schema(SubMenuSummary, sub) sub_res.dishes = [] for dish in sub.dishes: - dish_res = dump_to_schema(DishBase, dish) + dish_res = await dump_to_schema(DishBase, dish) sub_res.dishes.append(dish_res) menus_res.submenus.append(sub_res) diff --git a/manage.py b/manage.py index a05d492..cb5762c 100644 --- a/manage.py +++ b/manage.py @@ -10,11 +10,11 @@ from fastfood.repository import create_db_and_tables loop = asyncio.get_event_loop() -def start_celery_worker(): +def start_celery_worker() -> None: Popen(['celery', '-A', 'bg_tasks.bg_task.celery_app', 'worker', '--loglevel=info']) -def start_celery_beat(): +def start_celery_beat() -> None: Popen(['celery', '-A', 'bg_tasks.bg_task.celery_app', 'beat', '--loglevel=info']) @@ -22,7 +22,7 @@ celery_worker_process = multiprocessing.Process(target=start_celery_worker) celery_beat_process = multiprocessing.Process(target=start_celery_beat) -async def run_app(): +async def run_app() -> None: """ Запуск FastAPI """ @@ -36,7 +36,7 @@ async def run_app(): ) -async def recreate(): +async def recreate() -> None: """Удаление и создание таблиц в базе данных для тестирования""" await create_db_and_tables()