首页 > 解决方案 > ImageForm 类型的对象不是 JSON 可序列化的

问题描述

我想将图像处理从视图发布到 celery,但它向我显示了一个与 JSON 相关的问题 “ImageForm 类型的对象不是 JSON 可序列化的”

这是来自models.py的代码

class ImageModel(models.Model):
    title = models.CharField(max_length=20, null=True)
    sec_title = models.CharField(max_length=20, null=True)
    img = models.ImageField(upload_to='upload_p/', blank=False)
    slug = models.SlugField(max_length=250, null=True)

    def delete(self, *args, **kwargs):
        self.img.delete()
        super().delete(*args, **kwargs)

表格.py

class ImageForm(forms.ModelForm):
    class Meta:
        model = ImageModel
        fields = ('title', 'img', 'sec_title')

视图.py

def upload_image(request):
    if request.method == 'POST':
        form_w = ImageForm(request.POST, request.FILES)
        if form_w.is_valid():
            water_mark.delay(form_w)
    else:
        form = ImageForm()
    return render(request, 'Luki/upload_img.html', {
        'form': form,
    })

任务.py

@shared_task
def water_mark(form_w):
    instance = form_w.save(commit=False)
    cd = form_w.cleaned_data['img']

    if instance.img:
        im = Image.open(instance.img)

        width, height = im.size
        draw = ImageDraw.Draw(im)
        text = "TEST WATERMARK"

        font = ImageFont.truetype('arial.ttf', 36)
        textwidth, textheight = draw.textsize(text, font)

        # calculate the x,y coordinates of the text
        margin = 10
        x = width - textwidth - margin
        y = height - textheight - margin

        draw.text((x, y), text, font=font)


        thumb_io = BytesIO()
        print('BYTES IO: ', thumb_io)
        im.save(thumb_io, im.format, quality=100)
        instance.img.save(str(cd), ContentFile(thumb_io.getvalue()), save=False)

    instance.save()

    return redirect('Luki:gallery')

当然,所有的库都被导入,没有 celera 的视图中的代码被执行,看起来像这样。这样可以使您在表单中添加的照片获得水印,将其保存并带您到画廊。

视图.py

def upload_image(request):
    if request.method == 'POST':
        form_w = ImageForm(request.POST, request.FILES)
        if form_w.is_valid():
            instance = form_w.save(commit=False)
            cd = form_w.cleaned_data['img']

            if instance.img:
                im = Image.open(instance.img)

                width, height = im.size
                draw = ImageDraw.Draw(im)
                text = "TEST WATERMARK"

                font = ImageFont.truetype('arial.ttf', 36)
                textwidth, textheight = draw.textsize(text, font)

                # calculate the x,y coordinates of the text
                margin = 10
                x = width - textwidth - margin
                y = height - textheight - margin

                # draw watermark in the bottom right corner
                draw.text((x, y), text, font=font)

                thumb_io = BytesIO()
                im.save(thumb_io, im.format, quality=100)
                instance.img.save(str(cd), ContentFile(thumb_io.getvalue()), save=False)

            instance.save()


            return redirect('Luki:gallery')
    else:
        form_w = ImageForm()
    return render(request, 'Luki/upload_img.html', {
        'form_w': form_w,
    })

标签: djangodjango-modelsdjango-viewsdjango-forms

解决方案


根据此博客,您不能在 celery 中传递对象。

由于 Celery 是一个分布式系统,你无法知道任务将在哪个进程中运行,甚至在哪台机器上运行。因此,您不应该将 Django 模型对象作为参数传递给任务,从数据库中重新获取对象几乎总是更好,因为可能涉及竞争条件。

因此,在您的情况下,将图像保存在模型中的视图本身并将模型的 pk 传递给 celery 任务,然后再次从模型中获取这些详细信息。


推荐阅读