Bot API version 4.9 (Telegram bot API docs)
If you have questions about how you can use the package (or if you think you'd be able to help others) please join the Telegram group (@DjangoTGBotChat).
If you would like to contribute, read this page for a list of suggestions of what you could work on.
Please note that all types and methods implemented here are defined exactly as they have been in Telegram Bot API. This means, although some type annotations and method comments have been provided in this package, you can find additional explanations for all types and methods on Telegram Bot API docs and use them in this package exactly the same way.
-
Install package from pip:
pip install django-tgbot
-
Add
django_tgbot
to your Django project'sINSTALLED_APPS
That's it :) You installed django-tgbot.
-
Create a bot in Telegram using BotFather and receive your API token
-
Open the Django project with
django-tgbot
installed in it -
Enter this command in the command line (terminal / cmd):
python manage.py createtgbot
-
Enter your API token:
> python manage.py createtgbot Enter the bot token (retrieved from BotFather): <YOUR_TOKEN> Setting up @BotDevTestBot ...
-
Enter the URL your Django project is deployed on. If your project is not deployed yet and is not accessible, press Enter to skip. (If you have not deployed yet and want to test your bot, you can use services like Ngrok to do so)
Enter the url of this project to set the webhook (Press Enter to skip): https://URL.com Bot webhook will be set to https://URL.com/botdevtestbot/update/. Do you confirm? (Y/N): y Webhook was successfully set.
-
A new app will be created in your Django project. Add this app to your
INSTALLED_APPS
-
Include this new app's urls in your project urls as described in the output of the above command
-
Update the database:
python manage.py migrate
Your bot is created! If you have set the webhook correctly you can now send messages to your bot and it responds all messages with Hello!
.
Overview of the process:
> python manage.py createtgbot
Enter the bot token (retrieved from BotFather): 521093911:AAEe6X-KTJHO98tK2skJLsYJsE7NRpjL8Ic
Setting up @BotDevTestBot ...
Enter the url of this project to set the webhook (Press Enter to skip): https://URL.com
Bot webhook will be set to https://URL.com/botdevtestbot/update/. Do you confirm? (Y/N): y
Webhook was successfully set.
Successfully created bot Test Bot(@botdevtestbot).
Next steps:
1. Add 'botdevtestbot' to INSTALLED_APPS in project settings
2. Add `from botdevtestbot import urls as botdevtestbot_urls` to project urls file
3. Add `path('botdevtestbot/', include(botdevtestbot_urls))` to project urls' urlpatterns
4. `python manage.py migrate`
Enjoy!
It is important to understand these definitions in order to read the rest of the doc or to use the package. We encourage you to also read the Definitions section in the full documentations. You can find a link to the full documentations at the end of this document.
This is an overview of the flow:
Bot receives a message/update --> Telegram sends an Update to your webhook --> Django receives this request and passes it to the app created for this bot (In steps above) --> django_tgbot
creates an Update
object from the HTTP request --> One or several processor
s will be assigned to handle this Update
--> All of these processor
s will run and possibly make some calls to Telegram API.
Telegram uses some methods and Type
s (think of this types as classes) to handle everything. All of these types are implemented as Python classes and you can use them from django_tgbot.types
. You can view a full list of all Telegram available types here (The API version based on which this package is designed is written at the top of this document. With newer versions there might be new types not implemented in this package)
Each new bot you create comes prepackaged with 3 models:
- TelegramUser: represents a user in Telegram. Can be a person or a bot. Basically, it is an entity that can send messages.
- TelegramChat: represents a chat in Telegram. Can be a private chat, a group, a supergroup or a channel. Basically, it is a place that messages can be sent from one or several parties.
- TelegramState: From the bot's perspective, each user in a chat or a chat by itself or a user by itself, are in a state. This state is stored in
TelegramState
model. It holds the user (can be blank), the chat (can be blank), a memory and a name. This name helps the bot to easily determine what this state is and what needs to be done.
When you create a new bot, an app will be created which has a new class named TelegramBot
and a bot instantiated from this class. This is your interface for working with the Telegram Bot API.
For every request it receives, it will do some preprocessing and then finds the processor
s responsible for this request and runs all of them. Finally, it will do some post-processings.
The mentioned preprocessing and post-processings can be changed or removed from the Bot class in bot.py
in your newly created app. By default, for all requests, the user's id
, first_name
, last_name
and username
and the chat's id
, title
and type
will be stored in database in the preprocessing and nothing is done in the postprocessing.
This is the core of your bot's functionality and for this you write most of your codes.
So far, we have seen every client of our bot (a user with/without a chat or a chat itself) has a state (i.e. is in a state). Processors take a client with its state and based on their state and the sent update, they will forward this client to another state.
Each processor should declare the states from which clients can enter and the state to which clients should be sent in case processor ran successfully or in case it failed.
Processors are just Python functions that take the bot instance, the update received from Telegram and the state of the client as input.
When you create a new bot, a new app will be created in your Django project which will contain a file named processors.py
. This module is where all your processors lie. You can also remove this file and instead, create a package with the same name in the same directory since the number of processors might get large and it's a good idea to keep them separated in different modules. If you do so, do not forget to import all of these modules in the __init__.py
of processors
package.
If you replace processors.py
with a processors
package:
processors
├── __init__.py
├── greetings.py
├── signup.py
└── ...
Where __init__.py
contains:
from . import greetings, signup, ...
Initially, there is a hello_world
processor available in processors.py
. As you can see, all of your processors should get registered by @processor
decorator in order to be recognized later by the bot. They should also take three named parameters (like the hello_world
sample):
- bot: An instance of the TelegramBot. Can be used to call Telegram API (sending messages, etc.)
- update: The received update loaded into the
Update
type explained above. - state: The state of this client, a TelegramState instance. You can change their state or memory using this.
As said earlier, each processor should declare what states it accepts to process and if processing is done successfully, what should the client's state become and what should it become if the processing fails.
These are declared above the function definition in the @processor
arguments:
- from_states: Name of the accepting states for this processor. It can be a string, a list or
state_types.All
which will accept all states. If you want to accept the empty (reset) state (the client's state is initially empty and it's a good idea to use empty string as a reset state), leave it blank or set it asfrom_states = ''
orfrom_states = state_types.Reset
. - success: The new state of the client, if processor runs successfully. "successfully" means being run without raising
ProcessFailure
exception. - fail: The new state of the client, if processor fails to run. If you want to fail the processor you should raise
ProcessFailure
. This exception can be imported fromdjango_tgbot.exceptions
.
You may use state_types.Keep
as the value for success
or fail
to not change the state or use state_types.Reset
to reset the state.
Additionally, you can define the update types and the message types you want this processor to handle. For example, you may want to have a processor that only handles requests regarding a message getting edited (which is a different update type than receiving a new message) or you may want to have a processor only handling requests of video messages (which is a different message type than text messages). To see a full list of different updates types and message types read Telegram Bot API docs. Parameters for @processor
:
- message_types: Can be a single value or a list of values. Leave unfilled to accept any message type. Use values from
message_types
module to fill in the parameter. For example you can saymessage_types = message_types.Text
to only handle text messages ormessage_types = [message_types.NewChatMembers, message_types.LeftChatMembers]
to handle updates about group members coming and going. - exclude_message_types: Works exactly like
message_types
except that values passed here will be excluded from the valid message types to handle. - update_types: Can be a single value or a list of values. Leave unfilled to accept any update type. Like the message_updates, available update_types are accessible from the
update_types
module. For example,update_types = [update_types.ChannelPost, update_types.EditedMessage]
makes the processor handle only updates about a new post being sent to a channel or a message being edited. - exclude_update_types: Works exactly like
update_types
except that values passed here will be excluded from the acceptable update types to handle.
Please note that the first parameter for @processor
should be always an state manager. An state manager is created automatically when you create a new bot and it's imported in the processors module. You can use that and give it to all of the processors. You may change this state manager to have different behaviors in your bot, which is not a common case and will be explained in advanced documentations.
Example of a processor definition:
@processor(state_manager, from_states='asked_for_name', success='got_their_name', fail=state_types.Keep, message_types=message_types.Text, update_types=update_types.Message)
def say_hello(bot, update, state):
bot.sendMessage(update.get_chat().get_id(), "Hello {}!".format(update.get_message().get_text()))
You may also leave the success
and fail
arguments in order to not change the state automatically, if you want to change it yourself in the processor:
@processor(state_manager, from_states='asked_for_name', message_types=message_types.Text, update_types=update_types.Message)
def say_hello(bot, update, state):
text = update.get_message().get_text()
if text == 'Alireza':
bot.sendMessage(update.get_chat().get_id(), "Hello Alireza!")
state.name = 'got_their_name'
state.save()
else:
bot.sendMessage(update.get_chat().get_id(), "Nah")
state.name = 'failed_to_give_name'
state.save()
Please note that leaving the success
and fail
parameters without a value is NOT the same as setting them to state_types.Keep
. Leaving them will not change them and allows you to set them in the processor's run time. However, setting them to state_types.Keep
will force the state to be the same as what is was before entering the processor.
The interface you can use for sending requests to the Bot API is the TelegramBot class and an instance of it will be created when you start a new bot.
All of the methods on Telegram API are implemented in this class. Furthermore, if you want to send any custom request or call any method, you can use the method send_request
to do so.
You should have a look at the API documentations while calling methods as they might have certain requirements on some arguments. For example, parse_mode
argument on some methods,
only accepts a few fixed strings and inline keyboards have three optional fields that exactly one of them should be filled with a value.
You might need to use the defined Type
s to create and pass data more easily, in cases that Telegram expects a certain type as the value for some parameter. For example,
if you want to send a keyboard as the reply_markup
for some message, you can create the keyboard object with the ReplyKeyboardMarkup
object and pass
it as the value. Please note that Type
classes' constructor is designed to accept a JSON object. If you want to create an instance of such classes,
you should use another method called a
.
All of the Type
s have a method called a
that allow you to create an object of that type. They get the parameters and validate them and return an object of that type.
For example, if you want to create a keyboard with two buttons one saying A
and other saying B
this is how you create it:
keyboard = ReplyKeyboardMarkup.a(keyboard=[
[KeyboardButton.a(text='A'), KeyboardButton.a(text='B')]
])
All Type
classes also have a to_dict
and to_json
method that may help you in some scenarios. For more information see the package docs.
- As explained earlier, some API methods have certain requirements for some of their parameters. One of them is the
reply_markup
parameter for all of the methods that have it. This parameter should be passed as a JSON object. However, since it is a very common parameter to use in a lot of methods, if you pass this as aType
(e.g.ReplyKeyboardMarkup
orInlineKeyboardMarkup
) it will be converted to JSON automatically. - To send a file when using methods that accept it (such as
sendPhoto
orsendDocument
), if you are going to upload the file (and not providing the file url or file id), set theupload
argument toTrue
and pass the opened file to the according argument. For example:bot.sendPhoto(chat_id, photo=open('my_file.png', 'rb'), upload=True)
- Some demo bots created with
django-tgbot
: https://github.com/Ali-Toosi/django-tgbot_demo - Full documentation: https://django-tgbot.readthedocs.io/en/latest/