Наступило время внести изменения в наши проекты и разделить их на файлы. В этом нам поможет класс Router(), а именно его объект, который заменит объект dp (от класса Dispatcher).
Router необходим для того, чтобы распределить обработчики запросов по файлам и получить более удобную и понятную структуру проекта. Структура папок будет организована следующим образом:
Была создана папка app, внутри которой создали файл handlers.py. В нём будут все основные обработчики.
Затем в этой папке будут созданы папки и файлы для базы данных, клавиатуры, административной панели и других частей проекта.
В файле handlers будет такой код:
from aiogram import Router, F
from aiogram.types import Message
from aiogram.filters import CommandStart, CommandObject
router = Router()
@router.message(CommandStart(deep_link=True, magic=F.args.isdigit()))
async def cmd_start(message: Message, command: CommandObject):
await message.answer(f'Привет! Ты пришел от {command.args}')
@router.message(F.photo)
async def get_photo(message: Message):
await message.answer(f'ID фотографии: {message.photo[-1].file_id}')
Как можно заметить, обработчики запросов были перемещены из файла run в файл handlers. Вместе с ними был импортирован класс Router и создан объект router. В декораторах обработчиков я заменил dp на router. Затем в файле run удалил все обработчики, перенеся создание объектов в функцию main.
Также было добавлено подключение роутера. Это очень важный момент:
from app.handlers import router
...
dp.include_router(router)
И теперь весь файл run выглядит следующим образом:
import os
import asyncio
from aiogram import Bot, Dispatcher
from dotenv import load_dotenv
import logging
from app.handlers import router l
oad_dotenv()
async def main():
bot = Bot(token=os.getenv('TOKEN'))
dp = Dispatcher()
dp.include_router(router)
await dp.start_polling(bot)
if __name__ == '__main__':
logging.basicConfig(level=logging.INFO)
try:
asyncio.run(main())
except:
print('Exit')
Что произошло?
Чтобы структурировать проект и разделить различные функциональные части программы, обработчики из основного файла были перемещены в файл handlers.
Затем в файле handlers был создан экземпляр класса Router, который был передан в Dispatcher через include_router. Благодаря роутеру мы можем переносить обработчики в другие файлы и просто передавать эти роутеры диспетчеру.
Теперь файл run является точкой входа. Это основной скрипт, запускающий все остальные.
Как это работает?
Например, у диспетчера есть два роутера, а у последнего роутера есть ещё один дополнительный роутер:
В этом случае, процесс обработки обновления будет работать следующим образом:
Из этого вывод, что роутер - это просто аналог диспетчера. Вся проблема в том, что мы не можем просто импортировать диспетчер в другой файл, поэтому пользуемся роутером.
Пример из документации: https://docs.aiogram.dev/en/latest/dispatcher/finite_state_machine/index.html
P.S. Даже если эта статья потеряет свою актуальность, она всё равно будет служить мне напоминанием о некоторых командах и избавит меня от необходимости искать их снова в интернете. Возможно, спустя пару лет я вернусь к этой статье и освежу свои знания. А тем, кто дочитал до конца, я желаю, чтобы ваши труды, проекты и творческие работы всегда оставались актуальными и востребованными! =)