django - 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,
})
解决方案
根据此博客,您不能在 celery 中传递对象。
由于 Celery 是一个分布式系统,你无法知道任务将在哪个进程中运行,甚至在哪台机器上运行。因此,您不应该将 Django 模型对象作为参数传递给任务,从数据库中重新获取对象几乎总是更好,因为可能涉及竞争条件。
因此,在您的情况下,将图像保存在模型中的视图本身并将模型的 pk 传递给 celery 任务,然后再次从模型中获取这些详细信息。