Programmatically Saving Image to Django Imagefield

Programmatically saving image to Django ImageField

I have some code that fetches an image off the web and stores it in a model. The important bits are:

from django.core.files import File  # you need this somewhere
import urllib

# The following actually resides in a method of my model

result = urllib.urlretrieve(image_url) # image_url is a URL to an image

# self.photo is the ImageField
self.photo.save(
os.path.basename(self.url),
File(open(result[0], 'rb'))
)

self.save()

That's a bit confusing because it's pulled out of my model and a bit out of context, but the important parts are:

  • The image pulled from the web is not stored in the upload_to folder, it is instead stored as a tempfile by urllib.urlretrieve() and later discarded.
  • The ImageField.save() method takes a filename (the os.path.basename bit) and a django.core.files.File object.

Let me know if you have questions or need clarification.

Edit: for the sake of clarity, here is the model (minus any required import statements):

class CachedImage(models.Model):
url = models.CharField(max_length=255, unique=True)
photo = models.ImageField(upload_to=photo_path, blank=True)

def cache(self):
"""Store image locally if we have a URL"""

if self.url and not self.photo:
result = urllib.urlretrieve(self.url)
self.photo.save(
os.path.basename(self.url),
File(open(result[0], 'rb'))
)
self.save()

Django image saving

you can do it in the following way
I'll put the functions here, but you can put them in another file to reuse them and then import them, I'll add the necessary libraries

import PIL
from io import BytesIO
from PIL import Image
from django.core.files import File

class Image(models.Model):
image = models.FileField()

def save(self, *args, **kwargs):
new_image = self.compress_images(self.image)

# asignar la nueva imagen con menor peso
self.image = new_image
super().save(*args, **kwargs)


def valid_extension(self,_img):
if '.jpg' in _img:
return "JPEG"
elif '.jpeg' in _img:
return "JPEG"
elif '.png' in _img:
return "PNG"

def compress_images(self,image):
im = Image.open(image)
width, height = im.size
im = im.resize((width-50, height-50), PIL.Image.ANTIALIAS)
# crear a BytesIO object
im_io = BytesIO()
im.save(im_io, self.valid_extension(image.name) ,optimize=True,
quality=70)
new_image = File(im_io, name=image.name)
return new_image

Programmatically saving image to Django ImageField returning 404 in production

My approach is a bit different from @Xyres's, I thought xyres's would make a duplicate of the existing image and create a new one and when I tried overriding the URL attribute it returned an error of

can't set the attribute

but when I saw this question and this ticket I tried making this and it worked

model2.processed_image = processingfunction(model1.uploaded_image.path)
full_path = model2.processed_image.path
model2.processed_image.name = full_path.split('media')[1]

so that explicitly making the URL media/path/to/image and cut out all of the unneeded parts like home/ubuntu and stuff

How to save an image using django imageField?

Just because you're not using an actual HTML form to submit the data doesn't mean you can't use a ModelForm to process the request:

from django.http import HttpResponse, HttpResponseBadRequest, HttpResponseNotAllowed
from django.utils import simplejson

def upload_view(request):
if request.method == 'POST':
form = UploadForm(request.POST, request.FILES)
if form.is_valid():
form.save()
result = {'success': True}
return HttpResponse(simplejson.dumps(result), mimetype='application/json')
else:
return HttpResponseBadRequest()
else:
return HttpResponseNotAllowed(['POST'])

Django - Saving an image manually to an ImageField field

I have solved my problem simply by moving:

super(Image, self).save(*args, **kwargs)

to the end of def save(). I'm still not certain why it's happening this way, but my only explanation is that save() itself is persisting fields values to the database and hence it needs to be executed at the very end.

Django ImageField: directly using file from disk

Use uploadedfile--(Django doc) class as

from django.core.files.uploadedfile import UploadedFile
instance = MyModel(
image=UploadedFile(
file=open("/home/user/path/to/file/foo.jpg", 'rb')
)

)
instance.save()

Result

Sample Image

Save a generated PIL image into an ImageField in django

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.

Programatically saving an image to a Django ImageField is creating an infinite loop of images

I think from a browse through the source code that calling ImageFileField.save() (actually FileField.save() due to inheritance) causes the instance (namely the db row) that the file name is stored in to be updated.

This means that in your save method you call ImageFileField.save() which in turn calls your save method, causing the recursion.

From reading the source code, if you want to prevent this, then just pass save=False to self.image.save. This will save the file data to disk, but just won't save the instance (db row) data. However in the next line you save it by calling the superclass, so I think it will be saved to the database then.

In fact it looks like that the save=False on the save method was designed to help with this case!



Related Topics



Leave a reply



Submit