如何将 django 对象发送到 celery 任务?
Posted
技术标签:
【中文标题】如何将 django 对象发送到 celery 任务?【英文标题】:How to send django objects to celery tasks? 【发布时间】:2018-11-12 23:40:57 【问题描述】:大家好!
在我提出问题之前,我尝试了这些 SO 帖子:
Pass parameter request to a celery task in Django passing django request object to celery task它们都不起作用!
我想让用户在网站上更新新课程。使用Courses
的查询集,我想通过电子邮件发送它们。
send_daemon_email.delay(instance=instance,all_courses=Course.objects.all())
我的函数看起来像:
@shared_task
def send_daemon_email(instance,all_courses):
ctx = 'instance':instance,'all_courses':all_courses
message = get_template("emails/ads.html").render(ctx)
''' '''
当我尝试将电子邮件发送给特定用户时 我得到的错误是
<User: First Name> is not JSON serializable
只是因为来自 celery 的delay()
得到了非序列化数据。
如何将 Django 对象发送到 celery 任务,以便在模板中使用它?我知道我可以将所需的信息作为 python 对象发送
send_daemon_email.delay(first_name='Name',
last_name='Lapr',all_courses = ['title1':'title1',,'title2':'title2',])
但是信息太多了。
任何提示将不胜感激。 谢谢!
【问题讨论】:
你不能传递对象本身,因为它们是不可序列化的,但是你可以传递主键等。 用pk
,我可以在函数内检索对象吗?这是一个很好的观点
【参考方案1】:
Django 对象不能在 celery 任务中发送,您可以通过提供模板中所需的字段,使用 django 序列化程序 (from django.core import serializers
) 序列化,查找将像模板中的 django 对象一样工作
注意:使用序列化程序,您需要转储和加载数据
或者只是将您的查询集转换为如下列表:
send_daemon_email.delay(
instance = User.objects.filter(pk=user.pk).values('first_name','last_name'),
all_courses= list(Course.objects.values('title','other_field'))
)
您只需在模板中提供您真正需要的字段values('')
@shared_task
def send_daemon_email(instance,all_courses):
ctx =
'instance': instance,
'all_courses': all_courses,
message = get_template("emails/ads.html").render(ctx)
在模板中% for course in all_courses %course% endfor %
将显示所有课程, instance.first_name
将显示用户
【讨论】:
这是一个有趣的答案!让我试一试 是的!有效,values()
比查询两次要好,@WillemVanOnsem 的回答很好,更详细。【参考方案2】:
通常像 celery 这样的工具使用 格式 来传递消息。这里使用的是 JSON,并不是每个 Python 对象都可以默认转换为 JSON 对象。
但是,例如,我们可以传递主键,然后在接收方再次将它们转入对象。比如:
send_daemon_email.delay(
instance=instance.pk,
all_courses=list(Course.objects.all().values_list('pk', flat=True))
)
然后在接收器一侧,我们可以通过以下方式获取对象:
@shared_task
def send_daemon_email(instance,all_courses):
ctx =
'instance': User.objects.get(pk=instance),
'all_courses': Course.objects.filter(pk__in=all_courses)
message = get_template("emails/ads.html").render(ctx)
当然,我们本身不需要传递主键:可以使用任何可以被 JSON 序列化(或通过手动序列化)的对象。虽然我不会让它太复杂,但通常简单的事情比更复杂的事情更好(这是 Python 的信条之一)。
【讨论】:
谢谢!我们做了两次查询。序列化数据可能会更好 @EuChi:如果你只需要直接属性,你可以使用model_to_dict
。但是序列化也是有代价的:因为 Python 必须在 JSON 流中转储和恢复数据。以上是关于如何将 django 对象发送到 celery 任务?的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Django-Celery 失败的情况下设置重试任务
Django/Celery 和 CloudAMQP/Heroku 的连接错误
celery beat 没有发送消息(使用 django-celery-beat)