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 то нет никаких ошибок вообще...
  • Вопрос задан
  • 1254 просмотра
Решения вопроса 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. Явно откатывать транзакция не нужно, контекстный менеджер делает это за вас.
Ответ написан
Пригласить эксперта
Ваш ответ на вопрос

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

Войти через центр авторизации
Похожие вопросы