#36872: Django's template engine cannot handle asynchronous methods
-------------------------------------+-------------------------------------
     Reporter:  rrobles              |                     Type:  Bug
       Status:  new                  |                Component:  Template
                                     |  system
      Version:  6.0                  |                 Severity:  Normal
     Keywords:  Template, Async      |             Triage Stage:
                                     |  Unreviewed
    Has patch:  0                    |      Needs documentation:  0
  Needs tests:  0                    |  Patch needs improvement:  0
Easy pickings:  0                    |                    UI/UX:  1
-------------------------------------+-------------------------------------
 Currently, the Django template is not designed to execute asynchronous
 methods; it is only designed to execute synchronous methods.

 Here's an example of how to reproduce the error:


 {{{
 from django.template import engines

 django_engine = engines['django']

 class Example:
     def sync_method(self):
         return "Synchronous Method Result"
     async def async_method(self):
         return "Asynchronous Method Result"

 html_string = """
 <!DOCTYPE html>
 <html>
 <head>
     <title>Example</title>
 </head>
 <body>
     <h1>sync: {{ example.sync_method }}!</h1>
     <p>async: {{ example.async_method }}</p>
 </body>
 </html>
 """

 template = django_engine.from_string(html_string)
 rendered_html = template.render({'example': Example()})

 print(rendered_html)
 }}}

 This will return this error:

 {{{
 <!DOCTYPE html>
 <html>
 <head>
     <title>Example</title>
 </head>
 <body>
     <h1>sync: Synchronous Method Result!</h1>
     <p>async: &lt;coroutine object Example.async_method at
 0x7bdeeb9aa980&gt;</p>
 </body>
 </html>
 }}}

 I had thought that a solution to this error might be to modify the resolve
 method of the FilterExpression class
 https://github.com/django/django/blob/main/django/template/base.py#L785

 If we add this:

 {{{
 class FilterExpression:
     ...

     def resolve(self, context, ignore_failures=False):
         if self.is_var:
             try:
                 obj = self.var.resolve(context)

                 # My proposal begins
                 if asyncio.iscoroutine(obj):
                     try:
                         loop = asyncio.get_event_loop()
                     except RuntimeError:
                         loop = asyncio.new_event_loop()
                         asyncio.set_event_loop(loop)

                     if loop.is_running():
                         obj = loop.run_until_complete(obj)
                     else:
                         obj = asyncio.run(obj)
                 # My proposal ends

             except VariableDoesNotExist:
                 ...
 }}}

 Now it renders correctly:

 {{{
 <!DOCTYPE html>
 <html>
 <head>
     <title>Example</title>
 </head>
 <body>
     <h1>sync: Synchronous Method Result!</h1>
     <p>async: Asynchronous Method Result</p>
 </body>
 </html>
 }}}

 I use Django ASGI a lot at work, and there are many features like this
 that would be very useful. I look forward to your feedback.
-- 
Ticket URL: <https://code.djangoproject.com/ticket/36872>
Django <https://code.djangoproject.com/>
The Web framework for perfectionists with deadlines.

-- 
You received this message because you are subscribed to the Google Groups 
"Django updates" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To view this discussion visit 
https://groups.google.com/d/msgid/django-updates/0107019bdad5c8cc-e117fe00-5cc0-4e64-be72-ea44afd3ec87-000000%40eu-central-1.amazonses.com.

Reply via email to