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

3

我希望将一些长查询移动到Celery的异步任务中,并使用AJAX检索额外信息。现在我得到的QuerySet像这样:

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

任务:

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

我希望做类似于这里的事情:
task_run = brand_count.delay(brands)

问题是:如何将 QuerySet 传递给 Celery 任务?现在会出现无法完成此操作的错误。

我已经找到了一个可能使用 pickle解决方案,但是我无法找到正确的使用方法。特别是在query = pickle.loads(s)中,# 假设 's' 是腌制的字符串。是什么意思。
1个回答

7

正如你发现的那样,你不能直接将查询集传递给任务,因为任务参数必须可序列化。使用pickle也不是一个好主意,因为你实际上不需要序列化整个查询集。

相反,你应该将对象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到任务。但是你的实现非常出色。 - Chiefir

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