The Python Oracle

Save a generated PIL image into an ImageField in django

Become part of the top 3% of the developers by applying to Toptal https://topt.al/25cXVn

--

Track title: CC I Beethoven Sonata No 31 in A Flat M

--

Chapters
00:00 Question
01:12 Accepted answer (Score 13)
02:06 Answer 2 (Score 5)
02:59 Thank you

--

Full question
https://stackoverflow.com/questions/4906...

Question links:
[qrcode]: https://github.com/lincolnloop/python-qr...

Accepted answer links:
https://docs.djangoproject.com/en/2.0/re...

Answer 2 links:
[File]: https://docs.djangoproject.com/en/dev/re...

--

Content licensed under CC BY-SA
https://meta.stackexchange.com/help/lice...

--

Tags
#python #django #python3x #pythonimaginglibrary

#avk47



ACCEPTED ANSWER

Score 13


You can use a BytesIO to save the Pillow file to an in-memory blob. Then create a File object and pass that to your model instance ImageField's save method.

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) 

Check out the django documentation for the File object. https://docs.djangoproject.com/en/stable/ref/files/file/#the-file-object

You have to use save=False, since the default save=True means that the parent model's save method would be called after the image is saved. You don't want recursion here, since you would typically end up in an infinite loop.




ANSWER 2

Score 5


Change your code and use Django File as below:

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)

You can save canvas on the media_root and upload_to path, or in temporary directory or use BytesIO object.