I am using qrcode to generate qrcode. When a ticket is bought, or when bought is true, I would like to generate a qrcode image and make some changes using PIL. Finally save the modified canvas into the Image field of the model.
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)
But this throws an error:
AttributeError: 'Image' object has no attribute '_committed'
How can I save a generated PIL image into an ImageField in django?
How you specify the location of an image in Django is in between {% %}. In between these brackets, you specify static 'images\\Python. png', where Python is the image you want to display which is inside of the images directory in the static directory you create for the current app you are in.
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/2.0/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.
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With