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