When we register a handler, we specify what command it should respond to, what type of message to accept, etc. For example:
@dp.message_handler(is_admin=True, commands=['kick'], commands_prefix='!/', chat_type=[ChatType.GROUP, ChatType.SUPERGROUP]) async def kick_user(message: Message):
As you can see, here the handler will be executed only when:
- this will be the kick command;
- the command starts with "!" or "/";
- The command is written in a group or supergroup.
These are all called filters. Somewhere deep in the library, handler registration takes place, where its filters are registered for each handler:
def register(self, handler, filters=None, index=None): """ Register callback Filters can be awaitable or not. :param handler: coroutine :param filters: list of filters :param index: you can reorder handlers """ from .filters import get_filters_spec spec = _get_spec(handler) if filters and not isinstance(filters, (list, tuple, set)): filters = [filters] filters = get_filters_spec(self.dispatcher, filters) record = Handler.HandlerObj(handler=handler, spec=spec, filters=filters) if index is None: self.handlers.append(record) else: self.handlers.insert(index, record)
If we look at what the handle decorator accepts, we will see the following:
and today we will learn to create a custom filter.
First, we need to create a file in the filters folder, for example,
┃ ┣ 📜admin.py
┃ ┗ 📜init.py
and add the following code inside:
from aiogram import types from aiogram.dispatcher.filters import BoundFilter class IsAdminFilter(BoundFilter): key = 'is_admin' def __init__(self, is_admin): self.is_admin = is_admin async def check(self, message: types.Message) -> bool: member = await message.bot.get_chat_member(message.chat.id, message.from_user.id) return member.is_chat_admin()
As you can see, the filter is a simple Python class that inherits a BoundFilter class that allows us to create our own filters. We have a field
key = 'is_admin' that shows how we will describe our filter in the handlers. In addition to the structure, we have the main method
async def check(). You can describe any of your logic inside it, but this method must return a Boolean value (True or False).
Simply creating a class is not enough. Next, you need to go to the
bot.py file, import out filter and bind it to the dispatcher:
... from tgbot.config import load_config from tgbot.services.setting_commands import set_default_commands from tgbot.filters.admin import IsAdminFilter ... def register_all_filters(dispatcher: Dispatcher) -> None: logger.info('Registering filters') dispatcher.filters_factory.bind(IsAdminFilter)
Now we can add our filter to the handlers as I showed in the first picture. In this article, we will not yet write handlers for administering chats.
For now, let's program the handlers for the two commands:
from aiogram.types import Message from aiogram.dispatcher.filters.builtin import CommandStart from loader import dp @dp.message_handler(CommandStart()) async def start_command(message: Message) -> Message: return await message.answer('Add a bot to the chat, give the administrator permissions and use it')
from aiogram.types import Message from aiogram.dispatcher.filters.builtin import CommandHelp from loader import dp @dp.message_handler(CommandHelp()) async def help_command(message: Message) -> Message: """ This handler will be called when a user sends `/help` command """ return await message.answer(""" User's command: /help - get commands /admins - get chat admins /dice - roll a dice Administrator's command: !kick - kick a user !ban - ban a user !mute - mute a user !unmute, !unban - opposite commands """)
Here, the decorators have already used filters built into aiogram. The entire list of such filters can be found here.
Thank you for reading! ❤️ ❤️ ❤️