1

I have a Django model with a customized image field. The image field creates some thumbnail sizes on upload. Code may look like this:

from django.db import models
from utils import CustomImageField

class Photo(models.Model):
    image = CustomImageField()

Now I modify the original image, let's say I rotate it. And now I want to trigger the save method of my image field again, in order to overwrite the thumbnails and create rotated versions. So, I don't need to rotate the thumbnails elsewhere in my code (DRY).

Any thoughts? Something along those lines - but how exactly?

p = Photo.objects.get(pk=1)
p.image.save(...)

I have full control over the CustomImageField widget. The save() method is defined as:

def save(self, name, path, save=True):

Question is, what do I use for the methods parameters?

Simon Steinberger
  • 6,605
  • 5
  • 55
  • 97

2 Answers2

3

This question looks like a duplicate of Programmatically saving image to Django ImageField

The parameters of the ImageField.save() method are documented for FileField.save() (of which ImageField is a subclass): https://docs.djangoproject.com/en/1.9/ref/models/fields/#django.db.models.fields.files.FieldFile.save

Takes two required arguments: name which is the name of the file, and content which is an object containing the file’s contents. The optional save argument controls whether or not the model instance is saved after the file associated with this field has been altered. Defaults to True.


Here is what is working for us:

class CustomImage(models.Model):
    image = models.ImageField(upload_to=get_file_path, max_length=500)
    orig_name = models.TextField()

This is the method that adds an image file to the ImageField from an http resource:

from django.core.files.base import ContentFile

def download_photo(amazon_id, url):
    img_data = requests.get(url)
    img = CustomImage(orig_name=img_data.url)
    img.image.save(slugify(img.orig_name), ContentFile(img_data.content), save=True)

It also works without ContentFile:

new_img = File(open(different_obj.image.path), 'r')
img.image.save(different_obj.image.url, new_img, save=True)

See also: - https://docs.djangoproject.com/en/1.9/topics/files/ - https://djangosnippets.org/snippets/2587/

Community
  • 1
  • 1
Risadinha
  • 16,058
  • 2
  • 88
  • 91
2

An option is dirty field checking, either manually (see this SO question) or using a pypi package

Alternatively, if you want to conserve memory, the resizing can be triggered from the field's property setter (assuming you inherit from FileField

class CustomImageField(FileField):

    def _set_file(self, file):
        has_file_changed = file != self._file
        super(CustomImageField, self)._set_file(file)
        if has_file_changed:
             self.handle_resizing_etc()

    # need to redeclare property so it points to the right _set_file
    file = property(FileField._get_file, _set_file, FileField._del_file)

disclaimer: I haven't used this approach in production code and I haven't written a proof of concept before posting this answer, so it might not work as desired

Community
  • 1
  • 1
zsepi
  • 1,572
  • 10
  • 19