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

Aam*_*amu 6 python django python-imaging-library python-3.x

我正在使用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)
Run Code Online (Sandbox Code Playgroud)

但这会引发错误:

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

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

Håk*_*Lid 11

您可以使用 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) 
Run Code Online (Sandbox Code Playgroud)

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

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


M.j*_*vid 5

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

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)
Run Code Online (Sandbox Code Playgroud)

您可以保存canvasmedia_rootupload_to路径上,或者保存在临时目录或使用BytesIO对象中。