我从外部库给我一个QuerySet,并且 - 由于QuerySets是懒惰的 - 我想在访问它之前将其序列化至JSON ,因此在DB中执行,因此可以在异步芹菜任务中执行。
我的问题是,是否有一种将QuerySet的基本要素表示为JSON的方法,所以我不必使用泡菜?
我知道我可以使用queryset.query
获取原始查询,但是由于我必须在另一端执行原始查询,所以我不太喜欢这个想法。
详细信息
此处的特定用例正在评估任务中的QuerySet,因此可以将结果导出到文件并倒在服务器上以供以后访问。
结果集可能很大,因此作为标准请求/响应周期的一部分进行导出通常可以超时。
该请求是从Django管理员更改视图列表过滤器生成的。我已经尝试返回列表过滤器代码,但似乎它只是生成过滤对象 - 不适合JSON序列化。
我可以查看列表过滤器查询字符串并将所有键重新评估到QuerySet滤波器中,但是许多过滤器是SimpleListFilter
类,也只需返回过滤器对象,并且不会在该滤波器中显示真正的QuerySet滤波器URL。我需要为这些过滤器重新创建逻辑,以获取可以序列化的夸尔格风格的过滤器。
django 1.11&芹菜3.0
可悲的是,这不再起作用。如果有人有任何有关如何正确序列化QuerySet或其各种过滤器和属性的信息,请让我知道。
原始答案
事实证明,my_queryset.query
是在执行前序列化QuerySet的正确且安全的方法。
如果您只想腌制必要的信息即以后从数据库中重新创建QuerySet,则泡菜QuerySet 的查询属性。然后,您可以使用这样的代码重新创建原始QuerySet(没有加载任何结果(:
import pickle
query = pickle.loads(s) # Assuming 's' is the pickled string.
qs = MyModel.objects.all()
qs.query = query # Restore the original 'query'.
查询属性是一个不透明的对象。它代表了查询构造的内部,而不是公共API的一部分。但是,如下所述,泡菜并取消属性的内容是安全的(并得到了完全支持(。。
https://docs.djangoproject.com/en/1.11/ref/models/querysets/#pickling-querysets
这是关于使用Pickle的,但它当然也可以与JSON Serialials一起使用。
# admin.py
...
export_data.delay(queryset.query)
...
# tasks.py
@task(serializer='json')
def export_data(query):
qs = MyModel.objects.all()
qs.query = query
...
在写作时,使用Python 3.7 和Django 2.2 pickle
转储/负载似乎有效。最后仅缺少queryset.update()
。
我尝试了类似的东西:
# packing
queryset = MyModel.objects.filter(...)
serialized_queryset = pickle.dumps(queryset.query)
# unpacking
restored = MyModel.objects.all()
restored.query = pickle.loads(serialized_queryset)
restored.update()
它可以正常工作。尚未跨芹菜任务进行测试,但我希望它应该起作用。
您不必序列化QuerySet
即可在芹菜任务中访问它。您可以使用Django模型并在任务本身中创建QuerySet
。如果创建QuerySet
的特定方式,则可以将QuerySet
创建代码放在公共功能或类中,并在Web应用程序代码和芹菜任务中导入此共享代码。
没有理由避免在芹菜任务中使用django orm。
您需要decode
和encode
查询。使用 django 2.1 和芹菜4.2 与此代码一起使用:
query_dump = pickle.dumps(queryset.query).decode('latin1')
query = pickle.loads(query_dump.encode('latin1'))