Easy Call async functions in sequential code [Call coroutines in django views]

If you’ve ever tried to call coroutines in Django views, you’ve probably felt that mix of confusion and betrayal when it spits out a coroutine object instead of doing what you actually wanted. “What is this sorcery?” you wonder. Well, it’s not sorcery—it’s Django being Django. You see, Django views are built for good old sequential code. So, when you call an async function in this traditional setting, it just hands you a coroutine object like, “Here, you deal with it.”

Naturally, your next thought might be, “Fine, I’ll just slap an await in there and call it a day.” But no. Django’s like that one friend who refuses to play along. The moment you try await, it throws a tantrum with a SyntaxError: 'await' outside async function. At this point, you’re probably wondering if Django and async functions even like each other. Spoiler: they do—but it’s complicated.

call async functions in sequential code
call async functions in sequential code

So, what’s the solution? How do you make these two frenemies work together without losing your sanity? In this tutorial, we’ll dive into the surprisingly entertaining world of calling async functions in sequential code. Along the way, we’ll figure out how to tame coroutines and get them to play nice with Django views. By the end, you’ll not only solve the problem but also impress your code with your newfound async wizardry. Or at least, that’s the plan!

Call coroutines in django views

Let’s dive into the chaos that unfolds when you try calling async functions in sequential code. Picture this: your trusty Django views are minding their own business, running synchronously, when suddenly, you drop an async coroutine into the mix like a plot twist nobody asked for.

Now, imagine this coroutine is a simple one—it just returns a string. Sounds harmless, right? But no. You try to call it in your Django view, expecting it to hand over the string so you can stuff it into a text file and send it off as a response. Instead, you get greeted with errors so cryptic they might as well be written in Elvish. Why? Because async and sequential code are like cats and dogs—they just don’t play nice together without some serious intervention

Call async functions in sequential code – Always return coroutine object

It seems like a straightforward task—famous last words of every developer ever. With unshakable optimism, you naively whip up the following code, blissfully unaware that Python is lurking in the shadows, ready to ambush you with error messages and shattered dreams.

data.py – The module with coroutine declared with async syntax
import asyncio

async def msg():
    await asyncio.sleep(2)
    return 'hello'
urls.py
from django.urls import path
from . import views

urlpatterns = [
    path('hello', views.hello, name='hello')
]
views.py
from . import data

def hello(request):
    ss = data.hello()
    return HttpResponse(ss,content_type='text/plain')

But when you eagerly test the URL, fully expecting everything to work like a charm, you’re met with a surprise! Instead of the smooth, flawless result you were imagining, you’re greeted with the following text file—what?!

Text File at /hello
<coroutine object msg at 0x7f8504696d48>

This example makes one thing painfully clear: when you call async functions in sequential code, you’ll always get a coroutine object instead of the actual result. Sure, a coroutine object is nice—it’s like getting the gift wrap without the present. But let’s be honest, that’s not what you signed up for. What you really want is the value generated by the async function, not a fancy placeholder that just sits there, mocking you with its unhelpfulness. It’s like asking for coffee and getting an empty cup—you see the potential, but it’s not going to wake you up!

‘await’ outside async function

Luckily, a light bulb goes off—you remember the magic word: await. It’s like the ‘Open Sesame’ of async functions, promising to unlock the treasure trove of generated values. So, with newfound determination (and maybe a hint of desperation), you decide to modify the code to include the await construct, hoping this time Python won’t roll its eyes at you

views.py
from . import data

def hello(request):
    ss = await data.hello()
    return HttpResponse(ss,content_type='text/plain')

When you test the code by accessing the hello URL, you eagerly brace yourself for success… only to be greeted with:

SyntaxError: ‘await’ outside async function
$ ./manage.py runserver 0:8000
Performing system checks...

Unhandled exception in thread ...
ss = await data.msg()
         ^

SyntaxError: 'await' outside async function

It doesn’t solve the problem. Oh no, now the code raises an exception like it’s trying to teach you a lesson. You’re hit with a SyntaxError that practically screams at you: ‘await outside async function.’ It’s like Python is saying, ‘Nice try, but you can’t just sprinkle magic dust on this mess and expect it to work!’

async functions always return coroutine object

Well, you might think this is a no-brainer fix. ‘Just convert the view function to a coroutine with the async construct,’ you think. Simple, right? Like turning a regular pumpkin into a carriage. So, with all the confidence of a developer who’s just discovered a shiny new tool, you decide to make the change and hope for the best. What could possibly go wrong?

