2

I use the python-telegram-bot 20.0a2 library and Django 4.1

The bot runs by main.py script:

if __name__ == "__main__":
    asyncio.run(main())

Inside of the main script I also run uvicorn in the same ascynhronous context as Application instance

# Run application and webserver together
async with application_tg:
    await application_tg.start()
    await server.serve()       # uvicorn
    await application_tg.stop()

What is the problem?
I use webhook for my bot
Django's url.py calls async view but the view can't get initalized Application instance of the bot.

so the question is:
How can to rearrange a scheme of interaction between python-telegram-bot 20 and Django 4.1 in a way that I can access Application instance from a Django hook?

Addition:
It's easy to achieve by using other frameworks such as starlette as it mentioned on the official wiki page of PTB library: https://docs.python-telegram-bot.org/en/v20.0a2/examples.customwebhookbot.html


My main script: https://gist.github.com/SergSm/6843fadf505b826f83a10bf7eebc3fa0

my view:

import json
from django.views import View
from django.http import JsonResponse, HttpResponse
from django.views.decorators.csrf import csrf_exempt

from telegram import Update

from bot.tgbot.main import application_tg

async def telegram_handle(request):
    if request.method == 'POST':
 
        await application_tg.update_queue.put(
            Update.de_json(data=json.loads(request.body), bot=application_tg.bot)
        )
 
        return JsonResponse({"ok": "POST processed"})
    else:
        return JsonResponse({"ok": "GET processed"})

UPDATE 1

I was desperate to make it run this way. I tried to use contextvars module and read a lot of asyncio related stuff/

In the end I made an awful assumption that if I put my python-telegram-bot code into the Django view async function it's gonna work. But it does work!

And now I will try to wrap it using middleware to make my code cleaner

UPDATE 2

If you want to use Django orm with sync functions you need to use @sync_to_async(thread_sensitive=False)

the thread_sensitive=False parameter is important in this case otherwise you will never get the result of awaitables

arpa
  • 328
  • 3
  • 13
  • Does this answer your question? [django variable available to all the views](https://stackoverflow.com/questions/55697465/django-variable-available-to-all-the-views). Also if you're using Django anyways, I'm wondering why you're using `uvicorn` for the webserver instead of having Django handle that as well – CallMeStag Aug 15 '22 at 05:53
  • I use `uvicorn` instead of Django itself because it's the right way for a production https://docs.djangoproject.com/en/4.1/howto/deployment/ – arpa Aug 15 '22 at 06:28
  • @CallMeStag I will dig into using of Django middleware for this problem and will write the result later – arpa Aug 15 '22 at 06:35
  • ah okay, thanks for the clarification. I somehow thought that django had a built-in webserver … – CallMeStag Aug 15 '22 at 08:38
  • Hey! Did you fix this? I’m kind of at the same zone :/ – Cristian Favaro Carriço Nov 15 '22 at 01:00
  • 1
    @CristianFavaroCarriço well yes but my code is a total mess. Some context: the main goal of my bot is to implement a telegram webapp using Heroku free tier(it'll shutdown soon). Some sort of a proof-of-concept. If you are still interested I will clean my code and share it on github. What do you think? – arpa Nov 16 '22 at 08:57
  • 1
    @CristianFavaroCarriço for now I may show you the gist with 2 main files for this trick. Here you are: https://gist.github.com/SergSm/0244b3c86d691c8ae31f4a1881f4ce54 – arpa Nov 16 '22 at 08:59
  • Thanks.m, man. I’ll take a look and see if your code helps me. My thing is that I want to keep using Django db instead of running a different process in my server… don’t know if this is the best approach btw. – Cristian Favaro Carriço Nov 19 '22 at 03:19

0 Answers0