Приветствую! Времени с последней записи прошло прилично, так что собраться с мыслями и продолжить было сложновато. А готовые черновики с тех времен были рассмотрены и.. переписаны заново..
Итак. Вторая часть затронула фильтры. Фильтры для базовых команд, которые заботливо предоставляет сам AIOGram, и фильтры по типу чата. Кроме этих есть ещё несколько крутых фильтров, ссылку на разбор которых я прикреплю ниже. Но реально крутая штука – свои фильтры, о них тоже сегодня поговорим.
Фильтры в AIOGram (взято тут)
- Command — проверка сообщения на команду
- CommandHelp — проверка на команду
/help
- CommandPrivacy — проверка на команду
/privacy
- CommandSettings — проверка на команду
/settings
- CommandStart — проверка на команду
/start
- ContentTypeFilter — проверка типа контента
- ExceptionsFilter — исключение для errors_handler
- HashTag — обработка сообщений с #hashtag и $cashtags
- Regexp — регулярное выражение для сообщений callback query
- RegexpCommandsFilter — проверка команды регулярным выражением
- StateFilter — проверка состояния пользователя
- Text — фильтр текста. Работает на большинстве обработчиков
- IDFilter — фильтр для проверки id чата или пользователя
- AdminFilter — проверка на то, является ли пользователь администратором чата
- IsReplyFilter — проверяет, что отправленное сообщение является ответом
- IsSenderContact — проверяет, что пользователь отправил именно свой контакт
- ForwardedMessageFilter — проверка на то, что сообщение переслано
- ChatTypeFilter — проверка типа чата
Добавляем свой фильтр
Но если вы хотите сделать свой фильтр, то AIOGram и для этого даёт инструменты. Добавим новую папку filters. Pycharm создаст _init_, он нам пригодится позже. И создаём там новый файл: private_chat_filter.py. Пишем в него такой код:
1 2 3 4 5 6 |
from aiogram import types from aiogram.dispatcher.filters import BoundFilter class PrivateChatFilter(BoundFilter): async def check(self, message: types.Message): return len(message.text.replace(".", "")) == 0 |
Наш фильтр наследует BoundFilter, это специальный класс в AIOGram для создания своих фильтров. Функция check наследуется из абстрактного класса AbstractFilter, и проверка условия фильтра происходит именно тут:
1 2 |
async def check(self, message: types.Message): return len(message.text.replace(".", "")) == 0 |
Если простыми словами, то мы получаем сообщение и прогоняем его handlers бота. У них могут быть фильтры, и если условие совпадёт – выполняется соответствующая функция. Главное не забывать, что этот поиск происходит до первого соответствия, а дальше проверка идти не будет.
Теперь в файле init биндим фильтр:
1 2 3 4 5 6 |
from aiogram import Dispatcher from .private_chat_filter import PrivateChatFilter def setup(dp: Dispatcher): pass dp.filters_factory.bind(PrivateChatFilter) |
А функцию setup нужно вызывать при запуске бота. Так что переходим на новый уровень сознания и добавляем функцию-слушатель запуска нашего бота. В предыдущей версии мы запускали бота так:
1 2 3 |
if __name__ == '__main__': from handlers import dp executor.start_polling(dp, skip_updates=True) |
Но у нас есть возможность выполнять какие-либо операции при запуске бота, для этого просто добавляем ещё один параметр:
1 2 3 |
if __name__ == '__main__': from handlers import dp executor.start_polling(dp, on_startup=on_startup) |
И в этом же файле создаём функцию с таким именем:
1 2 3 |
async def on_startup(dp): logging.warning("Start Bot!") filters.setup(dp) |
Подведем итоги. Мы добавили фильтр и функцию, которая будет вызываться при каждом запуске бота. Теперь давайте используем его в файле personal_start.py, который мы использовали для приветствия игрока в ЛС.
Было:
1 2 3 4 5 6 7 8 |
from aiogram import types from aiogram.dispatcher.filters.builtin import CommandStart, ChatTypeFilter from main import dp @dp.message_handler(CommandStart(), ChatTypeFilter(chat_type=types.ChatType.PRIVATE)) async def bot_start(message: types.Message): await message.answer(f'Привет, {message.from_user.full_name}!') |
Стало:
1 2 3 4 5 6 7 8 9 |
from aiogram import types from aiogram.dispatcher.filters.builtin import CommandStart, ChatTypeFilter from filters import PrivateChatFilter from main import dp @dp.message_handler(CommandStart(), PrivateChatFilter()) async def bot_start(message: types.Message): await message.answer(f'Привет, {message.from_user.full_name}!') |
Функционал не изменился, но выглядит лучше. IMHO 😀
Возможности фильтров AIOGram
На самом деле пример очень простой, и может показаться излишеством, ведь проверка подобная уже есть. Но фильтры предлагают куда более широкий спектр возможностей. Например, фильтр, проверяющий, что отправитель сообщения — это человек из особого списка юзеров бота. Сделайте проверку на свой айди и получите фильтр, который будет реагировать только на ваши сообщения! (P.S. с последним пример спорный, ведь для проверки ID юзера уже есть IDFilter, просто пример)
1 2 3 4 5 6 7 8 |
from aiogram import types from aiogram.dispatcher.filters import BoundFilter import main class BotAdminsFilter(BoundFilter): async def check(self, message: types.Message) -> bool: return main.admins.__contains__(message.from_user.id) |
А вот мой, чутка дурацкий фильтр, который проверяет, что сообщение состоит только из точек:
1 2 3 4 5 6 7 |
from aiogram import types from aiogram.dispatcher.filters import BoundFilter class IsDotsMessage(BoundFilter): async def check(self, message: types.Message): return len(message.text.replace(".", "")) == 0 |
Можно сделать фильтры на тип сообщения, на его контент, на юзеров, чаты и т.д. Иными словами: вас ограничивает лишь фантазия и функционал TG.
Дополнение
Кстати, хотите, чтобы ваш бот в ЛС умел присылать ваш ID? Легче простого!
Создаём файл user_id.py (в папке personal) и пишем туда:
1 2 3 4 5 6 7 8 |
from aiogram import types from filters import PrivateChatFilter from main import dp @dp.message_handler(PrivateChatFilter(), commands=["id"]) async def get_my_id(message: types.Message): await message.answer(f'Ваш id: {message.from_user.id}') |
Думаю, что понятно всё? Фильтр сработает в ЛС на команду /id. Реакцией будет ответ на сообщение с id 😀
Регистрируем в _init_
1 2 3 4 5 |
from .user_id import dp from .personal_start import dp from .echo import dp __all__ = ["dp"] |
Запускаем, проверяем!
Спасибо за внимание, постараюсь больше не умирать так надолго)
1 часть: [AIOGram | Python] Урок 1. Вступление. Простой бот
2 часть: [AIOGram] Урок 2. Наводим порядки и добавляем фильтры