skip to Main Content

I’m trying to make multiple different message handlers, is this an acceptable way to register multiple ones?:

import asyncio

from aiogram import Bot, Dispatcher, types
from settings import BOT_TOKEN


async def start_handler(event: types.Message):
    await event.answer(
        f"Hello, {event.from_user.get_mention(as_html=True)} 👋!",
        parse_mode=types.ParseMode.HTML,
    )

async def echo_answer(event: types.Message):
    await event.answer(event.text, parse_mode=types.ParseMode.HTML
    )


async def main():
    bot = Bot(token=BOT_TOKEN)
    try:
        disp = Dispatcher(bot=bot)
        disp.register_message_handler(start_handler, commands={"start", "restart"})
        disp.register_message_handler(echo_answer, lambda msg: msg.text)
        await disp.start_polling()
    finally:
        await bot.close()

asyncio.run(main())

my settings.py file contains

import os

BOT_TOKEN = os.getenv('BOT_TOKEN')
if not BOT_TOKEN:
    print('You have forgot to set BOT_TOKEN')
    BOT_TOKEN = 'missing'
    quit()

This code runs, and sends echo responses to any message and replies with Hello, @username 👋! for start and restart commands.
to reproduce one must have a bot and have a BOT_TOKEN in the environmental variables before running the code.

I tried this code, described above, looked ad https://docs.aiogram.dev/en/latest/dispatcher/index.html documentation and modified example on the source code page https://github.com/aiogram/aiogram#poll-botapi-for-updates-and-process-updates

2

Answers


  1. I faced the same problem, so I made little dive into source code of aiogram.

    Handlers in Dispatcher instance held in multiple properties.

    • message_handlers
    • edited_message_handlers
    • channel_post_handlers
    • and etc (you can view full list of them in autocomplete of your IDE or at source code page)

    Every handler is instance of Handler class, so they have once property, that shows, can mulltiple handlers be called on one message

    So in your case, you should set message_handlers.once to False

    async def main():
        bot = Bot(token=BOT_TOKEN)
        try:
            disp = Dispatcher(bot=bot)
            disp.message_handlers.once = False 
            disp.register_message_handler(start_handler, commands={"start", "restart"})
            disp.register_message_handler(echo_answer, lambda msg: msg.text)
            await disp.start_polling()
        finally:
            await bot.close()
    
    Login or Signup to reply.
  2. so first you need a variable with handlers you need to register.
    since dispatcher.register takes in callable, then *filters and then keywords you’ve
    got to be percise with what you will pass in.

    How I would do it (example):

    bot = Bot(TOKEN, parse_mode='HTML')
    dispatcher = Dispatcher(bot)
    register_handlers = [
        
        (help_handler, (filters.CommandHelp()), {"state": "*"}),
        # Example of handler with tuple of filters (only 1 here)
    
        (start_handler, {"commands": ["start"], "state": "*"}),
        # Example of handler with no filters, but keywords
    ]
    for handler in register_handlers:
        if isinstance(handler[1], dict):
            dispatcher.register(handler[0], **handler[1])
        else:
            dispatcher.register(handler[0], *handler[1], **handler[2])
    

    So the tirck is to always pass some keywords as a dict into register_handlers.

    If you are aiogram creator or contributor – please read this

    Please make *filters in dispatcher.register function a keyword, that takes in iterable of filters. This will ease registering multiple handlers dramatically. Thank you.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search