Opened 2 hours ago
#36872 new Bug
Django's template engine cannot handle asynchronous methods
| Reported by: | Ricardo Robles | Owned by: | |
|---|---|---|---|
| Component: | Template system | Version: | 6.0 |
| Severity: | Normal | Keywords: | Template, Async |
| Cc: | Triage Stage: | Unreviewed | |
| Has patch: | no | Needs documentation: | no |
| Needs tests: | no | Patch needs improvement: | no |
| Easy pickings: | no | UI/UX: | yes |
Description
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: <coroutine object Example.async_method at 0x7bdeeb9aa980></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.