如何使用Django异步视图异步发送邮件?

3
我正在建立一个项目,当用户执行特定操作时,我希望发送通知邮件。通过一些搜索,我使用了线程threading.Thread实现了这个功能。由于Django现在完全支持异步视图,我想使用异步函数来完成它。以下是我尝试的内容:
from asgiref.sync import sync_to_async
from django.core.mail import send_mail
from django.shortcuts import render
from myproj.settings import EMAIL_HOST_USER
import asyncio

asend_mail = sync_to_async(send_mail)

async def index(request):
    asyncio.create_task(
        asend_mail(
            subject='Test',
            message='Lorem ipsum',
            from_email=EMAIL_HOST_USER,
            recipient_list=['ezon@stackoverflow.dummy']
        )
    )
    return render(request, 'myapp/index.html', {})

然而,当我请求这个索引页面时,我仍然会在asend_mail协程完成之后才收到响应。

我尝试了下面这个简单的异步函数(来自教程),一切都按照预期工作。

async def async_print():
    for num in range(1, 6):
        await asyncio.sleep(1)
        print(num)

async def index(request):
    asyncio.create_task(async_print())
    return render(request, 'myapp/index.html', {})

我想知道上述两种情况之间的主要区别是什么。

我正在使用Python 3.10.7,Django 4.1.2,Daphne 3.0.2(作为服务器,而不是Django的开发服务器)。

我对async/await功能不熟悉。如果有人能够给出全面的解释,我将不胜感激。


你需要添加一个包装器,awaitasend_mail上。 - Brian Destura
你能提供一些代码片段吗?我刚试过了 async def real_asend_mail(*args, **kwargs): await asend_mail(*args, **kwargs),并调用了 real_asend_mail,但仍然在邮件发送后得到了响应。 - Ezon Zhao
哦,是的,看起来不错。另外确认一下,你仍然使用了 asyncio.create_task(real_asend_mail(...)) 吗?如果还是不行,你可以尝试在 sync_to_async 中添加 thread_sensitive=False 参数。 - Brian Destura
添加 thread_sensitive=False 就可以了。谢谢!但是为什么呢?这与我在控制台中运行 Daphne,使服务器只有一个进程有关吗? - Ezon Zhao
1个回答

0

我会尝试使用线程(参见:https://realpython.com/intro-to-python-threading/ 参考)

我曾经用它来上传数千个(大)文件到 S3 存储桶。这比顺序执行快了 70 倍。

这个想法是将此电子邮件任务包装在一个线程中,然后发出该线程,并且您的代码将从那里继续而不是等待任务(在线程中)完成。


1
我想了解关于async/await函数的答案。我知道如何在子线程中发送电子邮件。 - Ezon Zhao

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接