lightarhont
@lightarhont
python/php developer

Асинхронная функция вызывает ошибку 'is not JSON serializable'?

Есть view.py
from rest_framework.response import Response
from rest_framework.views import APIView
from .models import *
from .tasks import trasactiontaskfunc
#from .trasactionfunc import trasactionfunc

# Create your views here.
class PageView(APIView):
    def get(self, request, item):
        page = Page.objects.filter(pk=item).first()
        
        totrasaction = []
        
        la = []
        for e in page.pageaudio_set.all():
            el = {
                  'type': 'audio',
                  'id': e.audio.pk,
                  'title': e.audio.title,
                  'counter': e.audio.counter,
                  'bitrate': e.audio.bitrate,
                  }
            totrasaction.append(e.audio)
            la.append({'order': e.order, 'quantity': e.quantity, 'el': el})
        lv = []
        for e in page.pagevideo_set.all():
            el = {
                  'type': 'video',
                  'id': e.video.pk,
                  'title': e.video.title,
                  'counter': e.video.counter,
                  'fileurl': e.video.fileurl,
                  'subtitresurl': e.video.subtitresurl
                  }
            totrasaction.append(e.video)
            lv.append({'order': e.order, 'quantity': e.quantity, 'el': el})
        lt = []
        for e in page.pagetext_set.all():
            el = {
                  'type': 'text',
                  'id': e.text.pk,
                  'title': e.text.title,
                  'counter': e.text.counter,
                  'text': e.text.text,
                  }
            totrasaction.append(e.text)
            lt.append({'order': e.order, 'quantity': e.quantity, 'el': el})
        
        content = {
            "id": item,
            "title": page.title,
            "pageaudio": la,
            "pagevideo": lv,
            "pagetext": lt,
                   }
        
        trasactiontaskfunc.delay(totrasaction)
        #trasactionfunc(totrasaction)
        
        return Response({'t':1})


Есть таски:
from celery import shared_task
from api.trasactionfunc import trasactionfunc

@shared_task(time_limit=20000)
def trasactiontaskfunc(totrasaction):
    return trasactionfunc(totrasaction)


Транзакция:
from django.db import transaction

def trasactionfunc(totrasaction):
    try:
        with transaction.atomic():
            for e in totrasaction:
                e.counter = e.counter + 1
                e.save()
    except:
        transaction.rollback()
    else:
        return True
    return False


Почему получаю ответ :

EncodeError at /api/page/1

is not JSON serializable

Если функция асинхронная и нету return вообще? Если делаю напрямую, без celery то нет никаких ошибок вообще...
  • Вопрос задан
  • 1420 просмотров
Решения вопроса 1
sergey-gornostaev
@sergey-gornostaev Куратор тега Celery
Седой и строгий
Категорически не понимаю, зачем вы наращиваете счётчики в цикле, тем более в асинхронной задаче. Правильно это делается так:
page.pageaudio_set.all().update(counter=F('counter ') + 1)

Но если уж очень хочется зачем-то сделать это в асинхронной задаче, то лучше так:
trasactiontaskfunc.delay({
    'audio': list(page.pageaudio_set.values_list('id', flat=True)),
    'video': list(page.pagevideo_set.values_list('id', flat=True)),
    'text': list(page.pagetext_set.values_list('id', flat=True)),
})

def trasactionfunc(totrasaction):
    try:
        with transaction.atomic():
            Audio.objects.filter(id__in=totrasaction['audio']).update(counter=F('counter ') + 1)
            Video.objects.filter(id__in=totrasaction['video']).update(counter=F('counter ') + 1)
            Text.objects.filter(id__in=totrasaction['text']).update(counter=F('counter ') + 1)
    except:
        transaction.rollback()
    else:
        return True
    return False

А ещё лучше сделать Content не абстрактным и передавать идентификаторы простым списком.

P.S. Явно откатывать транзакция не нужно, контекстный менеджер делает это за вас.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы