5.7 Написание запросов к БД используя SQLAlchemy, часть 2
3 из 3 шагов пройдено

Приступим к реализации функции product_by_category, отвечающую за вывод товаров из определенной категории.

@router.get('/{category_slug}')
async def product_by_category(db: Annotated[Session, Depends(get_db)], category_slug: str):
    category = db.scalar(select(Category).where(Category.slug == category_slug))
    if category is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail='Category not found'
        )
    subcategories = db.scalars(select(Category).where(Category.parent_id == category.id)).all()
    categories_and_subcategories = [category.id] + [i.id for i in subcategories]
    products_category = db.scalars(
        select(Product).where(Product.category_id.in_(categories_and_subcategories), Product.is_active == True,
                              Product.stock > 0)).all()
    return products_category

Разберем логику работы. Первым делом нам нужно проверить наличие данной категории, в случае отсутствия вызвать соответствующую ошибку.

    category = db.scalar(select(Category).where(Category.slug == category_slug))
    if category is None:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail='Category not found'
        )

Так как таблица Category является самоссылающаяся, то есть внутри нее есть ключ, который ссылается на эту таблицу, нам нужно получить ID всех ее подкатегорий.

subcategories = db.scalars(select(Category).where(Category.parent_id == category.id)).all()

В результате выполнения мы получаем список с ID подкатегорий, например [2, 3, 4]. Далее нам необходимо сделать так, чтобы в одном списке была наша категория и ее подкатегории:

categories_and_subcategories = [category.id] + [i.id for i in subcategories]

В случае, если мы получаем в переменной category_slug категорию или подкатегорию, у которой не содержится еще подкатегорий. То в данном списке будет только ID категории с переменной category_slug.

И в заключении мы выполняем запрос, где фильтруем наш товар через метод IN , а также получаем только активные товары с остатком более 0.

    products_category = db.scalars(
        select(Product).where(Product.category_id.in_(categories_and_subcategories), Product.is_active == True,
                              Product.stock > 0)).all()

Метод IN работает следующим образом:

stmt = select(User.id).where(User.id.in_([1, 2, 3]))
>>> result = db.execute(stmt)

Подробнее о методе IN вы можете посмотреть в документации. Запустим сервер и проверим работу. На данном этапе у меня в бд хранятся следующие категории и товары:

Я добавлю еще одну подкатегорию IPhone, которая будет подкатегорией у Apple и несколько товаров в нее:

 

Проверим эту логику работы:

Мы видим что логика данной конечной точки у нас прекрасно работает, в следующем шаге продолжим разработку проекта.


Будьте вежливы и соблюдайте наши принципы сообщества. Пожалуйста, не оставляйте решения и подсказки в комментариях, для этого есть отдельный форум.
Нет обсуждений. Начните первое.