-
Notifications
You must be signed in to change notification settings - Fork 5
Storing bot, user and chat related data
Sometimes you need to temporarily store some information about the current user and/or chat for later use. An example of this would be a survey bot that asks the user a series of questions one after another and saves them to your database when all answers are collected.
The telegram.ext
framework provides a built-in solution for this common task. Let's jump straight to an example:
from uuid import uuid4
from telegram.ext import Updater, CommandHandler
def put(update, context):
"""Usage: /put value"""
# Generate ID and separate value from command
key = str(uuid4())
# We don't use context.args here, because the value may contain whitespaces
value = update.message.text.partition(' ')[2]
# Store value
context.user_data[key] = value
# Send the key to the user
update.message.reply_text(key)
def get(update, context):
"""Usage: /get uuid"""
# Seperate ID from command
key = context.args[0]
# Load value and send it to the user
value = context.user_data.get(key, 'Not found')
update.message.reply_text(value)
if __name__ == '__main__':
updater = Updater('TOKEN', use_context=True)
dp = updater.dispatcher
dp.add_handler(CommandHandler('put', put))
dp.add_handler(CommandHandler('get', get))
updater.start_polling()
updater.idle()
By using context.user_data
in any Handler
callback, you have access to a user-specific dict
.
Every time the bot receives a message, the handler for that message finds (or creates) the user_data
of the user who sent the message. This dictionary is shared across all handlers of the bot.
chat_data
works in the exact same way as user_data
, except it is managed per chat instead of every user. Use context.chat_data
to get access to this dict. As of version 12.4 bot_data
is provided as well and works in the exact same way as user_data
, except it's a single dictionary for your bot. Use context.bot_data
to get access to this dict.
-
Everything is stored in memory. This means that all
bot_data
,user_data
andchat_data
is deleted when the bot process ends. If you don't want this, have a look at the persistence page. - If not empty,
bot_data
,user_data
andchat_data
will be kept until the process ends. -
user_data
andchat_data
are different dictionaries even for private chats. - You can not assign a new value to
bot_data
,user_data
orchat_data
. Instead ofuser_data = {}
anduser_data = other_dict
, useuser_data.clear()
and/oruser_data.update(other_dict)
respectively.
If a group chat migrates to supergroup, its chat id will change. Since the chat_data
dicts are stored per chat id you'll need to transfer the data to the new id. Here are the two situations you may encounter:
When a group migrates, Telegram will send an update that just states the new info. In order to catch those, simply define a corresponding handler:
def chat_migration(update, context):
m = update.message
dp = context.dispatcher # available since version 12.4
# Get old and new chat ids
old_id = m.migrate_from_chat_id or m.chat_id
new_id = m.migrate_to_chat_id or m.chat_id
# transfer data, if old data is still present
if old_id in dp.chat_data:
dp.chat_data[new_id].update(dp.chat_data.get(old_id))
del dp.chat_data[old_id]
...
def main():
updater = Updater("TOKEN", use_context=True)
dp = updater.dispatcher # available since version 12.4
dp.add_handler(MessageHandler(Filters.status_update.migrate, chat_migration))
...
To be entirely sure that the update will be processed by this handler, either add it first or put it in its own group.
If you try e.g. sending a message to the old chat id, Telegram will respond by a Bad Request including the new chat id. You can access it using an error handler:
def error(update, context):
"""Log Errors caused by Updates."""
logger.warning('Update "%s" caused error "%s"', update, context.error)
if isinstance(context.error, ChatMigrated):
new_chat_id = context.error.new_chat_id
Unfortunately, Telegram does not pass along the old chat id, so there is currently no simple way to perform a data transfer like above within the error handler. So make sure, that you catch the status updates! Still, you can wrap your requests into a try-except
-clause:
def my_callback(update, context):
dp = context.dispatcher # available since version 12.4
...
try:
context.bot.send_message(chat_id, text)
except ChatMigrated as e:
new_id = e.new_chat_id
# Resend to new chat id
context.bot.send_message(new_id, text)
# Transfer data
if chat_id in dp.chat_data:
dp.chat_data[new_id].update(dp.chat_data.get(chat_id))
del dp.chat_data[chat_id]
...
Wiki of python-telegram-bot
© Copyright 2015-2022 – Licensed by Creative Commons
- Types of Handlers
- Advanced Filters
- Storing data
- Making your bot persistent
- Adding Defaults
- Exception Handling
- Job Queue
- Arbitrary
callback_data
- Avoiding flood limits
- Frequently requested design patterns
- Code snippets
- Performance Optimizations
- Webhooks
- Telegram Passport
- Bots built with PTB
- Automated Bot Tests