Package: telegram-django-bot
This library provides a Python high-level interface for creating Telegram Bots. It standardizes the coding in the best
practice of the web development. The library is based onDjangoandPython-Telegram-Bot.
It also provides viewset interface for managing data with.If you start a new project, you could useTelegram django bot templatewith preconfigured settings.InstallYou can install viapip:$pipinstalltelegram_django_botThen you can configure it in your app:Add “telegram_django_bot” to your INSTALLED_APPS setting like this:INSTALLED_APPS=[...'telegram_django_bot','django_json_widget',# needed for django admin site]If you are planning to use Django in asynchronous mode, then you need to setDJANGO_ALLOW_ASYNC_UNSAFE = True(otherwise DB writings will be failed).2. Runpython manage.py migrateto create the telegram_django_bot models (checked that theAUTH_USER_MODELselected
in settings).Set up constants in Django settings file:TELEGRAM_ROOT_UTRLCONF-  (same asROOT_URLCONFfor WEB) for using django notation in callback (routing) (strongly recommended)Not necessary, but useful settings:TELEGRAM_TOKEN- for adding “triggers”,TELEGRAM_TEST_USER_IDS- for adding tests for your bot,Make sure, thatLANGUAGE_CODE,LANGUAGE_CODE,USE_I18Nare also used in the library for language localization.This step connectsTelegram Django BotwithPython-Telegram-Bot. AddRouterCallbackMessageCommandHandlerin handlers for using TELEGRAM_ROOT_UTRLCONF :updater=Updater(bot=TG_DJ_Bot(settings.TELEGRAM_TOKEN))updater.dispatcher.add_handler(RouterCallbackMessageCommandHandler())or in 20.x version :bot=TG_DJ_Bot(settings.TELEGRAM_TOKEN)application=ApplicationBuilder().bot(bot).build()application.add_handler(RouterCallbackMessageCommandHandler())Quick startNormally, Python-Telegram-Bot gives the next opportunities for bot creation:Python Interface for communication with Telegram API;Web service to get updates from telegram;and Django:Django ORM  (communication with Database);Administration panel for management.Telegram Django Bot provides next special opportunities:using Viewsets (typical action with model (create, update, list, delete));using Django localization.using function routing like urls routing in Django.creating general menu items with no-coding (through Django Admin Panel);collecting stats from user actions in the bot;other useful staff.The key feature of the lib isTelegramViewSet- a class for managing Django ORM model. It is designed in a
similar way asDjango rest framework Viewset, but has
a significant difference: while DRF Viewset provides a response in serializable format (usually in json format) to frontend app, TelegramViewSet
provides a response to the user in telegram interface in message format with buttons. So, you will manage data and receive
responses in human format by executing TelegramViewSet method. The methods use some kind of templates for generating human
responses (it is possible to overwrite these templates). By default, TelegramViewSet has 5 methods:create- create a new instance of the specified ORM model;change- update instance fields of specified ORM model;show_elem- show fields of the element and buttons with actions of this instance;show_list- show list of model elements (with pagination);delete- delete the instanceSo, if, for example, you have a model of somerequestin your project:fromdjango.dbimportmodelsclassRequest(models.Model):text=models.TextField()importance_level=models.PositiveSmallIntegerField()# for example it will be integer fieldproject=models.ForeignKey('Project',on_delete=models.CASCADE)tags=models.ManyToManyField('Tags')The next piece of code gives the opportunity for full managing (create, update, show, delete) of this model from Telegram:fromtelegram_django_botimportformsastd_formsfromtelegram_django_bot.td_viewsetimportTelegramViewSetclassRequestForm(td_forms.TelegramModelForm):classMeta:model=Requestfields=['text','importance_level','project','tags']classRequestViewSet(TelegramViewSet):model_form=RequestFormqueryset=Request.objects.all()viewset_name='Request'If you need, you can add extra actions to RequestViewSet for managing (see details information below) or change existing functions.
There are several parameters and secondary functions in TelegramViewSet for customizing logic if it is necessary.In this example,TelegramModelFormwas used. TelegramModelForm is a descendant of Django ModelForm. So, you could use
labels, clean functions and other parameters and functions for managing logic and displaying.TelegramViewSet is designed to answer next user actions: clicking buttons and sometimes sending messages. The library imposesDjango URL notationfor mapping user actions to TelegramViewSet methods (or usual handlers).
Usually, for correct mapping you just need to setTELEGRAM_ROOT_UTRLCONFand useRouterCallbackMessageCommandHandlerin
dispatcher as it is mentioned above in theInstall paragraph.For correct mappingRequestViewSetyou should write in the TELEGRAM_ROOT_UTRLCONF file something like this:fromdjango.urlsimportre_pathfrom.viewsimportRequestViewSeturlpatterns=[re_path(r"^rv/",RequestViewSet,name='RequestViewSet'),]From this point, you can use buttons with callback data “rv/<function_code>” for function calling. For example:“rv/cr” - RequestViewSet.create method;“rv/sl” - RequestViewSet.show_list;See these examples for great understanding:Telegram django bot templateDrive BotDeep in detailsIn this chapter, we will analyze how everything works. The main task of the library is to unify the code and
provide frequently used functions for developing a bot, that is why a lot of logic is based on resources and paradigms
of Django <https://www.djangoproject.com/>`_ andPython-Telegram-Bot. Let’s analyze
key features of the library on the example ofTelegram django bot template.ImportantThe template is based on 13.x Python-Telegram-Bot version (synchronous version). So, the next examples is suitable for that version. For use with 20.x versions you need to do some modification.Since Telegram bots are designed as a tool for responding to user requests, writing a bot begins
from the user request handler. For this, the standard tools of the Python-Telegram-Bot library are used ﹣telegram.ext.Update:fromtelegram.extimportUpdaterdefmain():...updater=Updater(bot=TG_DJ_Bot(TELEGRAM_TOKEN))add_handlers(updater)updater.start_polling()updater.idle()if__name__=='__main__':main()As indicated in the example, to run the bot (Update) you need to specify a few things (thePython-Telegram-Botlibrary standard):1. an instance of thetelegram.Botmodel with the specified API token. In this case, a descendanttelegram_django_bot.tg_dj_bot.TG_DJ_Botof thetelegram.Botclass is used. It has additional functionality for convenience (we will return to it later);
2. Handlers that will be called in response to user requests.In the example, the list of handlers is specified in theadd_handlersfunction:fromtelegram_django_bot.routingimportRouterCallbackMessageCommandHandler...defadd_handlers(updater:Updater):dp=updater.dispatcherdp.add_handler(RouterCallbackMessageCommandHandler())The example adds 1 super handlerRouterCallbackMessageCommandHandler, which allows you to write handlers
in the style of handling link requests in the same way as it is done inDjango.RouterCallbackMessageCommandHandlerallows you to handle
messages, user commands and button clicks by users. In other words, it replaces the handlersMessageHandler, CommandHandler, CallbackQueryHandler. Since theTelegram Django Botlibrary is an extension,
it does not prohibit the use of standard handlers of thePython-Telegram-Botlibrary for handle user requests.
(sometimes it is simply necessary, for example, if you need to process responses to surveys (you need to use PollAnswerHandler)).Django notationof routing handlers is that paths to handlers are described in a separate file or files.
As in theDjangostandard, the main file (root) for routing is specified in the project settings, where paths to handlers or paths to groups of handlers are stored.
TheTELEGRAM_ROOT_UTRLCONF(same asROOT_URLCONFfor WEB) attribute is used to specify the path to the file. In the example template, we have the following settings:bot_conf.settings.py:TELEGRAM_ROOT_UTRLCONF='bot_conf.utrls'bot_conf.utrls.py:fromdjango.urlsimportre_path,includeurlpatterns=[re_path('',include(('base.utrls','base'),namespace='base')),]That is, only 1 group of handlers is connected in the file (which corresponds to thebaseapplication at the conceptual level). You can
add several groups as well, this can be convenient if you create several folders (applications) for storing code.
As you can seeDjangofunctions are imported without any redefinition.There is following code in the specified included filebase.utrls.py:fromdjango.urlsimportre_pathfromdjango.confimportsettingsfromtelegram_django_bot.user_viewsetimportUserViewSetfrom.viewsimportstart,BotMenuElemViewSet,some_debug_funcurlpatterns=[re_path('start',start,name='start'),re_path('main_menu',start,name='start'),re_path('sb/',BotMenuElemViewSet,name='BotMenuElemViewSet'),re_path('us/',UserViewSet,name='UserViewSet'),]ifsettings.DEBUG:urlpatterns+=[re_path('some_debug_func',some_debug_func,name='some_debug_func'),]So, the end handlers (which are defined in thebase.views.pyfile) are specified here. Thus, if
user in the bot writes the command/start, thenUpdaterreceives a message about the user’s action and selects
the appropriate for the request handlerRouterCallbackMessageCommandHandlerfrom a set of handlers. Then the
handlerRouterCallbackMessageCommandHandlersearches the appropriate for string/startpath inutrlsand
finds a suitable path'' + 'start', and then executes corresponding start function.This distribution of handlers allows you to group part of the handlers into modules and quickly connect or
change them, while not being afraid of confusion which handlers need to be called, as it can be if all paths from
different modules to handlers are described in one place as required byPython-Telegram-Bot.In this example filebase.utrls.pyalso ViewSets are used in addition to simple handler functions likedef startanddef some_debug_func.
ViewSet is an aggregator of several functions. The concept of it is that you quite often need to apply
the same operations for a dataset, such as create, update, show, delete an example of dataset.
There is the classtelegram_django_bot.td_viewset.TelegramViewSetin the library  for such purposes. The class manages
the Django ORM database model.TelegramViewSethas 5 functions for managing the model:МетодUTRLDescriptioncreatecrCreate modelchangeupChange model attributesdeletedeDeleting a modelshow_elemseDisplay a modelshow_listslDisplay a list of modelsThus, if we want to call theBotMenuElemViewSet.createmethod to create an element, we need to use
path ‘sb/cr’, whereby the first part of the path ‘sb/’  the routerRouterCallbackMessageCommandHandlerwill execute
theBotMenuElemViewSetclass, namely theTelegramViewSet.dispatchmethod, which in turn will call  thecreatemethod by analyzing the second part of the pathcr.To sum up the scheme of handlers routing, there are following key points:telegram.ext.Updateis used as a receiver of messages from Telegram;Standard handlers of thePython-Telegram-Botlibrary can be used as handlers. For convenient use Django’s path scheme andTelegramViewSetyou need to useRouterCallbackMessageCommandHandler.TelegramViewSetaggregates a set of standard functions for managing data, what is made possible to group code associated with one type of data type in one class (place).TelegramViewSet featuresAs described above, TelegramViewSet contains standard functions for data manipulation.
Due to such standard data processing methods, it turns out in the example to describe the logic ofBotMenuElemViewSetin 40
lines of code, also using some customization for beautiful data displaying.To use all the features of the TelegramViewSet in your class, it should be inherited from it, as, for example, this is done
in theBotMenuElemViewSet:fromtelegram_django_bot.td_viewsetimportTelegramViewSetclassBotMenuElemViewSet(TelegramViewSet):In order to customize the ViewSet, you must specify 3 required attributes:viewset_name- class name, used to display to telegram usersmodel_form- data form, used to specify which fields of the ORM database model to use in the viewset;queryset- basic query for getting model elements.TheBotMenuElemViewSetis used the following values:fromtelegram_django_botimportformsastd_formsfromtelegram_django_bot.modelsimportBotMenuElemclassBotMenuElemForm(td_forms.TelegramModelForm):form_name=_("Menu elem")classMeta:model=BotMenuElemfields=['command',"is_visable","callbacks_db","message","buttons_db"]classBotMenuElemViewSet(TelegramViewSet):viewset_name='BotMenuElem'model_form=BotMenuElemFormqueryset=BotMenuElem.objects.all()whereBotMenuElemFormis a descendant of theDjango ModelFromclass, so it has a similar structure and parameterization methods.
`` form_name ``  stands for the name of the form and is used in some messages sent to Telegram users.TelegramViewSet has quite a lot in common with Viewset analogs tailored for WEB development (for example,django-rest-framework viewsets). However, as part of the development of Telegram bots, TelegramViewSet
has some special features:An unusual way to create elements;The display of information in bots is limited and most often comes down to displaying text and buttons, so the viewset in addition to business logic includes the creation of standard responses to user actions in the form of messages with buttons.FormsSince Telegram does not have the ability to create forms (in the classic Web sense) and communication between the bot and the user takes place in a chat, then
the most intuitive solution for filling out a form (creating an element) is filling the form attribute by attribute,
when the first element of the form is filled first, then the second, and so on. With this approach, it is necessary to use temporary storage for remembering
specified values in order to create an element from the form at the end.TelegramModelFormandTelegramFormare implemented just
in such way for taking over this process. The difference between these classes and the standard Django classes is precisely
in the modification of the method of filling in the form fields, otherwise they do not differ from standard forms.TelegramModelFormandTelegramFormas Django descendants ofModelFormandFormhave the following parameters, which you may need to customize:The clean function and otherform validation process functions;labels- field names;forms.HiddenInput- designation of hidden fields (hiding fields allows them not to be shown to the user, while using and configuring in forms or inTelegramViewSet).TelegramViewSetis designed to interact with descendants of theTelegramModelFormclass and allows you to use
generate forms with different fields, such asCharField, IntegerFieldorForeignKey, ManyToManyField. Also, it is a good idea
to use theprechoice_fields_valuesdictionary inTelegramViewSetdescendants for improving the convenience of filling out forms for users.
It is possible to store a list of frequently used values of form fields in theprechoice_fields_values.
This allows users to select the desired values by clicking buttons rather than
writing text manually. The template has an example of using this field:classBotMenuElemViewSet(TelegramViewSet):...prechoice_fields_values={'is_visable':((True,'👁 Visable'),(False,'🚫 Disabled'),)}In this case, 2 values are specified for choosing true or false for the boolean fieldis_visable. You can also useprechoice_fields_valuesforCharField, IntegerFieldor any other fields.
Sometimes the list of values needs to be generated dynamically, in which case you can overrideprechoice_fields_valuesas a@propertyfunction.Key logic of TelegramViewSetThe main function of the class, which is selected the function for managing data by the request of the user,  isTelegramViewSet.dispatch.
Let’s analyze its logic in more detail:defdispatch(self,bot,update,user):self.bot=botself.update=updateself.user=userifupdate.callback_query:utrl=update.callback_query.dataelse:utrl=user.current_utrlself.utrl=utrlifsettings.DEBUG:logging.info(f'utrl:{utrl}')utrl_args=self.get_utrl_params(re.sub(f'^{self.prefix}','',self.utrl))ifself.has_permissions(bot,update,user,utrl_args):chat_action,chat_action_args=self.viewset_routing[utrl_args[0]](*utrl_args[1:])else:chat_action=self.CHAT_ACTION_MESSAGEmessage=_('Sorry, you do not have permissions to this action.')buttons=[]chat_action_args=(message,buttons)res=self.send_answer(chat_action,chat_action_args,utrl)utrl_path=utrl.split(self.ARGS_SEPARATOR_SYMBOL)[0]# log without params as to much varientsadd_log_action(self.user.id,utrl_path)returnresLike a regular handler, the function takes 3 arguments as input: bot, update, user. After saving these arguments in class,
the determination of the current routing path is occurred. It is determined either by pressing a button in the bot (thecallback_datavalue of the button), or
can be stored in the user attributeuser.current_utrl. The second option is possible if the user manually enters
some information (for example, filled in a text field of form). After that, the arguments are extracted from the path
to call a specific function. Storing and interacting with arguments in a path is similar to howsys.argvworks. So,
for example, the string"sl&1&20"will be converted to the list['sl', '1', '20']. The separator character between attributes
is&by default and can be changed via theTelegramViewSet.ARGS_SEPARATOR_SYMBOLvariable.When usingTelegramViewSetyou most likely won’t have to interact with the argument string directly, sincedispatchconverts a string into arguments. And for creating acallback_databutton string, that the user can call another method from Telegram interface, you should useTelegramViewSet.gm_callback_datafunction. In case you need more low-level interaction with function arguments, then
you can use theconstruct_utrlandget_utrl_paramsfunctions.After receiving the utrl_args arguments and checking access rights, the managing method (action) is directly selected and called.
The first argument, which is the short name for the function, is popped from the utrl_args. All other arguments are passed as parameters
into a function. Inside the function, the necessary business logic and the data formatting for displaying to the user as a response take place.
Any such managing function in theTelegramViewSetclass must return the action typechat_actionand the parameters to that actionchat_action_args.
By default, the class has only 1 action ﹣CHAT_ACTION_MESSAGE, which means that the user will receive
a text message (possibly with buttons) as an answer for his/her action. The arguments for this action are the text of the message and a list of buttons (can be None).After the function is processed, a response is sent to the user bysend_answerfunction and the user’s action is logged.The methods to call inviewset_routingare thecreate, update, delete, show_elem, show_listmethods.
You can also add your own methods. Suppose we want to add adef super_method(self, *args)method, then
you need to add the following lines in the class:classSomeViewSetClass(TelegramViewSet):...actions=['create','change','delete','show_elem','show_list','super_method']command_routing_super_method='sm'defsuper_method(self,*args):...Whereactionsdefines the list of available methods andcommand_routing_<method>defines the path (url; short name) of the method.As noted above, thedispatchmethod performs a permissions check by calling thehas_permissionsmethod.
The check is performed by the classes specified inpermission_classesand the default class isAllowAny:classTelegramViewSet:permission_classes=[AllowAny]Additional TelegramViewSet ToolsThis section describes the following class functionality that makes it easier to write code:External filters;Data display setting options;Helper functions for displaying data;Helper functions of business logic;External filtersQuite often, there is a situation when you need to work not with all the elements of a database table, but with some
group (for example, a group of elements with a specific foreign key). For such purposes, you should use theforeign_filterslist,
which stores the values for filtering when the method is called. How exactly to use these filters is up to you, but
usually it is a good idea to use it in theget_querysetfunction. Thus, it is possible to pass to functions
additional arguments that do not break the key logic of standard functions. Using the template example, you can modifyBotMenuElemViewSetso that if an additional parameter is specified, then the BotMenuElem list displays
only those elements that contain the specified parameter in theircommandattribute. To do this, you need to make the following changes to the code:classBotMenuElemViewSet(TelegramViewSet):...foreign_filter_amount=1defget_queryset(self):queryset=super().get_queryset()ifself.foreign_filters[0]:queryset=queryset.filter(command__contains=self.foreign_filters[0])returnquerysetWhereforeign_filter_amountspecifies the number of foreign filters. To call a method with a filter value, you must
specify them right after the function name in the path (utrls):"sb/sl&start&2","sb/sl&start&2&1","sb/sl&hello.
It is worth noting that if we do not want to specify a filter, then we need to skip the argument in the path (utrls) in the next way:"sb/sl&&2".There is no need to construct and process filters in paths (utrls) directly, since the functionsgm_callback_dataandget_utrl_paramsknow how to work with them. gm_callback_data also has a parameteradd_filters(default True) which defines
whether to include filters in the generated path (utrl) or not. If the value is False , then it is necessary in the function arguments
manually specify filters:self.gm_callback_data('show_list','start', add_filters=False)(will generate"sb/sl&start).
This allows you to change the value of filters when generating paths.A more detailed use of external filters can be seen in the example ofDrive Bot.Data display optionsTheTelegramViewSethas the following options for displaying model elements:updating_fields: list- list of fields that can be changed (displayed when showing the element (show_elem);show_cancel_updating_button: bool = True- shows a cancel button when changing fields, which leads back to the displaying element (show_elem);deleting_with_confirm: bool = True- ask the user for confirmation when deleting an element;cancel_adding_button: InlineKeyboardButtonDJ = None- cancel button when creating an element (createmethod);use_name_and_id_in_elem_showing: bool = True- enables the use of the name and ID of the element when displaying this element (methodsshow_listandshow_elem);meta_texts_dict: dict- a dictionary that stores standard texts for display (texts are used in all methods).However, these fields are not always enough and you need to redefine the logic of helper functions for a beautiful display of information.Helper functions for displaying dataTheTelegramViewSetclass describes the following helper functions for generating a response message:def gm_no_elem- if no element with this ID was found;def gm_success_created- successful creation of the model;def gm_next_field- when moving to the next form attribute;def gm_next_field_choice_buttons- generates buttons to select options for a specific form attribute (used insidegm_next_field);def gm_value_error- error output when adding a form attribute;def gm_self_variant- generates a message about the need to write the value manually by the user;def gm_show_elem_or_list_fields- displays model fields in the message (used inshow_elemwithfull_show=True, and inshow_list﹣withfull_show=False);def gm_value_str- generates a string displaying a specific attribute (used ingm_show_elem_or_list_fields);def gm_show_elem_create_buttons- displays available buttons (actions) when showing a model element (callingshow_elem) ;def gm_show_list_button_names- generates the names of item buttons when displaying the list (callingshow_list);Depending on the need for customization, it is necessary to redefine these functions.Helper functions of business logicTheTelegramViewSetclass uses the following helper functions:def get_queryset- allows you to modify Model queries to the database (most often used to filter elements, as in the example above);def create_or_update_helper- main logic forcreateandupdatemethods;def show_list_get_queryset- allows you to customize the selection of items to display in show_list;handler_decorWhen writing your own handlers, it is recommended to use a wrapper liketelegram_django_bot.utils.handler_decor,
which performs the following functions:Getting or creating a user in the database;In case of an error inside the handler function, returns an error message to the user;Logs the handler call;Tracks where the user came from;Choice of language for sending messages to the user (in the case of localization enabled);This handler is also used insideRouterCallbackMessageCommandHandler, and as a result in callingTelegramViewSetclasses.LocalizationThe library expands theDjango localization toolsfor use in Telegram.
To support the use of different languages, the main elements of the Python-Telegram-Bot library are redefined intelegram_django_bot.telegram_lib_redefinition:telegram.Bot->telegram_django_bot.BotDJ;telegram.ReplyMarkup->telegram_django_bot.ReplyMarkupDJ;telegram.KeyboardButton->telegram_django_bot.KeyboardButtonDJ;telegram.InlineKeyboardButton->telegram_django_bot.InlineKeyboardButtonDJ;telegram.InlineKeyboardMarkup->telegram_django_bot.InlineKeyboardMarkupDJ.When using these classes in code, multilingual support comes down to the following steps:Specifying the necessary settings in the settings.py file:LANGUAGES- list of languages,LANGUAGE_CODE- default language;Create folder with translations:$django-adminmakemessages-l<language_code>Necessary texts for translation are wrapped ingettextandgettext_lazyfromdjango.utils.translation(how it works in Djangoread here)Run command$django-adminmakemessages-ato update texts for translation (created in locale folder)Generation of translation files$django-admincompilemessages.Only a part of the functions uses localization in the template. It is made for easy understanding. The usage of localization can be seen in the example
functionssome_debug_func.Extra lib featuresThe library provides some additional tools for the convenience of developing and managing the bot.Embedded ORM lib modelsFor the correct work ofTelegramViewSetand other components the Django ORM model representing the user in Telegram must be inherited
fromtelegram_django_bot.models.TelegramUser, as these components use its fields.TelegramUserinherited fromdjango.contrib.auth.models.AbstractUser(which allows you to authorize users on the site if necessary) and has
the following additional fields:id- redefined to use user ID from telegrams;seed_code- arbitrary value from 1 to 100 to randomly group users for tests and analysis;telegram_username- username of the user in telegram;telegram_language_code- telegram language code (some languages have dialects and as a result the code designation is more than 2 symbols);timezone- the user’s time zone (for determining the time);current_utrl- path (utrl) of the last user action (used inTelegramViewSet);current_utrl_code_dttm- time of the last action, when saving the path;current_utrl_context_db- path context (utrl);current_utrl_form_db- intermediate data for the form. Acts as a temporary data store when filling out a form;Fieldscurrent_utrl_<suffix>are needed forTelegramViewSet,TelegramModelFormand are needed in exceptional cases
when writing code. The model also has the following methods (property) to simplify interaction with model fields:current_utrl_form(property) - returns the current temporarily stored path form data (utrl);current_utrl_context(property) - returns the current path context (utrl);save_form_in_db- saves the form in thecurrent_utrl_form_dbfield;save_context_in_db- saves the context in the fieldcurrent_utrl_context_db;clear_status- clears the data associated with the used path (fieldscurrent_utrl_<suffix>) ;language_code(property) - returns the language code in which messages should be generated for the user;If you want, you can create your self Django ORM model representing the user, you just need to copyid, telegram_username, telegram_language_code, current_utrl, current_utrl_code_dttm, current_utrl_context_db, current_utrl_form_dband corresponding functions.The library also describes additional models to improve the usability of the bot:ActionLog- stores user actions. Records help to collect analytics and make triggers that work on certain actions;TeleDeepLink- stores data on which links new users have clicked (to analyze input traffic);BotMenuElem- Quite often a bot needs messages that have only static data. These pages can be help and start messages.BotMenuElemallows you to configure such pages through the admin panel, without having to write anything in the code. InBotMenuElemthere is the ability to customize pages depending on the starting deeplinks.BotMenuElemcan not only add buttons to the message, but also send different files. To do this, you must specifymediaand the file formatmessage_format.BotMenuElemallows you to quickly change bot menu blocks without having to make changes to the code;BotMenuElemAttrText- helper model forBotMenuElem, responsible for translating texts into other languages. The elements themselves are created depending on the specified languages in theLANGUAGESsettings. You only need to fill in the translation in thetranslated_textfield;Trigger- allows you to create triggers depending on certain actions. For example, remind the user that he has left incomplete order, or give a discount if it is inactive for a long time. For triggers to work, you need to add tasks fromtelegram_django_bot.tasks.create_triggersto CeleryBeat schedule;UserTrigger- helper model forTrigger, controlling to whom triggers have already been sent;Additional functions of TG_DJ_BotTo improve convenience,TG_DJ_Bothas several high-level functions:send_format_message- Allows you to send a message of an arbitrary type (internally, depending on themessage_formatselects the appropriate method of thePython-Telegram-Botlibrary). An important feature of this function is that if the user clicks on the button, then the previous message of the bot is changed, rather than a new one being sent. If, nevertheless you need to send a new message to the user, then you need to set the parameteronly_send=True;edit_or_send- wrapper of thesend_format_messagemethod for sending text messages with buttons;send_botmenuelem- Sends aBotMenuElemto the user. Theupdateargument can be empty;task_send_message_handler- created for sending messages to many users. Handles situations where the user blocked the bot, deleted or when the limit for sending messages to users is reached;UtilsThe following additional functions are provided in the libraries:telegram_django_bot.utils.add_log_action- to create a user ActionLog;telegram_django_bot.utils.CalendarPagination- class for generating a calendar with buttons;telegram_django_bot.user_viewset.UserViewSet- telegram user class for changing language and time zone;Routing detailsIn this section, we will analyze the work ofRouterCallbackMessageCommandHandlerandtelegram_reversein a little more detail.As described earlierRouterCallbackMessageCommandHandleris used to be able to write handlers in the style
Django. AlsoRouterCallbackMessageCommandHandlerprovides the ability to handle calls toBotMenuElemas
through commands, and through callback. This is achieved by using the functionsall_command_bme_handlerandall_callback_bme_handler. By default,BotMenuElemcall handling is enabled and handled after
no suitable path was found in the description of utrls (paths in Django notation). If there is noBotMenuElemelement
match is found, theBotMenuElemis considered to be configured incorrectly and an error message is returned to the user.
You can create a class with theonly_utrl=Trueattribute, what is disable calls toBotMenuElem.The example template contains the use of thetelegram_reversefunction, the essence of which is to generate a path (string) to the
handler specified in the function argument. The function is analogous to thereverseDjango function
and avoids errors when changing paths.TestsThe library also extends thedjango.test.TestCasecapabilities for use with Telegram through theTD_TestCaseclass.The simplest approach for testing the bot is to generate messages that the bot expects from Telegram and
send a response to Telegram (to check that the bot’s response messages are in the correct format). ClassTD_TestCasehas a functioncreate_updatefor easy and fast creation ofTelegram.Updatewhich generates the request
telegram user. So the overall design looks like this:ATelegram.Updateis created for emitting a user request;Thehandle_updatelambda function, which usesRouterCallbackMessageCommandHandler,  is called with created update. It does its staff and as a result sends a real message to the test user. Due to this, the correctness of the response data format  is checked by Telegram;The correctness of the sent data and changes in the database is checked using the standard toolsdjango.test.TestCase.You need to specify at least one test user ID in theTELEGRAM_TEST_USER_IDSsettings section for correct tests work.
Messages will be sent to that user, so the bot needs to have permission to write to that user.In thetestsfolder you could find test examples.