Search code examples
pythontelegram-botaiogram

How do i iterate and display the next product from database in python TelegramBot (aiogram)?


Im running a test project that fetches data from mysql and i added two inline keyboards ("next" and "previous"). I want to display image and whenever the next button is pressed, i want to display the next picture and whenever previous button is pressed, the previous product image will be displayed. I need help How do i do it?

Here is my code

from aiogram import types, Dispatcher, Bot, executor
import logging
import utils
import mysql.connector as connector

connection = connector.connect(
    database = 'awesugn_products',
    host = 'localhost',
    username = 'root',
    password = 'root'
)

bot = Bot(token=utils.TOKEN)
dp = Dispatcher(bot)

logging.basicConfig(level=logging.INFO)

class database_wrapper:
    def fetch_image():
        cursor = connection.cursor()
        cursor.execute("SELECT img FROM Image")
        rows = cursor.fetchall()
        for r in rows:
            r = r[0]
            # print(r)
            return r

@dp.message_handler(commands='start')
async def start (message: types.Message):
    keyboard_markup = types.InlineKeyboardMarkup()
    
    text_value = (("Previous", "previous"), ("Next","next"))

    row_btns = (types.InlineKeyboardButton(text, callback_data=data)for text, data in text_value)
    keyboard_markup.add(*row_btns)

    await message.answer_photo(database_wrapper.fetch_image(), reply_markup=keyboard_markup)


@dp.callback_query_handler(text='next')
async def inline_keyboard(query: types.CallbackQuery):
    answer_data = query.data
    await query.answer(f'You answered with {answer_data!r}')

    if answer_data == "next":
        await bot.send_message(query.from_user.id, "next")
if __name__ == '__main__':
    executor.start_polling(dp, skip_updates=True)

Solution

  • I usually do this:

    • Get length of values list
    • Create buttons with page № stored in its callback
    • Use some sort of id which I link to number in callback

    In code it looks like this:

    connection = connector.connect(
        database = 'awesugn_products',
        host = 'localhost',
        username = 'root',
        password = 'root'
    )
    cursor = connection.cursor()
    
    def construct_keyboard(data: tuple, page: int) -> types.InlineKeyboardMarkup:
        length=len(data)
        kb={'inline_keyboard': []}
        buttons=[]
        if page > 1: #preventing going to -1 page
            buttons.append({'text':'<-', 'callback_data':f'page_{page-1}'})
        #adding a neat page number
        buttons.append({'text':f'{page}/{length}', 'callback_data':'none')
        if page < length: #preventing going out of range
            buttons.append({'text':'->', 'callback_data':f'page_{page+1}') 
        kb['inline_keyboard'].append(buttons)
        return kb
    
    @dp.message_handler(commands='start')
    async def start (message: types.Message):
        data=cursor.execute("SELECT img FROM Image").fetchall()
        image=data[0][0] #here you have to set 1st page manually
        await message.answer_photo(image, reply_markup=construct_keyboard(data, 1)
    
    @dp.callback_query_handler(text_startswith='page_')
    async def page(call: types.CallbackQuery):
        page=int(call.data.split('_')[1])
        #get value by id (page)
        data=cursor.execute("SELECT img FROM Image").fetchall()
        image=data[page-1][0]
        await bot.send_photo(call.message.chat.id, image, reply_markup=construct_keyboard(data, page)
    

    Hope it helps!