I’m using the latest pre-release version of Django 3.1 with wsgi. I have a view that calls a method to create a PDF. I want the view to return JSON with just the path to the PDF that will be created so that I can poll for it later and download it once it exists.
I’ve tried this:
async def create_pdf(request, slug):
m = Material.objects.get(slug=slug)
path_to_pdf = 'some/path/to/pdf.pdf'
m.create_pdf(path_to_pdf) # Don't wait for this to finish
data = {
'pdf': path_to_pdf
}
return JsonResponse(data)
I get the following error:
The view materials.views.create_pdf didn’t return an HttpResponse object. It returned an unawaited coroutine instead. You may need to add an ‘await’ into your view.
I tried adding await
before the call to m.create_pdf
(although I don’t want to wait for that to finish), but I still got the same error.
I’d appreciate any help. Thanks.
I’m really hoping someone else more familiar with the environment chimes in here - and that means just about anyone. What follows is about 75% conjecture. (I’m only posting this because I’d like to learn more about this as well and am hoping a discussion ensues.)
I don’t think you’re going to be able to “not-wait” if you’re running in a wsgi
environment. My understanding is that the view itself would run in a one-off event loop, but that that loop needs to end before the view returns results.
(That’s how I interpret the second paragraph of Async Views)
Also, since the ORM is not currently async-capable, you might have issues with the create_pdf
method not being async-friendly.
I believe that to achieve your real goal, you’d need to run this in an asgi container.
1 Like
Hi @natdunn.
At first glance, an async view isn’t really what you want here. Rather you want to be off-loading the create_pdf
task to some kind of queuing system. I’m a big fan of Django-Q — it’s nice and lightweight, and most of what you need most of the time.
The async def
doesn’t do anything to let you pass a task off to the background by itself. And an await
just says, more or less, to the interpreter, “You can go an do something else for a while because I’ll be waiting for I/O for a moment”. Importantly, it doesn’t let your view move on to the part where it returns a response early. So you still need an out of band processing channel somehow (basically a queue).
The move to async opens to the door maybe to that sort of thing appearing in Django one day, but it’s not there yet. As I say, Django-Q is super. I’d point you that way.
I hope that helps.
3 Likes
Thanks @carltongibson and @KenWhitesell! I guess this is the crux of it:
The async def
doesn’t do anything to let you pass a task off to the background by itself.
I’ll check out Django-Q. Thanks for the tip!