{
"$type": "site.standard.document",
"bskyPostRef": {
"cid": "bafyreibsqe7nli24rr3o4xvz4e3fo5nqonhgtvfhaoqvn5qarhiabvpo3i",
"uri": "at://did:plc:25rdn5elo5izoxrmtis34zuk/app.bsky.feed.post/3mplhonxcrby2"
},
"coverImage": {
"$type": "blob",
"ref": {
"$link": "bafkreifozmaufhcdrnaehruzcd4wr4tsjjxbwvuixilrjoyizzldsj2a6i"
},
"mimeType": "image/webp",
"size": 66178
},
"path": "/castanderness/5-telegram-bot-patterns-every-python-developer-should-know-3iip",
"publishedAt": "2026-07-01T11:43:12.000Z",
"site": "https://dev.to",
"tags": [
"python",
"telegram",
"patterns",
"tutorial",
"@dp.message",
"@wraps"
],
"textContent": "# 5 Telegram Bot Patterns Every Python Developer Should Know\n\nAfter building 50+ bots, these patterns solve 90% of problems.\n\n## 1. FSM for Multi-Step Flows\n\n\n from aiogram.fsm.state import State, StatesGroup\n\n class OrderFlow(StatesGroup):\n product = State()\n quantity = State()\n address = State()\n\n @dp.message(Command('order'))\n async def start_order(message: Message, state: FSMContext):\n await state.set_state(OrderFlow.product)\n await message.answer('What product?')\n\n @dp.message(OrderFlow.product)\n async def get_product(message: Message, state: FSMContext):\n await state.update_data(product=message.text)\n await state.set_state(OrderFlow.quantity)\n await message.answer('How many?')\n\n\n## 2. Throttle Decorator\n\n\n from functools import wraps\n import time\n\n _last_call = {}\n\n def throttle(rate_limit: int = 3):\n def decorator(func):\n @wraps(func)\n async def wrapper(message: Message, *args, **kwargs):\n uid = message.from_user.id\n now = time.time()\n if now - _last_call.get(uid, 0) < rate_limit:\n await message.answer('Please wait...')\n return\n _last_call[uid] = now\n return await func(message, *args, **kwargs)\n return wrapper\n return decorator\n\n\n## 3. Paginated Results\n\n\n def paginate(items: list, page: int, per_page: int = 5):\n start = page * per_page\n return items[start:start + per_page], len(items) // per_page\n\n def build_page_kb(page: int, total: int) -> InlineKeyboardMarkup:\n btns = []\n if page > 0:\n btns.append(InlineKeyboardButton('Prev', callback_data=f'page:{page-1}'))\n if page < total:\n btns.append(InlineKeyboardButton('Next', callback_data=f'page:{page+1}'))\n return InlineKeyboardMarkup(inline_keyboard=[btns])\n\n\n## 4. Admin Middleware\n\n\n from aiogram import BaseMiddleware\n\n class AdminMiddleware(BaseMiddleware):\n def __init__(self, admin_ids: list[int]):\n self.admin_ids = admin_ids\n\n async def __call__(self, handler, event, data):\n user = data['event_from_user']\n if user.id not in self.admin_ids:\n await event.answer('Admin only')\n return\n return await handler(event, data)\n\n dp.message.middleware(AdminMiddleware([ADMIN_ID]))\n\n\n## 5. Retry on Network Errors\n\n\n async def safe_send(bot: Bot, chat_id: int, text: str, retries: int = 3):\n for attempt in range(retries):\n try:\n return await bot.send_message(chat_id, text)\n except TelegramRetryAfter as e:\n await asyncio.sleep(e.retry_after)\n except TelegramForbiddenError:\n db.mark_inactive(chat_id)\n return None\n except Exception:\n if attempt == retries - 1:\n raise\n await asyncio.sleep(2 ** attempt)\n\n\nNeed a production-ready bot with these patterns? Find me on Upwork.\n\nFrom $49 | 2-3 days | Full source code included",
"title": "5 Telegram Bot Patterns Every Python Developer Should Know"
}