Telegram
aiogram 3 bilan buyurtma qabul qiluvchi Telegram bot
Kichik biznes uchun Telegram bot ko'pincha saytdan foydaliroq: mijoz allaqachon shu ilovada, ro'yxatdan o'tish shart emas, xabar darhol keladi.
aiogram 3 va 2 farqi
Internetdagi ko'p namuna hali ham 2-versiyada yozilgan va ular 3-versiyada ishlamaydi. Asosiy farqlar:
| aiogram 2 | aiogram 3 | |
|---|---|---|
| Handler | @dp.message_handler | @router.message |
| Filtrlar | Argument sifatida | Alohida obyekt |
| Tuzilma | Dispatcher markaziy | Router'lar |
| Ishga tushirish | executor | asyncio.run |
Router'lar tizimi katta botni bo'laklarga ajratish imkonini beradi — buyurtma alohida faylda, admin alohida faylda.
Skelet
import asyncio, logging
from aiogram import Bot, Dispatcher, Router, F
from aiogram.filters import CommandStart
from aiogram.fsm.storage.memory import MemoryStorage
router = Router()
async def main():
bot = Bot(token=TOKEN)
dp = Dispatcher(storage=MemoryStorage())
dp.include_router(router)
await dp.start_polling(bot)
if __name__ == "__main__":
logging.basicConfig(level=logging.INFO)
asyncio.run(main())
FSM — bosqichma-bosqich suhbat
Buyurtma bir xabarda kelmaydi. Avval mahsulot, keyin miqdor, keyin manzil, keyin telefon. Bot har foydalanuvchi qaysi bosqichda ekanini eslab turishi kerak.
Buning uchun holat mashinasi ishlatiladi:
from aiogram.fsm.state import State, StatesGroup
class Order(StatesGroup):
product = State()
qty = State()
address = State()
phone = State()
confirm = State()
Har bosqichda javob olinadi, saqlanadi va keyingi holatga o'tiladi:
@router.message(CommandStart())
async def start(msg, state):
await state.clear()
await state.set_state(Order.product)
await msg.answer("Nima buyurtma qilamiz?", reply_markup=menu_kb())
@router.message(Order.qty, F.text.regexp(r"^\d+$"))
async def get_qty(msg, state):
await state.update_data(qty=int(msg.text))
await state.set_state(Order.address)
await msg.answer("Manzilni yozing yoki joylashuvni yuboring.")
Muhim detal. F.text.regexp filtri faqat raqam kiritilgandagina ishlaydi. Agar foydalanuvchi matn yozsa, bu handler chaqirilmaydi. Shuning uchun har bosqich uchun "noto'g'ri kiritish" handleri ham kerak, aks holda bot jim qoladi va foydalanuvchi nima bo'lganini tushunmaydi.
@router.message(Order.qty)
async def qty_invalid(msg):
await msg.answer("Faqat raqam kiriting. Masalan: 2")
Tartib muhim — aniqroq filtr yuqorida, umumiysi pastda turishi kerak.
Tugmalar
Matn kiritishdan ko'ra tugma bosish qulayroq va xato kamroq bo'ladi:
from aiogram.types import InlineKeyboardMarkup, InlineKeyboardButton
def menu_kb():
rows = [
[InlineKeyboardButton(text=p["name"],
callback_data=f"p:{p['id']}")]
for p in PRODUCTS
]
return InlineKeyboardMarkup(inline_keyboard=rows)
@router.callback_query(F.data.startswith("p:"))
async def pick(cb, state):
pid = cb.data.split(":")[1]
await state.update_data(product=pid)
await state.set_state(Order.qty)
await cb.message.answer("Nechta kerak?")
await cb.answer()
Oxirgi qator — cb.answer() — unutilmasin. Usiz Telegram tugmada aylanuvchi belgi ko'rsatib turadi va foydalanuvchi bot osilib qolgan deb o'ylaydi.
Xotira muammosi
MemoryStorage holatni operativ xotirada saqlaydi. Bot qayta ishga tushsa, barcha yarim tugallangan buyurtmalar yo'qoladi.
Ishlab chiqarish uchun men SQLite yoki Redis ishlataman. Kichik botlar uchun aiosqlite yetarli — alohida server kerak emas, fayl sifatida saqlanadi.
Buyurtmani yakunlash
Barcha ma'lumot yig'ilgach, tasdiqlash ko'rsatiladi va adminlarga xabar yuboriladi:
@router.callback_query(F.data == "confirm")
async def confirm(cb, state, bot):
data = await state.get_data()
oid = await save_order(data, cb.from_user.id)
text = (f"🆕 Buyurtma #{oid}\n"
f"Mahsulot: {data['product']} × {data['qty']}\n"
f"Manzil: {data['address']}\n"
f"Telefon: {data['phone']}")
for admin in ADMINS:
try:
await bot.send_message(admin, text)
except Exception as e:
logging.warning("admin %s: %s", admin, e)
await state.clear()
await cb.message.answer(f"Qabul qilindi. Raqam: #{oid}")
try/except shart. Agar admin botni bloklagan bo'lsa, xato chiqadi va u tsiklni to'xtatib, qolgan adminlarga xabar bormay qoladi.
Joylashtirish
Bot uzluksiz ishlashi kerak, ya'ni server talab qilinadi. Bepul variantlar orasida Render va Railway qulay.
Ammo bepul tarifda muhim cheklov bor: bir muddat so'rov bo'lmasa, xizmat uxlab qoladi. Birinchi xabar kelganda esa u uyg'onishga 30–50 soniya sarflaydi va foydalanuvchi javob kutib qoladi.
Yechim — tashqi cron xizmati orqali har 10 daqiqada bir marta so'rov yuborish. Buning uchun botga oddiy HTTP endpoint qo'shiladi:
from aiohttp import web
async def health(request):
return web.Response(text="ok")
app = web.Application()
app.router.add_get("/health", health)
Keyin cron-job.org kabi bepul xizmatda shu manzilga muntazam so'rov sozlanadi.
Xulosa
aiogram 3 da bot yozish murakkab emas, lekin uchta joyda ehtiyot bo'lish kerak: handler tartibi, holat saqlash usuli va bepul hostingdagi uyqu rejimi.
Bu uchtasi to'g'ri qo'yilsa, bot barqaror ishlaydi va mijoz uni sayt o'rniga ishlatishga rozi bo'ladi.