9👍
If it’s OK for you, there is a Django application ready, doing exactly what you want:
https://github.com/sorl/sorl-thumbnail
4👍
This is what I use in my models to save a new thumbnail if the uploaded image has changed. It’s based of another DjangoSnippet but it I can’t remember who wrote the orginal – if you know please add a comment so that I can credit them.
from PIL import Image
from django.db import models
from django.contrib.auth.models import User
import os
import settings
class Photo_Ex(models.Model):
user = models.ForeignKey(User, blank=True, null=True)
photo = models.ImageField(upload_to='photos')
thumbnail = models.ImageField(upload_to='profile_thumb', blank=True,
null=True, editable=False)
def save(self, *args, **kwargs):
size = (256,256)
if not self.id and not self.photo:
return
try:
old_obj = Photo_Ex.objects.get(pk=self.pk)
old_path = old_obj.photo.path
except:
pass
thumb_update = False
if self.thumbnail:
try:
statinfo1 = os.stat(self.photo.path)
statinfo2 = os.stat(self.thumbnail.path)
if statinfo1 > statinfo2:
thumb_update = True
except:
thumb_update = True
pw = self.photo.width
ph = self.photo.height
nw = size[0]
nh = size[1]
if self.photo and not self.thumbnail or thumb_update:
# only do this if the image needs resizing
if (pw, ph) != (nw, nh):
filename = str(self.photo.path)
image = Image.open(filename)
pr = float(pw) / float(ph)
nr = float(nw) / float(nh)
if image.mode not in ('L', 'RGB'):
image = image.convert('RGB')
if pr > nr:
# photo aspect is wider than destination ratio
tw = int(round(nh * pr))
image = image.resize((tw, nh), Image.ANTIALIAS)
l = int(round(( tw - nw ) / 2.0))
image = image.crop((l, 0, l + nw, nh))
elif pr < nr:
# photo aspect is taller than destination ratio
th = int(round(nw / pr))
image = image.resize((nw, th), Image.ANTIALIAS)
t = int(round(( th - nh ) / 2.0))
image = image.crop((0, t, nw, t + nh))
else:
# photo aspect matches the destination ratio
image = image.resize(size, Image.ANTIALIAS)
image.save(self.get_thumbnail_path())
(a, b) = os.path.split(self.photo.name)
self.thumbnail = a + '/thumbs/' + b
super(Photo_Ex, self).save()
try:
os.remove(old_path)
os.remove(self.get_old_thumbnail_path(old_path))
except:
pass
def get_thumbnail_path(self):
(head, tail) = os.path.split(self.photo.path)
if not os.path.isdir(head + '/thumbs'):
os.mkdir(head + '/thumbs')
return head + '/thumbs/' + tail
def get_old_thumbnail_path(self, old_photo_path):
(head, tail) = os.path.split(old_photo_path)
return head + '/thumbs/' + tail
- How can you dispatch on request method in Django URLpatterns?
- Make Django admin use translated field names
3👍
Not sure about the code you sent, because I never use Models as such, but there is another method.
You can implement your own FileUploadHandler
for handling image file uploads. Example is
here.
Just after line 37 (dest.close()
) use thumbnail(upload_dir + upload.name)
function (the one you sent).
Hope it helps you.
- Django admin dropdown of 1000s of users
- Emptying the database through Django's `manage.py`
- Django test client does not log in
2👍
A key question is: when should the thumbnail be generated?
- Dynamically when the user requests a thumbnail image?
- Or do you want to create a physical disk file whenever a country is INSERTed/UPDATEd in the database.
If (1) I suggest you create a view that maps to url /flagthumbnail/countryid
. The view method would then have to:
- Get the country instance from the database
- Read the flag image into a PIL Image and resize that.
- Create (and return) a HTTPResponse with correct content-type and write the PIL Image to the response.
Whenever you need to display a thumbnail flag, just use <a href="/flagthumbnail/countryid">
.
If (2), you could connect to Django’s django.db.models.signals.post_save
signal and in the signal handler create and save a thumbnail file.
2👍
I guess it depends on how and when your using your thumbnails.
If you want to create some thumbnails every time the Country is saved, you could do it like so:
from django.db import models
# This is to list all the countries
# For starters though, this will be just United Kingdom (GB)
class Country(models.Model):
name = models.CharField(max_length=120, help_text="Full name of country")
code = models.CharField(max_length=2, help_text="This is the ISO 3166 2-letter country code (see: http://www.theodora.com/country_digraphs.html)")
flag = models.ImageField(upload_to="images/uploaded/country/", max_length=150, help_text="The flag image of the country.", blank=True)
class Meta:
verbose_name_plural = "Countries"
def __unicode__(self):
return self.name
def save(self, force_insert=False, force_update=False):
resize_image(self.flag)
super(Country, self).save(force_insert, force_update)
If you aren’t 100% sure what sizes you’ll need your images, you could resize them last minute. I’ve seen this effectively done with a templatetag (I believe in a version on Pinax). You create a templatetag that takes the image and a size, then create and save the image of the appropriate size if you need to, or display a previously created one if it’s there. It works pretty well.
- When to use the Custom User Model in Django 1.5
- Upgrading to Django 1.7. Getting error: Cannot serialize: <storages.backends.s3boto.S3BotoStorage object
- Using a Django variable in a CSS file
- Django South Error: "there is no enabled application matching 'myapp'"
2👍
Overriding the save method is a good option, but I’d be more tempted to use a signal in this case. Django signals allow you to “listen” to a given model type’s various events; in this case, you’d be interested in the post_save
event.
I usually subscribe to such signals in my models.py
file. Code for you would look something like this:
from django.db.models.signals import post_save
from models import Country
def resize_image(sender, **kwargs):
country = kwargs["instance"]
resize_image(country.flag) # where resize_image generates a thumbnail given a Country instance
post_save.connect(resize_image, sender=Country)
2👍
You can give a try to:
features:
- Allows you to set the center of attention of an image… heads won’t get cut anymore.
- Video thumbnailing
- Prevents cross-site image linking
- Simple setup and usage
- Filter a django QuerySet with the query from another QuerySet: Possible?
- Mysql_exceptions.OperationalError: (1045, "Access denied for user 'root'@'localhost' (using password: YES)")
- Python and sqlite3 – importing and exporting databases
1👍
Ryan is correct signals are a better way to go however the advantage of the overriden save is that we can get the old and new image paths, see if the image has changed (and if it has create a new thumbnail), save the model instance and then delete the old image and thumbnail.
Remember django does not clean up the old images for you so unless you have script to check that the images/thumbnails are still in use and clean out any that are not you will leak disk space. (This may or may-not be a problem for you depending on image size and frequency of updates)
I’m not sure how you could do this with a post_save signal, and I don’t know enough about signals (That’s research for tonight!) to know if there is a suitable pre_save signal. If i find one then I’ll re-write the code above to use signals as a generic pre save listner.
- HttpResponse vs. Render
- Django Rest Framework debug post and put requests
- Django Multiple File Upload
- Best way to make Django's "user" system have "friends"
1👍
Another alternative is to use Imagemagick directly, if you want to avoid several difficulties with Pillow and Python 3 such as this one.
from subprocess import call
call(['convert', img_path_file_name, '-thumbnail', target_size_str, '-antialias', style_path_file_name])
You could call this on model save, or on a template tag to generate an one-off manipulated copy of the original file in a file-caching fashion, or even a celery task.
You can get an example of how I have used this in one of my projects:
- How to display a list of objects containing many-to-many relations in Django template?
- What is the best CouchDB backend for Django?
- Find_element_by_class_name for multiple classes
- Get list of occurrences + count in a model Django?
- GeoDjango: How to create a circle based on point and radius
0👍
I also swear by Justin Driscoll’s django-photologue is also great for resizing. It:
- Resizes (that is can be scaled to a height or width proportionately)
- Crops (kind-of intelligently: from the center, top, left, bottom or right)
- Optionally upsizes
- Can add effects (such as “color”, “brightness”, “contrast” and “sharpness” as well as filters like “Find Edges” and “Emboss”. Sharpen your images. Make your thumbnails black and white.)
- Can add simple watermark
- Cache the results
Basically it’s awesome.
- Django template engine indentation
- Django admin, section without "model"?
- Django: test failing on a view with @login_required
- Change default Django REST Framework home page title
- How disable return of HTML error page with django rest framework?
0👍
A very easy way is to resize and/or crop your image on display with django-imagefit.
It will preserve the original image so you can have multiple versions, refactor your frontend later and it also works with non-model images.
-1👍
you can change photo size after save data in database models using ‘Pillow’ , for example i am going
to change the user profile image to 300 x 300 , just i will define save() method inside model and change the size , just following the steps below:
1- first make sure ‘Pillow’ is installed .
2- here is my code in profile model class :
from PIL import Image
class Profile(models.Model):
PRF_image = models.ImageField(upload_to='profile_img', blank=True, null=True)
def save(self , *args , **kwargs):
# change profile image size
img = Image.open(self.PRF_image.path)
if img.width > 300 or img.height > 300:
output_size = (300, 300)
img.thumbnail(output_size)
img.save(self.PRF_image.path)
this is just example , and change it beasd on you case/requirements.
and don’t forget to use your_object.save() inside your view to use this method.
i hope this helpful