django template tags with async view

Question:

As soon as I add async in front of a view, my template which contains {% if request.user.is_authenticated %} causes a SynchronousOnlyOperation, You cannot call this from an async context – use a thread or sync_to_async.

The error only occurs when a user is logged in, hence is_authenticated==True. What am I not getting here?

view

async def test(request):
    return render(request, 'test.html')

template, test.html

{% if request.user.is_authenticated %}
<script>
  const usr = "{{user}}";
</script>
{% endif %}
Asked By: noob112233

||

Answers:

When the current user is not authenticated, request.user is an AnonymousUser, so is_authenticated is just false. However, when request.user is an actual user, it needs to check through the ORM if the user is authenticated. The ORM is synchronous (except in a few situations), so this doesn’t work in an async context. To make this work, use sync_to_async in the view:

from asgiref.sync import sync_to_async
async def test(request):
    return render(request, 'test.html', {"is_authenticated": await sync_to_async(lambda: request.user.is_authenticated)()})

And in test.html:

{% if is_authenticated %}
<script>
  const usr = "{{user}}";
</script>
{% endif %}

I know it’s a pain, but for now it’s the only way. Here’s hoping that Django will add asynchronous support ORM-wide in the next release.

Answered By: pigrammer
Categories: questions Tags: ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.