如何将 django 对象发送到 celery 任务?

8 python django celery django-serializer

你好很棒的人!

在我提出问题之前,我尝试了这些 SO 帖子:

它们都不起作用!

我想让用户在网站上更新新课程。查询集为Courses,我想通过电子邮件发送它们。

send_daemon_email.delay(instance=instance,all_courses=Course.objects.all())
Run Code Online (Sandbox Code Playgroud)

我的功能看起来像:

@shared_task
def send_daemon_email(instance,all_courses):
    ctx = {'instance':instance,'all_courses':all_courses}
    message = get_template("emails/ads.html").render(ctx)
    ''' '''
Run Code Online (Sandbox Code Playgroud)

当我尝试将电子邮件发送给特定用户时,我得到的错误是

<User: First Name> is not JSON serializable

只是因为delay()从 celery 得到了一个非序列化的数据。

如何将 Django 对象发送到 celery 任务以便我可以在模板中使用它?我知道我可以将所需的信息作为 python 对象发送

send_daemon_email.delay(first_name='Name',
      last_name='Lapr',all_courses = [{'title1':'title1',},{'title2':'title2',}])
Run Code Online (Sandbox Code Playgroud)

但这将是太多的信息。

任何提示将不胜感激。谢谢!

Wil*_*sem 9

通常像 celery 这样的工具使用一种格式来传递消息。这里使用的是 JSON,并且默认情况下并不是每个 Python 对象都可以转换为 JSON 对象。

然而,我们可以传递主键,然后在接收方再次将它们转换为对象。例如:

send_daemon_email.delay(
    instance=instance.pk,
    all_courses=list(Course.objects.all().values_list('pk', flat=True))
)
Run Code Online (Sandbox Code Playgroud)

然后在接收器一侧,我们可以通过以下方式获取对象:

@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)
Run Code Online (Sandbox Code Playgroud)

当然,我们本身不需要传递主键:可以使用任何类型的可以 JSON 序列化(或通过手动序列化)的对象。虽然我不会让它变得太复杂,但通常简单的事情比更复杂的事情效果更好(这是Python的信条之一)。

  • @EuChi:如果您只需要直接属性,您可以使用“model_to_dict”。但序列化也有成本:因为 Python 必须转储和恢复 JSON 流中的数据。 (3认同)

Lem*_*eur 9

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'))
)
Run Code Online (Sandbox Code Playgroud)

您所需要的只是在模板中提供您真正需要的字段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)
Run Code Online (Sandbox Code Playgroud)

在模板{% for course in all_courses %}{{course}}{% endfor %}中将显示所有课程,以及{{ instance.first_name }}用户