29👍
Based on xjtian’s answer. This works for Python 3:
import os.path
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
from .my_app_settings import THUMB_SIZE
class Photo(models.Model):
photo = models.ImageField(upload_to='photos')
thumbnail = models.ImageField(upload_to='thumbs', editable=False)
def save(self, *args, **kwargs):
if not self.make_thumbnail():
# set to a default thumbnail
raise Exception('Could not create thumbnail - is the file type valid?')
super(Photo, self).save(*args, **kwargs)
def make_thumbnail(self):
image = Image.open(self.photo)
image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
thumb_name, thumb_extension = os.path.splitext(self.photo.name)
thumb_extension = thumb_extension.lower()
thumb_filename = thumb_name + '_thumb' + thumb_extension
if thumb_extension in ['.jpg', '.jpeg']:
FTYPE = 'JPEG'
elif thumb_extension == '.gif':
FTYPE = 'GIF'
elif thumb_extension == '.png':
FTYPE = 'PNG'
else:
return False # Unrecognized file type
# Save thumbnail to in-memory file as StringIO
temp_thumb = BytesIO()
image.save(temp_thumb, FTYPE)
temp_thumb.seek(0)
# set save=False, otherwise it will run in an infinite loop
self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=False)
temp_thumb.close()
return True
17👍
To do this, you should add a new ImageField
to your current UserImages
model to hold the thumbnail, then override your the save
method to create and save the thumbnail after the full image is saved.
I’ve adapted the following snippet of code from one of my projects that did exactly this, I’m pretty sure this will do exactly what you need it to do:
from cStringIO import StringIO
import os
from django.db import models
from django.core.files.base import ContentFile
from django.core.files.storage import default_storage as storage
from PIL import Image
# Thumbnail size tuple defined in an app-specific settings module - e.g. (400, 400)
from app.settings import THUMB_SIZE
class Photo(models.Model):
"""
Photo model with automatically generated thumbnail.
"""
photo = models.ImageField(upload_to='photos')
thumbnail = models.ImageField(upload_to='thumbs', editable=False)
def save(self, *args, **kwargs):
"""
Make and save the thumbnail for the photo here.
"""
super(Photo, self).save(*args, **kwargs)
if not self.make_thumbnail():
raise Exception('Could not create thumbnail - is the file type valid?')
def make_thumbnail(self):
"""
Create and save the thumbnail for the photo (simple resize with PIL).
"""
fh = storage.open(self.photo.name, 'r')
try:
image = Image.open(fh)
except:
return False
image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
fh.close()
# Path to save to, name, and extension
thumb_name, thumb_extension = os.path.splitext(self.photo.name)
thumb_extension = thumb_extension.lower()
thumb_filename = thumb_name + '_thumb' + thumb_extension
if thumb_extension in ['.jpg', '.jpeg']:
FTYPE = 'JPEG'
elif thumb_extension == '.gif':
FTYPE = 'GIF'
elif thumb_extension == '.png':
FTYPE = 'PNG'
else:
return False # Unrecognized file type
# Save thumbnail to in-memory file as StringIO
temp_thumb = StringIO()
image.save(temp_thumb, FTYPE)
temp_thumb.seek(0)
# Load a ContentFile into the thumbnail field so it gets saved
self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=True)
temp_thumb.close()
return True
- [Django]-Django UniqueConstraint
- [Django]-Django save image from url and connect with ImageField
- [Django]-How do I write Facebook apps using Django?
2👍
I wrote it based by ziiiro’s answer.
It works fine with Django2.2.1.
Need process for save for path of image field.
models.py
from django.db import models
from my.images import make_thumbnail
class Image(models.Model):
image = models.ImageField(upload_to='')
thumbnail = models.ImageField(upload_to='', editable=False)
icon = models.ImageField(upload_to='', editable=False)
def save(self, *args, **kwargs):
# save for image
super(Image, self).save(*args, **kwargs)
make_thumbnail(self.thumbnail, self.image, (200, 200), 'thumb')
make_thumbnail(self.icon, self.image, (100, 100), 'icon')
# save for thumbnail and icon
super(Image, self).save(*args, **kwargs)
my.images.py
from django.core.files.base import ContentFile
import os.path
from PIL import Image
from io import BytesIO
def make_thumbnail(dst_image_field, src_image_field, size, name_suffix, sep='_'):
"""
make thumbnail image and field from source image field
@example
thumbnail(self.thumbnail, self.image, (200, 200), 'thumb')
"""
# create thumbnail image
image = Image.open(src_image_field)
image.thumbnail(size, Image.ANTIALIAS)
# build file name for dst
dst_path, dst_ext = os.path.splitext(src_image_field.name)
dst_ext = dst_ext.lower()
dst_fname = dst_path + sep + name_suffix + dst_ext
# check extension
if dst_ext in ['.jpg', '.jpeg']:
filetype = 'JPEG'
elif dst_ext == '.gif':
filetype = 'GIF'
elif dst_ext == '.png':
filetype = 'PNG'
else:
raise RuntimeError('unrecognized file type of "%s"' % dst_ext)
# Save thumbnail to in-memory file as StringIO
dst_bytes = BytesIO()
image.save(dst_bytes, filetype)
dst_bytes.seek(0)
# set save=False, otherwise it will run in an infinite loop
dst_image_field.save(dst_fname, ContentFile(dst_bytes.read()), save=False)
dst_bytes.close()
- [Django]-How do I force Django to ignore any caches and reload data?
- [Django]-Test sending email without email server
- [Django]-Django QuerySet order
2👍
The other solution is correct, but fails when implemented as a profile picture. Its safe to assume a profile is going to be more than just a picture and a thumbnail. If any other field is updated and the profile picture is not, you can run into a few different issues. To avoid this you must implement a comparison of the original file name and the file name returned when updated. If the profile picture is not updated you don’t want to save a thumbnail. Set a class string to None and compare it before running make_thumbnail.
import os.path
from PIL import Image
from io import BytesIO
from django.core.files.base import ContentFile
from .my_app_settings import THUMB_SIZE
class Photo(models.Model):
photo = models.ImageField(upload_to='photos')
thumbnail = models.ImageField(upload_to='thumbs', editable=False)
# Class string added to store original name of photo
original_photo_name = None
# When the form is initialized save the original photo name
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.original_photo_name = self.photo.name
def save(self, *args, **kwargs):
# This checks if the photo was updated or not before saving a thumbnail
if self.original_photo_name != self.photo.name:
if not self.make_thumbnail():
# set to a default thumbnail
raise Exception('Could not create thumbnail - is the file type valid?')
super(Photo, self).save(*args, **kwargs)
def make_thumbnail(self):
image = Image.open(self.photo)
image.thumbnail(THUMB_SIZE, Image.ANTIALIAS)
thumb_name, thumb_extension = os.path.splitext(self.photo.name)
thumb_extension = thumb_extension.lower()
thumb_filename = thumb_name + '_thumb' + thumb_extension
if thumb_extension in ['.jpg', '.jpeg']:
FTYPE = 'JPEG'
elif thumb_extension == '.gif':
FTYPE = 'GIF'
elif thumb_extension == '.png':
FTYPE = 'PNG'
else:
return False # Unrecognized file type
# Save thumbnail to in-memory file as StringIO
temp_thumb = BytesIO()
image.save(temp_thumb, FTYPE)
temp_thumb.seek(0)
# set save=False, otherwise it will run in an infinite loop
self.thumbnail.save(thumb_filename, ContentFile(temp_thumb.read()), save=False)
temp_thumb.close()
return True
- [Django]-Using django-rest-interface
- [Django]-Is it secure to store passwords as environment variables (rather than as plain text) in config files?
- [Django]-How do I run Django and PHP together on one Apache server?
0👍
If you don’t want to implement a solution from scratch I suggest you to use a django app called sorl-thumbnail
- [Django]-How to monkey patch Django?
- [Django]-Django REST Framework serializer field required=false
- [Django]-Django/Python assertRaises with message check
0👍
Probably you have forgotten save a file:
im.save(file + ".thumbnail", "JPEG")
- [Django]-How to handle per object permission in Django nowadays?
- [Django]-How can you create a non-empty CharField in Django?
- [Django]-Django can't find new sqlite version? (SQLite 3.8.3 or later is required (found 3.7.17))
0👍
there is super easier way,
in model:
def upload_thumb_dir(self, filename):
path = f'path_to_thumb.jpg'
return path
thumb = ProcessedImageField(upload_to=upload_thumb_dir,
processors=[ResizeToFill(192, 108)],
max_length= 255,
format='JPEG',
default='preview.jpg',
options={'quality': 80},
null=True, blank=True
)
# ...
def save(self, *args, **kwargs):
self.thumb = self.rawfile.file
super(VersionPreviews, self).save(*args, **kwargs)
- [Django]-Internationalisation Django (on OSX)
- [Django]-Django: Search form in Class Based ListView
- [Django]-Custom validation in Django admin