ERROR: Your view return an HttpResponse object. It returned an unawaited coroutine instead. You may need to add an 'await' into your view

Viewed 3177

I am working on a Django Project where i add an event to the database and then send an email to all the subscribers after adding event. I want to do the sending email task async, i followed some blog post and come up with this.

from asgiref.sync import sync_to_async
import asyncio

This is the add event view

@login_required(login_url='/login/')
async def add_event_view(request):

    if request.method == 'POST':

        title = request.POST.get('title')
        description = request.POST.get('editor')
        menu = request.POST.get('menu')
        tags = request.POST.get('tags')
        banner = request.FILES.get('banner')
        data = request.FILES.get('data', None)
        organised_by = request.POST.get('organised_by', None)
        sponsored_by = request.POST.get('sponsored_by', None)
        event_date = request.POST.get('event_date', None)
        uploaded_at = request.POST.get('uploaded_at')

        Event.objects.create(user_id=request.user, event_title=title, event_description=description, event_category=menu, event_tags=tags,
                             event_banner=banner, event_data=data, organised_by=organised_by, sponsored_by=sponsored_by, event_date=event_date, uploaded_at=uploaded_at)

        await sync_to_async(send_email(title))

        return redirect(etab_view)

This is the email sending function

async def send_email(title):

    event = Event.objects.get(event_title=title)

    content = render_to_string("email.html", {'et': event})

    subs = Subscriber.objects.values_list('email_address', flat=True)

    email = EmailMultiAlternatives('Emagazine Update', content, settings.EMAIL_HOST_USER, list(subs))
    email.attach_alternative(content, "text/html")
    email.fail_silenty = False
    email.send()  

I am getting the following error:

The view EMAG_APP.views.add_event_view didn't return an HttpResponse object. It returned an unawaited coroutine instead. You may need to add an 'await' into your view.

Can anyone help me out?

2 Answers

The problem appears to be that the login_required decorator doesn't currently support async views (see https://code.djangoproject.com/ticket/31949). One solution described in that ticket is to wrap the function before the decorator and then unwrap it:

import asyncio

from asgiref.sync import async_to_sync, sync_to_async
from django.contrib.auth.decorators import login_required


@sync_to_async
@login_required(login_url='/login/')
@async_to_sync
async def add_event_view(request):
    ...

I think the problem is in return redirect(etab_view)

What exactly is etab_view? Try replacing it with the name given in urls.py for that view.

See Documentation for redirect

Related