AIOGRAM, SQLALCHEMY Как вывести рандомную позицию из базы данных?

Подскажите, пожалуйста, как вывести из БД одну рандомную позицию. У меня есть несколько категорий, в них по несколько позиций. Пока что бот выводит все позиции по конкретной категории, но нужна одна - случайная (по конкретной категории). Знаю про random.choice и order_by(func.random()), но непонятно, где именно это лучше делать (в сессиях к бд или хендлерах) и как делать.

P.S. Делаю бота по фильмам (выводит постер фильма, описание, рейтинг, жанр). Не судите строго, я любитель

Таблицы:

class Category(Base):
    __tablename__ = 'categories'

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))

    item_rel: Mapped[List['Item']] = relationship(back_populates='category_rel')


class Item(Base):
    __tablename__ = 'items'

    id: Mapped[int] = mapped_column(primary_key=True)
    name: Mapped[str] = mapped_column(String(100))
    description: Mapped[str] = mapped_column(String(200))
    photo: Mapped[str] = mapped_column(String(200))
    rating: Mapped[int] = mapped_column()
    genre: Mapped[str] = mapped_column(String(200))
    category: Mapped[int] = mapped_column(ForeignKey('categories.id'))

    category_rel: Mapped['Category'] = relationship(back_populates='item_rel')

сессии БД:


async def get_categories():
    async with async_session() as session:
        categories = await session.scalars(select(Category))
        return categories

async def get_items_by_category(category_id: int):
    async with async_session() as session:
        items = await session.scalars(select(Item).where(Item.category == category_id))
        return items

async def get_category():
    async with async_session() as session:
        category = await session.scalars(select(Category).where(Category.id == 1))
        return category

async def get_item_by_id(item_id: int):
    async with async_session() as session:
        item = await session.scalar(select(Item).where(Item.id == item_id).order_by(func.random()).limit(1))
        return item

Кнопки:

async def categories():
    all_categories = await get_categories()
    keyboard = InlineKeyboardBuilder()
    for category in all_categories:
        keyboard.add(InlineKeyboardButton(text=category.name,
                                          callback_data=f'category_{category.id}'))
    return keyboard.adjust(2).as_markup()

async def category():
    all_categories = await get_category()
    keyboard = InlineKeyboardBuilder()
    for category in all_categories:
        keyboard.add(InlineKeyboardButton(text='Случайный фильм',
                                          callback_data=f'randomz_{category.id}'))
    return keyboard.adjust(2).as_markup()

Хендлеры:

@router.callback_query(F.data.startswith('category_'))
async def category(callback: CallbackQuery):
    items = await get_items_by_category(callback.data.split('_')[1])
    item = await get_item_by_id(callback.data.split('_')[1])
    for item in items:
        await callback.message.answer_photo(photo=item.photo, caption=f'<strong>{item.name}</strong>\n\n<b>Рейтинг:</b> {item.rating}\n\n<b>Рейтинг:</b> {item.genre}\n\n{item.description}')
    await callback.answer('')

@router.callback_query(F.data.startswith('randomz_'))
async def randomz(callback: CallbackQuery):
    items = await get_items_by_category(callback.data.split('_')[1])
    item = await get_item_by_id(callback.data.split('_')[1])
    for item in items:
        await callback.message.answer_photo(photo=item.photo, caption=f'<strong>{item.name}</strong>\n\n<b>Рейтинг:</b> {item.rating}\n\n<b>Рейтинг:</b> {item.genre}\n\n{item.description}')
    await callback.answer('')

Ответы (1 шт):

Автор решения: SVBazuev

Конечно в сессии БД:

import random


async def get_items_by_category(category_id: int):
    async with async_session() as session:
        items = await session.scalars(
            select(Item).where(Item.category == category_id))
        return random.choice(items)

или...

from sqlalchemy import func


async def get_items_by_category(category_id: int):
    async with async_session() as session:
        random_item = await session.scalars(
            select(Item).where(Item.category == category_id
                               ).order_by(func.random()).limit(1)
            ).first()
        return random_item
→ Ссылка