将生成的PIL图像保存到django中的ImageField中

时间:2018-03-02 07:44:51

标签: python django python-3.x python-imaging-library

我正在使用qrcode生成qrcode。购买机票或购买机票时,我想生成qrcode图像并使用PIL进行一些更改。最后将修改后的画布保存到模型的Image字段中。

class Ticket(models.Model):
    booked_at = models.DateTimeField(default=timezone.now)
    qrcode_file = models.ImageField(upload_to='qrcode', blank=True, null=True)
    bought = models.BooleanField(default=False)

    def save(self, *args, **kwargs):
        if self.bought:
            ...
            ...
            qrcode_img = qrcode.make('some data')
            canvas = Image.new('RGB', (total_width, total_height), 'white')
            draw = ImageDraw.Draw(canvas)
            position = (left, top)
            canvas.paste(qrcode_img, position)

            self.qrcode_file = canvas
            self.booked_at = timezone.now()
            super(Ticket, self).save(*args, **kwargs)
            canvas.close()
            qrcode_img.close()
        else:
            self.booked_at = timezone.now()
            super(Ticket, self).save(*args, **kwargs)

但这会引发错误:

  

AttributeError:'Image'对象没有'_committed'属性

如何将生成的PIL图像保存到django中的ImageField?

2 个答案:

答案 0 :(得分:3)

您可以使用BytesIO将Pillow文件保存到内存中的Blob。然后创建一个File对象并将其传递给模型实例ImageField的save方法。

from io import BytesIO
from django.core.files import File

canvas = Image.new('RGB', (total_width, total_height), 'white')
...
blob = BytesIO()
canvas.save(blob, 'JPEG')  
self.qrcode_file.save('ticket-filename.jpg', File(blob), save=False) 

查看File对象的django文档。 https://docs.djangoproject.com/en/2.0/ref/files/file/#the-file-object

您必须使用save=False,因为默认save=True表示在保存图像后将调用父模型的save方法。你不想在这里进行递归,因为你通常会陷入无限循环。

答案 1 :(得分:2)

更改您的代码并使用Django File,如下所示:

ancestor 1
opening hksh1
pasting ancestor 1 to hksh1
opening mysh1
pasting ancestor 1 to mysh1

ancestor 2
opening hksh2
pasting ancestor 2 to hksh2
opening mysh2
pasting ancestor 2 to mysh2

您可以将from django.core.files import File class Ticket(models.Model): booked_at = models.DateTimeField(default=timezone.now) qrcode_file = models.ImageField(upload_to='qrcode', blank=True, null=True) bought = models.BooleanField(default=False) def save(self, *args, **kwargs): if self.bought: ... ... qrcode_img = qrcode.make('some data') canvas = Image.new('RGB', (total_width, total_height), 'white') draw = ImageDraw.Draw(canvas) position = (left, top) canvas.paste(qrcode_img, position) canvas.save('path/of/dest.png', 'PNG') destination_file = open('path/of/dest.png', 'rb') self.qrcode_file.save('dest.png', File(destination_file), save=False) destination_file.close() self.booked_at = timezone.now() super(Ticket, self).save(*args, **kwargs) canvas.close() qrcode_img.close() else: self.booked_at = timezone.now() super(Ticket, self).save(*args, **kwargs) 保存在canvasmedia_root路径上,也可以保存在临时目录中或使用upload_to对象。