Муколамаҳо ва ҳолатҳо
Чаро қадами муколамаро дар хотир дорем
Як сатр метавонад маъноҳои гуногун дошта бошад. Пас аз савол дар бораи шаҳр он шаҳр аст, пас аз савол дар бораи сана — сана. Агар бот танҳо паёми охиринро бинад, заминаро намедонад. Мошини ҳолатҳо (FSM) қадами ҷориро нигоҳ дошта, барои фаҳмидани ҷавоби оянда ёрӣ медиҳад.
Ин барои сабти мулоқот, фармоиш ва сохтани ёдрасӣ муфид аст. Ду чизро алоҳида нигоҳ доред: ҳолат ба саволи «ҳоло кадом қадам?» ҷавоб медиҳад ва маълумот ҷавобҳои аллакай гирифташударо дар бар мегирад. Ҳеҷ кадом набояд барои ҳамаи одамон умумӣ бошад.
1. Номҳои ҳолатҳо
StatesGroup қадамҳои як равандро муттаҳид мекунад ва State қадами алоҳидаро ифода мекунад. Ҳолат функсия ё давраи интизори паём нест. Ин нишона дар анбор аст, ки бо он коркардкунандаи рӯйдоди оянда интихоб мешавад.
from aiogram.fsm.state import State, StatesGroup
class Booking(StatesGroup):
city = State()
date = State()
print(Booking.city.state)
print(Booking.date.state)
Натиҷа:
Booking:city
Booking:date
Филтри коркардкунандаи @router.message(Booking.city, F.text) маънои «паёми матнӣ дар қадами интихоби шаҳр»-ро дорад. Коркардкунанда танҳо ҳангоми рӯйдоди нав иҷро мешавад; байни паёмҳо функсияи Python-ро кушода нигоҳ доштан лозим нест.
2. Контекст ва анбор
FSMContext воситаи дастрасӣ ба ҳолат ва маълумоти як иштирокчии муколама аст. Дар aiogram 3 параметри state: FSMContext онро аз контексти Dispatcher мегирад. Стратегияи пешфарз сабтҳоро аз рӯи корбар дар дохили чат ҷудо мекунад. MemoryStorage сабтҳоро дар хотираи раванд нигоҳ медорад.
Дар мисоли навбатӣ барои санҷиши бе Telegram контекстро дастӣ месозем. StorageKey калиди сабтро муайян мекунад: бот, чат ва корбар. DYU рамзи шартии шаҳри интихобшуда аст.
import asyncio
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup
from aiogram.fsm.storage.base import StorageKey
from aiogram.fsm.storage.memory import MemoryStorage
class Booking(StatesGroup):
city = State()
date = State()
async def main():
storage = MemoryStorage()
state = FSMContext(storage, StorageKey(bot_id=1, chat_id=42, user_id=9))
await state.set_state(Booking.city)
await state.update_data(city="DYU")
await state.set_state(Booking.date)
print(await state.get_state())
print(await state.get_data())
await state.set_state(None)
print(await state.get_state(), await state.get_data())
await state.clear()
print(await state.get_state(), await state.get_data())
await storage.close()
asyncio.run(main())
Натиҷа:
Booking:date
{'city': 'DYU'}
None {'city': 'DYU'}
None {}
Пас аз set_state(Booking.date) шаҳр ҳанӯз дар маълумот ҳаст. Ивази қадам ҷавобҳоро тоза намекунад. set_state(None) танҳо ҳолатро гирифт: маълумот монд. clear() ҳам ҳолат ва ҳам маълумотро тоза кард — бинобар ин сатри охир None {} дорад.
3. Мустақилияти корбарон
Ду контекстро тасаввур кунед, ки бот ва чаташон яксон, вале ID-и корбаронашон гуногун аст. Онҳо як анбор ва калидҳои гуногунро истифода мекунанд. get_data() луғати маълумотро бармегардонад. Дар MemoryStorage ин нусхаи сатҳи болост, аз ин рӯ таъини мустақим дар луғати гирифташуда тағйирро нигоҳ намедорад.
import asyncio
from aiogram.fsm.context import FSMContext
from aiogram.fsm.storage.base import StorageKey
from aiogram.fsm.storage.memory import MemoryStorage
async def main():
storage = MemoryStorage()
a = FSMContext(storage, StorageKey(bot_id=1, chat_id=42, user_id=9))
b = FSMContext(storage, StorageKey(bot_id=1, chat_id=42, user_id=10))
await a.update_data(value=7)
print(await a.get_data(), await b.get_data())
data = await a.get_data()
data["value"] = 99
print((await a.get_data())["value"])
await a.update_data(value=8)
print((await a.get_data())["value"])
await storage.close()
asyncio.run(main())
Натиҷа:
{'value': 7} {}
7
8
Қимати 7 танҳо ба корбари аввал тааллуқ дорад. Пас аз таъини маҳаллии 99 дар анбор 7 монд. Танҳо update_data(value=8) натиҷаи навро сабт кард. Ба тағйири рӯйхатҳои дарунӣ дар ҷой такя накунед: нусхаи луғат ҳатман амиқ нест ва анборҳои гуногун метавонанд рафтори дигар дошта бошанд. Қиматҳои навшударо ба update_data ошкоро диҳед.
4. Чанд савол дар як ҳолат
Барои ҳар савол ҳамеша State-и алоҳида лозим нест. Агар амалҳо яксон бошанд, як қадамро монда, рақами савол ва ҷавобҳои ҷамъшударо дар маълумот нигоҳ доштан мумкин аст. Индекси step саволи ҷориро интихоб мекунад ва рӯйхати answers ҷавобҳоро нигоҳ медорад. Аввал навсозии луғати одиро мефаҳмем:
data = {"step": 0, "answers": []}
answers = data["answers"] + ["A"]
print(data["answers"], answers)
data.update(step=1, answers=answers)
print(data)
Натиҷа:
[] ['A']
{'step': 1, 'answers': ['A']}
Ҷавоби нодуруст ва баромадан
Агар сана нодуруст бошад, хоҳиш кунед онро такрор кунанд ва корбарро дар қадами ҷорӣ монед. Танҳо ҷавоби санҷидашударо нигоҳ доред. Ҳамин тавр шаҳри қаблӣ гум намешавад ва корбар барои як ғалат аз аввал оғоз намекунад.
Фармони баромад, масалан /cancel, бояд аз коркардкунандагони қадамҳо бартарӣ дошта бошад. Дар aiogram 3 коркардкунандаи бе филтри ҳолат дар миёнаи муколама ҳам кор карда метавонад. Агар коркардкунандаи васеи қадами ҷорӣ пештар бошад, фармони баромадро ҳамчун ҷавоб қабул мекунад. Ин натиҷаи тартиби аллакай шиноси сабт аст.
Набудани ҳолат бо None ифода мешавад. Агар коркардкунанда танҳо берун аз муколама кор кунад, шартро ошкоро диҳед, масалан StateFilter(None) аз aiogram.filters. Ин аз тамоман набудани филтр фарқ дорад.
Дар дохил чӣ мегузарад
Dispatcher калиди корбару чатро муайян карда, нишонаи ҷориро мехонад ва коркардкунандаро интихоб мекунад. FSMContext сабтро барои паёми оянда нав мекунад.
MemoryStorage ҳангоми оғози дубораи раванд ҳамаро фаромӯш мекунад. Барои нигоҳдорӣ байни оғози дубораи бот RedisStorage пайвастан мумкин аст; пойдорӣ ба танзимоти худи Redis низ вобаста аст.
Хатоҳои маъмул ва ислоҳ
- Интизори гузариши худкор. Пас аз саволи сана бе
await state.set_state(Booking.date)ҷавоби нав боз ба қадами кӯҳна мерасад. Нишонаро ошкоро иваз кунед. - Барвақт гум кардани маълумот.
await state.clear()пеш азget_data()луғати холӣ медиҳад. Маълумоти лозимро пеш аз тозакунӣ хонед. - Дар охир танҳо иваз кардани ҳолат.
await state.set_state(None)маълумотро мемонад, тавре мисол нишон дод. Барои анҷоми пурраclear()истифода кунед. - Танҳо маҳаллӣ нигоҳ доштан.
data["city"] = "DYU"сабт тавассути FSMContext нест.await state.update_data(city="DYU")истифода кунед. - Гузоштани баромад пас аз қадамҳо. Қадам метавонад
/cancel-ро ҳамчун матни одӣ сабт кунад. Фармони баромадро пештар сабт карда, барои набудани муколама ҳам ҷавоб пешбинӣ кунед.
Ёддошт
| Амал | Натиҷа |
|---|---|
StatesGroup, State |
Гурӯҳи қадамҳо ва нишонаи қадам |
set_state(...) / get_state() |
Сабт / хондани қадами ҷорӣ |
update_data(...) / get_data() |
Навсозӣ / хондани ҷавобҳо |
clear() |
Тозакунии ҳолат ва маълумот |
StateFilter(None) |
Танҳо берун аз муколама |
| Бе филтри ҳолат | Ҳар ҳолат, агар коркардкунандаи пештар рӯйдодро нагирад |
| Ҷавоби нодуруст | Роҳнамоӣ бе гузаштан ба қадами дигар |
| MemoryStorage | Хотираи раванд, бе нигоҳдорӣ пас аз оғози дубора |