views.py
from . import data

async def hello(request):
    ss = await data.hello()
    return HttpResponse(ss,content_type='text/plain')

When you test the code by accessing the hello URL, you’re hoping for smooth sailing… but instead, an exception is raised like an unexpected plot twist in a bad soap opera. You’re greeted with:

exception at /hello : exception ‘coroutine’ object has no attribute ‘get’
 AttributeError at /hello
 'coroutine' object has no attribute 'get'

Oops! As we saw earlier, a function with async syntax will always return a coroutine object—kind of like ordering a pizza and getting a pizza-shaped inflatable instead. But here’s the kicker: sometimes your API doesn’t want a fancy coroutine; it just wants a regular, no-frills function.

In this case, Django (at least, Django 2.15) is looking for an HttpResponse object. But when it tries to call the get method on it, it’s like searching for a missing sock in the laundry—it just can’t find it. And bam! It raises an exception, as if to say, ‘Nice try, but you’re not getting away with this one!’”

How to Call async functions in sequential code?

Alright, let’s embark on the thrilling adventure of calling async functions in sequential code. You’re probably thinking, ‘How on earth do I make this work without a disaster?’ Well, don’t worry—we’ve got a trusty sidekick to help us out: the asyncio module. Think of it like the GPS for navigating the confusing maze of async programming. It’s here to keep you from getting lost in a sea of errors, and maybe even save you from your own bad decisions. So, let’s strap in and see how we can make this work without setting off a chain reaction of chaos!

First things first, we need to create a shiny new event loop with asyncio.new_event_loop. Think of it like setting up a new rollercoaster—you’re building the track so your coroutines can ride smoothly without derailing into a mess of errors. Get ready to strap in, because this event loop is about to take you on a wild ride through async-land!

loop = asyncio.new_event_loop()

The event loop is like the manager of a chaotic circus, and its job is to make sure all the coroutines (the acrobats, clowns, and fire-breathers) perform their tricks in the right order. It’s the unsung hero, tirelessly executing the async functions you throw at it. You can tell the loop, ‘Hey, wait until this coroutine finishes its act,’ and it’ll patiently stand by, twiddling its thumbs, until the show is over. Once the performance is done, it’ll return the generated value, like a satisfied audience member tossing you a bouquet of roses. All of this magic happens thanks to the run_until_complete method. It’s like telling the loop, ‘Alright, take a seat, enjoy the show, and let me know when the final curtain falls!

ss = loop.run_until_complete( data.msg() )

Now, once the event loop has finished its job, it’s time to close the curtain on this wild performance. We need to tell the loop, ‘Alright, you’ve done your part, now go home.’ Closing the loop is like telling the overworked intern to clock out after a 12-hour shift. It’s essential because, without it, the loop will just hang around, sipping coffee and hoarding resources like it’s never heard of ‘spring cleaning.’ By closing the loop, we let it release all the unused resources it’s been hoarding, saving precious memory and making sure your program doesn’t end up with a messy, cluttered backstage. So, don’t forget—when you’re done, give the loop a nice, polite ‘goodbye’ and let it pack up its things!

 loop.close()

Alright, time to pull all the pieces together and see the magic happen! After all that setup, here’s the code that ties everything together—like assembling a quirky puzzle where every piece finally clicks into place. Get ready to marvel at the masterpiece we’ve created!

Call async functions in sequential code

from . import data

def hello(request):
    loop = asyncio.new_event_loop()
    ss = loop.run_until_complete( data.msg() )
    loop.close()

    return HttpResponse(ss,content_type='text/plain')

Now, drumroll please… When you test the code by accessing the hello URL, you’re not hit with an exception! Nope, this time, you get exactly what you were hoping for—the expected contents! It’s like finally finding that missing sock after searching through every drawer. Victory is sweet, my friend!

Text File at /hello
hello

We’ve walked through the problems you encounter when you try to call async functions in sequential code, and we’ve explored how to overcome those pesky issues using the right tools and techniques. But now, it’s your turn! What do you think? Do you have a better solution up your sleeve, or maybe a more elegant way to handle this whole async-sequential showdown? We’d love to hear your thoughts and ideas—because let’s face it, there’s always room for improvement in the world of code!

1 thought on “Easy Call async functions in sequential code [Call coroutines in django views]”

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top