芹菜在将我的QuerySet OBJ作为参数传递时引起错误[英] Celery raise error while passing my queryset obj as parameter

本文是小编为大家收集整理的关于芹菜在将我的QuerySet OBJ作为参数传递时引起错误的处理方法,想解了芹菜在将我的QuerySet OBJ作为参数传递时引起错误的问题怎么解决?芹菜在将我的QuerySet OBJ作为参数传递时引起错误问题的解决办法?那么可以参考本文帮助大家快速定位并解决问题。

问题描述

我试图执行定期任务,因此我将芹菜与Django 1.8一起使用,Django Rest Framework和Postgres作为数据库.当我尝试将OBJ发送到任务时,我会得到TypeError: foreign_model_obj is not JSON serializable.我如何将我的queryset对象传递给我的任务.

views.py:

class MyModelCreateApiView(generics.CreateAPIView):
    queryset = MyModel.objects.all()
    serializer_class= MyModelSerializer
    authentication_classes = (TokenAuthentication,)

    def create(self, request, *args, **kwargs):
        data = dict()
        data['foreign_model_id'] = kwargs['pk']
        foreign_model_obj = MyForeignModel.objects.get(id=data['foreign_model_id'])

        obj = MyModel.objects.create(**data)
        result = serialize_query(MyModel, {"id": obj.id})
        local_time = foreign_model_obj.time
        my_celery_task.apply_async([foreign_model_obj], eta=local_time)
        return Response(result)

tasks.py:

@celery_app.task(name="my_celery_task")
def my_first_celery_task(mymodel_obj):
    # ... updating obj attributes
    mymodel_obj.save()

推荐答案

您只需要发送实例的id并在任务中检索对象. 通过实例是一个不好的做法,因为它可以在同时更改,尤其是您正在用depplay来示意您的任务.

views.py:

class MyModelCreateApiView(generics.CreateAPIView):
    queryset = MyModel.objects.all()
    serializer_class= MyModelSerializer
    authentication_classes = (TokenAuthentication,)

    def create(self, request, *args, **kwargs):
        data = dict()
        data['foreign_model_id'] = kwargs['pk']
        foreign_model_obj = MyForeignModel.objects.get(id=data['foreign_model_id'])

        obj = MyModel.objects.create(**data)
        result = serialize_query(MyModel, {"id": obj.id})
        local_time = foreign_model_obj.time
        my_celery_task.apply_async([foreign_model_obj.id], eta=local_time) # send only the obj id
        return Response(result)

tasks.py:

@celery_app.task(name="my_celery_task")
def my_celery_task(mymodel_obj_id):
    my_model_obj = MyModel.objects.get(id=mymodel_obj_id) # retrieve your object here
    # ... updating obj attributes
    mymodel_obj.save()

其他推荐答案

实际上,恕我直言,最好的方法是获得QuerySet的可挑选组件,然后在任务中重新生成QuerySet( https://docs.djangoproject.com/en/1.9/ref/models/querysets/):

import pickle
query = pickle.loads(s)     # Assuming 's' is the pickled string.
qs = MyModel.objects.filter(a__in=[1,2,3]) # whatever you want here...
querystr = pickle.dumps(qs.query)      # pickle the queryset
my_celery_task.apply_async(querystr, eta=local_time) # send only the string...

任务:

@celery_app.task(name="my_celery_task")
def my_celery_task(querystr):
    my_model_objs = MyModel.objects.all()
    my_model_objs.query = pickle.loads(querystr) # Restore the queryset
    # ... updating obj attributes
    item=my_model_objs[0]

我认为,这是最好的方法,因为查询将在任务中执行(也许是第一次),防止各种定时问题,因此无需在呼叫者中执行(因此在查询上不加倍) .

其他推荐答案

您可以将序列化方法更改为腌制方法,但不建议将QuerySet作为参数传递.芹菜文档的报价:

另一个陷阱是django模型对象.他们不应将其作为论点传递给任务.当任务正在运行时,从数据库中重新提取对象几乎总是更好,因为使用旧数据可能会导致竞赛条件.

tasks.html

本文地址:https://www.itbaoku.cn/post/1764160.html