mirror of
https://github.com/python-telegram-bot/python-telegram-bot.git
synced 2024-10-23 17:36:26 +02:00
Created Storing user- and chat-related data (markdown)
parent
667f80de1e
commit
73954b0cfb
1 changed files with 126 additions and 0 deletions
126
Storing-user--and-chat-related-data.md
Normal file
126
Storing-user--and-chat-related-data.md
Normal file
|
@ -0,0 +1,126 @@
|
||||||
|
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.
|
||||||
|
|
||||||
|
# `user_data` and `chat_data`
|
||||||
|
The `telegram.ext` framework provides a built-in solution for this common task. To understand how it works, let's take a look at a naïve solution using a global variable. In case you're in a hurry, you can also [**jump straight to the explanation**](#explanation).
|
||||||
|
|
||||||
|
## Bad Example
|
||||||
|
The following complete example bot provides a very simple key/value storage. When you use the `/put` command to store a value, it returns an ID which you can use with the `/get` command to retrieve the stored value.
|
||||||
|
|
||||||
|
It uses a global dictionary named `all_user_data` that maps a user ID to a `dict` that represents the user specific storage.
|
||||||
|
|
||||||
|
```python
|
||||||
|
from uuid import uuid4
|
||||||
|
from telegram.ext import Updater, CommandHandler
|
||||||
|
|
||||||
|
all_user_data = dict()
|
||||||
|
|
||||||
|
def put(bot, update):
|
||||||
|
"""Usage: /put value"""
|
||||||
|
# Generate ID and seperate value from command
|
||||||
|
key = str(uuid4())
|
||||||
|
value = update.message.text.partition(' ')[2]
|
||||||
|
|
||||||
|
user_id = update.message.from_user.id
|
||||||
|
|
||||||
|
# Create user dict if it doesn't exist
|
||||||
|
if user_id not in all_user_data:
|
||||||
|
all_user_data[user_id] = dict()
|
||||||
|
|
||||||
|
# Store value
|
||||||
|
user_data = all_user_data[user_id]
|
||||||
|
user_data[key] = value
|
||||||
|
|
||||||
|
update.message.reply_text(key)
|
||||||
|
|
||||||
|
def get(bot, update):
|
||||||
|
"""Usage: /get uuid"""
|
||||||
|
# Seperate ID from command
|
||||||
|
key = update.message.text.partition(' ')[2]
|
||||||
|
|
||||||
|
user_id = update.message.from_user.id
|
||||||
|
|
||||||
|
# Load value
|
||||||
|
try:
|
||||||
|
user_data = all_user_data[user_id]
|
||||||
|
value = user_data[key]
|
||||||
|
update.message.reply_text(value)
|
||||||
|
|
||||||
|
except KeyError:
|
||||||
|
update.message.reply_text('Not found')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
updater = Updater('TOKEN')
|
||||||
|
dp = updater.dispatcher
|
||||||
|
|
||||||
|
dp.add_handler(CommandHandler('put', put))
|
||||||
|
dp.add_handler(CommandHandler('get', get))
|
||||||
|
|
||||||
|
updater.start_polling()
|
||||||
|
updater.idle()
|
||||||
|
```
|
||||||
|
|
||||||
|
If you read the code carefully, you might have noticed that the code that gets the current `user_data` from `all_user_data` is [repeated](https://en.wikipedia.org/wiki/Don%27t_repeat_yourself) in both callbacks.
|
||||||
|
|
||||||
|
## Good Example
|
||||||
|
```python
|
||||||
|
from uuid import uuid4
|
||||||
|
from telegram.ext import Updater, CommandHandler
|
||||||
|
|
||||||
|
def put(bot, update, user_data):
|
||||||
|
"""Usage: /put value"""
|
||||||
|
# Generate ID and seperate value from command
|
||||||
|
key = str(uuid4())
|
||||||
|
value = update.message.text.partition(' ')[2]
|
||||||
|
|
||||||
|
# Store value
|
||||||
|
user_data[key] = value
|
||||||
|
|
||||||
|
update.message.reply_text(key)
|
||||||
|
|
||||||
|
def get(bot, update, user_data):
|
||||||
|
"""Usage: /get uuid"""
|
||||||
|
# Seperate ID from command
|
||||||
|
key = update.message.text.partition(' ')[2]
|
||||||
|
|
||||||
|
# Load value
|
||||||
|
try:
|
||||||
|
value = user_data[key]
|
||||||
|
update.message.reply_text(value)
|
||||||
|
|
||||||
|
except KeyError:
|
||||||
|
update.message.reply_text('Not found')
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
updater = Updater('TOKEN')
|
||||||
|
dp = updater.dispatcher
|
||||||
|
|
||||||
|
dp.add_handler(CommandHandler(
|
||||||
|
'put', put, pass_user_data=True))
|
||||||
|
dp.add_handler(CommandHandler(
|
||||||
|
'get', get, pass_user_data=True))
|
||||||
|
|
||||||
|
updater.start_polling()
|
||||||
|
updater.idle()
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note the following differences:**
|
||||||
|
- The global variable `all_user_data` was removed
|
||||||
|
- The repeated code to get the storage of the current user was removed
|
||||||
|
- The code to ensure that the storage exists was removed
|
||||||
|
- The parameter `user_data` was added to the `put` and `get` functions
|
||||||
|
- The parameter `pass_user_data=True` is now passed to both `CommandHandler`
|
||||||
|
|
||||||
|
### Explanation
|
||||||
|
By passing `pass_user_data=True` to any `Handler` constructor, you instruct the handler to pass a user-specific `dict` to the handler callback. The callback function *must* accept a parameter named `user_data`.
|
||||||
|
|
||||||
|
*Every time the bot receives a message*, the handler for that message checks if it was created with `pass_user_data=True`. If that is the case, it finds (or creates) the `user_data` of the user who sent the message and passes it to the callback function as a keyword argument. This dictionary is *shared across all handlers* of the bot.
|
||||||
|
|
||||||
|
#### What about `chat_data`?
|
||||||
|
`chat_data` works in the exact same way as `user_data`, except it is managed per *chat* instead of every *user*. Use the `pass_chat_data=True` parameter in the `Handler` constructor to have it passed to your callback.
|
||||||
|
|
||||||
|
#### Notes & Tips
|
||||||
|
- **Everything is stored in memory.** This means that all `user_data` and `chat_data` is deleted when the bot process ends.
|
||||||
|
- Empty `user_data` and `chat_data` dictionaries are automatically deleted from memory after the update is processed.
|
||||||
|
- If not empty, `user_data` and `chat_data` will be kept until the process ends.
|
||||||
|
- `user_data` and `chat_data` are different dictionaries even for private chats.
|
||||||
|
- You can not assign a new value to `user_data` or `chat_data`. Instead of `user_data = {}` and `user_data = other_dict`, use `user_data.clear()` and/or `user_data.update(other_dict)` respectively.
|
Loading…
Reference in a new issue