在 Django 1.11 中将 QuerySet 传递给 Celery 任务

Posted

技术标签:

【中文标题】在 Django 1.11 中将 QuerySet 传递给 Celery 任务【英文标题】:Pass QuerySet to Celery Task in Django 1.11 【发布时间】:2018-10-01 12:47:00 【问题描述】:

我想将一些长查询移至 Celery 中的异步任务,然后使用 AJAX 检索该额外信息。现在我得到这样的 QuerySet:

brands = Brand.objects.filter(shops__shop_name__in=[shop])

任务:

@task()
def brand_count(querystr):
    querystr.annotate(amount_of_products=Count('products'))

我想做here:

task_run = brand_count.delay(brands)

问题是:如何将 QuerySet 传递给 Celery 任务? 现在它会抛出一个无法完成的错误。 我有found pickle 可能在这里使用,但我无法找到正确的使用方法。特别是-query = pickle.loads(s) 中的# Assuming 's' is the pickled string. 是什么意思。

【问题讨论】:

【参考方案1】:

正如您所发现的,您不能将查询集直接传递给任务,因为任务参数必须是可序列化的。酸洗也不是一个好的理想选择,因为您实际上不需要序列化整个查询集。

您应该将对象 ID 列表传递给任务,然后从任务本身获取查询集。

brand_ids = Brand.objects.filter(shops__shop_name__in=[shop]).values_list('id', flat=True)
task_run = brand_count.delay(list(brand_ids))

values_list 将为您提供品牌 ID 列表。

然后,在您的任务中,您重新创建查询集并使用它做您需要的事情:

@task()
def brand_count(brand_ids):
    queryset = Brand.objects.filter(id__in=brand_ids)
    queryset.annotate(amount_of_products=Count('products'))

【讨论】:

是的,我还有一个想法,就是将 id-s 传递给任务。但你的认识很棒。

以上是关于在 Django 1.11 中将 QuerySet 传递给 Celery 任务的主要内容,如果未能解决你的问题,请参考以下文章

如何在django中将QuerySet过滤到每个组的最大成员?

Django - 如何将 QuerySet 转换为 Q 对象?

Django SUM 查询?

如何在 django 中将虚拟数据添加到数据表中?

如何在每个中将 itemController 设置为(ember 1.11 beta3)?

django 信号 目录 1.11