async in templates

Doc says (Asynchronous support | Django documentation | Django):

async for author in Author.objects.filter(name__startswith="A"):
    book = await author.books.afirst()

But a pattern I use often (is that even a pattern… ;-|) is this:

views

def get_context_data(self):
    # get parent context
    objs = Model.objects.filter(...)
    context['objs'] = objs
    return context

Now I understand the queryset won’t be evaluated for a long as it’s not “used”. But then in template:

<ul>
{% for obj in obj %}
    <li>{{ obj.field }}</li>
{% endfor %}
</ul>

That for loop: is it async? If not, how to garantee it is?

You want to change your perspective on how you look at this.

Templates are not “code”, they don’t execute.

The rendering engine reads the template and processes it as text. When it’s parsing the text, the {{ }} symbols are handled as a reference to a variable.

So it doesn’t make sense to even think of that for loop as being async.
(See Templates | Django documentation | Django)

What you would need to identify is whether or not the rendering engine is async, and I’m fairly sure the answer to that is currently “no”. (I can find no evidence in the docs or the code to give me any indication that it is.)

If you believe that there is an advantage to you executing this query in an async mode, then you will want to ensure the queryset is resolved in the view before handing it off to the rendering engine.

Thank Ken, I know they do not execute. But whatever the terminology, the idea is that querysets are lazy and that once called in templates (and field “extracted” from them?), they are “unlazyfied”.

That’s too bad if the templating/rendering engine is not async. :[
Guess the (awesome) django team has already quite a lot to do… :slight_smile:

Then to react to “you will want to ensure the queryset is resolved in the view”. How? list(queryset) seems to be excluded:

Be aware that you also can’t do other things that might iterate over the queryset, such as wrapping list() around it to force its evaluation (you can use async for in a comprehension, if you want it).

so something like this?

async def get_context_data(self):
    # get parent context
    objs = Model.objects.filter(...)
    objs_list = []
    async for obj in objs:
        objs_list.append(obj)
    context['objs'] = objs_list
    # or like this?
    context['objs'] = [obj async for obj in objs]
    return context

You might find something useful in this Django forum post: Is it feasible to improve streaming HTML in Django?

Looking forward to hearing how you got on.

That would seem to be the way to do it.

If the template rendering engine would not support being async, then you could not have async functiona-based-views, no? I believe that async class-based-views are not yet supported, which trickles down to not being able to use async template rendering in CBVs.

Hi everyone,

A thing I do now for managing async template data is very simple.

In a view I do something like that

modelData = Model.objects.all()
            html = "async/asyncAds.html"
            context = {
                "data": modelData
            }

            return HttpResponse(render(request, html, context))

Now from my async function in JS

Example :

async function Fetch(addr, p = null) {

  command = {
    command_type: addr,
    parameter: p
  }
  const csrftoken = getCookie("csrftoken");
  const request = new Request("asyncUrl/", {
    method: "POST",
    headers: { "X-CSRFToken": csrftoken },
    mode: "same-origin", // Do not send CSRF token to another domain.
    body: JSON.stringify(command)
  });
  const response = await fetch(request);
  
  const serverInfo = await response.text();

  return serverInfo;
}

Now, from the caller function, I can queryselector where I want put this html content. remove previous content and add the new content.

Very easy. No need extensive js to contruct the data. In fact it 100x better than PHP because the django render method do all the job for you.

You just need a template with all the preformatted html you want send back.