48👍
First, it’s best to establish the correct language. Django and Python exist only on the server side. Therefore, anything they manipulate, save, or otherwise use, has to be first sent to the server. If Django or Python is to manage the photo, the user MUST upload this photo to the server first. Once the photo is uploaded, Django is free to make changes before storing the file.
If your concern is with upload bandwidth, and you don’t want large files being uploaded, you will have to resize and reformat the photo on the client side. If this is a web application, this can be done using Javascript, but can not be done with Python, since Python does not operate on the client side for an application like yours.
If your concern is not with bandwidth, then you’re free to have the user "upload" the file, but then have Django resize and reformat it before saving.
You are correct that you will want to override your save function for the photo object. I would recommend using a library to handle the resizing and reformatting, such as sorl.
from sorl.thumbnail import ImageField, get_thumbnail
class MyPhoto(models.Model):
image = ImageField()
def save(self, *args, **kwargs):
if self.image:
self.image = get_thumbnail(self.image, '500x600', quality=99, format='JPEG')
super(MyPhoto, self).save(*args, **kwargs)
Sorl is just a library I am confident and familiar with, but it takes some tuning and configuration. You can check out Pillow or something instead, and just replace the line overriding self.image
.
I also found a similar question here.
Edit: saw the update to your comment response above. Also note that if your webserver is handling Django, and your files are being saved to some CDN, this method will work. The image will be resized on the webserver before being uploaded to your CDN (assuming your configuration is as I’m assuming).
Hope this helps!
19👍
from django.db import models
from django.contrib.auth.models import User
from PIL import Image
class profile(models.Model):
user = models.OneToOneField(User, on_delete=models.CASCADE)
bio = models.CharField(max_length=300)
location = models.CharField(max_length=99)
image = models.ImageField(default='default.jpg', upload_to='profile_pics')
def save(self):
super().save() # saving image first
img = Image.open(self.image.path) # Open image using self
if img.height > 300 or img.width > 300:
new_img = (300, 300)
img.thumbnail(new_img)
img.save(self.image.path) # saving image at the same path
This example shows how to upload image after image re-sizing.
Change the pixel of new_img, whatever you want.
- [Django]-Django 1.4 Many-to-Many bulk add
- [Django]-Python Django Global Variables
- [Django]-Set up a scheduled job?
11👍
Here is one more package that works for me with minimal code modification – django-resized.
models.py
from django_resized import ResizedImageField
class Post(models.Model):
image = ResizedImageField(upload_to='uploads/%Y/%m/%d')
settings.py
DJANGORESIZED_DEFAULT_SIZE = [1024, 768]
DJANGORESIZED_DEFAULT_QUALITY = 75
DJANGORESIZED_DEFAULT_KEEP_META = True
DJANGORESIZED_DEFAULT_FORCE_FORMAT = 'JPEG'
DJANGORESIZED_DEFAULT_FORMAT_EXTENSIONS = {'JPEG': ".jpg"}
DJANGORESIZED_DEFAULT_NORMALIZE_ROTATION = True
That’s it!
- [Django]-Change a Django form field to a hidden field
- [Django]-Show a ManyToManyField as Checkboxes in Django Admin
- [Django]-Linking to the django admin site
9👍
Here is an app that can take care of that: django-smartfields. It will also remove an old image whenever a new one is uploaded.
from django.db import models
from smartfields import fields
from smartfields.dependencies import FileDependency
from smartfields.processors import ImageProcessor
class ImageModel(models.Model):
image = fields.ImageField(dependencies=[
FileDependency(processor=ImageProcessor(
format='JPEG', scale={'max_width': 300, 'max_height': 300}))
])
- [Django]-How to force-save an "empty"/unchanged django admin inline?
- [Django]-How do you develop against OpenID locally
- [Django]-Using AuthenticationForm in Django
7👍
EDIT4 : full working code can be found here (the code below still has some mistakes)
Still fighting, but there is progress ^^ : I am trying to do the resizing and convertion in memory with PIL (and seeing the amount of questions on the subject, it seems that I am not the only one ^^). My code so far (in Models.py):
from PIL import Image as Img
import StringIO
from django.core.files import File
class Mymodel(models.Model):
#blablabla
photo = models.ImageField(uppload_to="...", blank=True)
def save(self, *args, **kwargs):
if self.photo:
image = Img.open(StringIO.StringIO(self.photo.read()))
image.thumbnail((100,100), Img.ANTIALIAS)
output = StringIO.StringIO()
image.save(output, format='JPEG', quality=75)
output.seek(0)
self.photo = File(output, self.photo.name())
super(Mymodel, self).save(*args, **kwargs)
I have an error at “photo = File(output, photo.name())”
Thanks
EDIT : Sorry, it was a simple mistake (forgot the self.) corrected in code. Now I have the error “TypeError, ‘unicode’ object is not callable”, at the same line.
EDIT2: Saw something about “output.getvalue()” here but don’t really know if could be of any help.
EDIT3 : Solved!! Code below.
from PIL import Image as Img
import StringIO
from django.core.files.uploadedfile import InMemoryUploadedFile
class Mymodel(models.Model):
photo = models.ImageField(upload_to="...", blank=True)
def save(self, *args, **kwargs):
if self.photo:
image = Img.open(StringIO.StringIO(self.photo.read()))
image.thumbnail((200,200), Img.ANTIALIAS)
output = StringIO.StringIO()
image.save(output, format='JPEG', quality=75)
output.seek(0)
self.photo= InMemoryUploadedFile(output,'ImageField', "%s.jpg" %self.photo.name, 'image/jpeg', output.len, None)
super(Mymodel, self).save(*args, **kwargs)
- [Django]-What's the best way to migrate a Django DB from SQLite to MySQL?
- [Django]-Django: For Loop to Iterate Form Fields
- [Django]-Best way to make Django's login_required the default
3👍
Just put together this for my own project, took me a while before i realized that the bytes and the image is separate attributes on the Django ImageField, this solution worked for me with Python 3.6.
def clean_image(self):
image_field = self.cleaned_data.get('image')
if image_field:
try:
image_file = BytesIO(image_field.file.read())
image = Image.open(image_file)
image.thumbnail((300, 300), Image.ANTIALIAS)
image_file = BytesIO()
image.save(image_file, 'PNG')
image_field.file = image_file
image_field.image = image
return image_field
except IOError:
logger.exception("Error during resize image")
- [Django]-Access request in django custom template tags
- [Django]-Django DeleteView without confirmation template
- [Django]-Reverse for success_url on Django Class Based View complain about circular import
3👍
from PIL import Image
class Article(TimeStampedModel):
image = models.ImageField(upload_to='article_images/', null=True, blank=True)
def save(self, *args, **kwargs):
if self.image:
super().save(*args, **kwargs)
img = Image.open(self.image.path)
if img.height > 700 or img.weight > 700:
output_size = (700,700)
img.thumbnail(output_size)
img.save(self.image.path)
- [Django]-How to add custom search box in Django-admin?
- [Django]-Tying in to Django Admin's Model History
- [Django]-How django time zone works with model.field's auto_now_add
2👍
This Worked for me try it. I am using Django 2.0.6 and Python 3.6.4
from django.db import models
from PIL import Image
from io import BytesIO
from django.core.files.uploadedfile import InMemoryUploadedFile
class ImageUpload(models.Model):
name = models.CharField(max_length=100)
uploadedImage = models.ImageField(upload_to='Uploads/%Y/%m/', db_column="Upload an Image")
def save(self, *args, **kwargs):
imageTemproary = Image.open(self.uploadedImage)
outputIoStream = BytesIO()
imageTemproaryResized = imageTemproary.resize( (1020,573) )
imageTemproaryResized.save(outputIoStream , format='JPEG', quality=85)
outputIoStream.seek(0)
self.uploadedImage = InMemoryUploadedFile(outputIoStream,'ImageField', "%s.jpg" %self.uploadedImage.name.split('.')[0], 'image/jpeg', sys.getsizeof(outputIoStream), None)
super(ImageUpload, self).save(*args, **kwargs)
- [Django]-Django-tables2: How to use accessor to bring in foreign columns?
- [Django]-Generate unique id in django from a model field
- [Django]-How do I use a dictionary to update fields in Django models?
0👍
The easiest solution:
def compress(image):
im = Image.open(image)
# create a BytesIO object
im_io = BytesIO()
# save image to BytesIO object
im.save(im_io, 'JPEG', quality=70)
# create a django-friendly Files object
new_image = File(im_io, name=image.name)
return new_image
- [Django]-Non-database field in Django model
- [Django]-How to redirect to previous page in Django after POST request
- [Django]-How to run Debug server for Django project in PyCharm Community Edition?