How to modify the file before saving

175 views
Skip to first unread message

Remy Gwaramadze

unread,
Oct 2, 2013, 7:22:49 AM10/2/13
to django...@googlegroups.com
I'd like to make some mandatory modifications to every file coming through django-filer.
1. I'd like to rename the actual filename.
And make some changes the the image, for now:
2. I'd like to crop main image.
3. I'd like to watermark it.

I know that I need to use Pillow for two latter manipulations, I think I can figure it out when it comes to that.
But for now I'd be thankful for any hints on how to intercept the image coming from filer upload process.
I think I'd need to do it in a pre_save signal. I'm putting this signal on one of my models which is closely related to images coming from filer. And after that I'm stuck.

@receiver(pre_save, sender=Image)
def filer_file_mods(sender, instance, **kwargs):
    # what here?

Thanks,
Remy

Stefan Foulis

unread,
Oct 2, 2013, 7:30:57 AM10/2/13
to django...@googlegroups.com

Hi Remy

Controlling the full filepath in the filesystem is a bit tricky, especially if you only want to control the path for certain files. It's actually the upload_to function on the filer File model and the used storage backend that determine the final file path. If you only care about the filename and not about the rest of the path, you can set it on the File object after uploading (using djangos SimpleUploadedFile.name, I think). Filer will keep that filename but change the path. If you are using secure storage backends with filer, the path might change when you change permissions. But the filename should stay the same.

If you want to completely control the path, it will be a bit more involved and you'll have to override the FILER_STORAGES setting to provide your own upload_to/storage backend.

Cheers

Stefan

Remy Gwaramadze

unread,
Oct 2, 2013, 7:36:52 AM10/2/13
to django...@googlegroups.com
No, luckily for my case, I don't need full path control, just the very end of it: the filename.
Could you be a little bit more specific, SimpleUploadedFile.name?

Remy Gwaramadze

unread,
Oct 2, 2013, 7:46:40 AM10/2/13
to django...@googlegroups.com
I tried doing this


@receiver(pre_save, sender=Image)
    def filer_file_mods(sender, instance, **kwargs):
        instance.name = "my-new-filename.jpg"
        return

and the name is changed indeed but the filename stays the same, advanced sections reveal the old filename:
Currently: filer_public/3f/d7/3fd73f4c-2f7f-41a9-8104-839cbe5a65dd/old-filename-here.jpg

Stefan Foulis

unread,
Oct 2, 2013, 7:53:41 AM10/2/13
to django...@googlegroups.com

Hi Remy

Hmm. I confused your case with another thread on the mailing-list. I thought you were uploading from a custom form. So the SimpleUploadedFile modification won't work.

yeah, instance.name is just a "pretty name" and has nothing to do with the actual filename.

It really depends based on what information you'd like to modify the filename. What information should the filename contain?

You'll probably have to override upload_to after all.

https://docs.djangoproject.com/en/dev/ref/models/fields/#filefield

http://django-filer.readthedocs.org/en/0.9.4/settings.html#filer-storages  (you need to override FILER_STORAGE.public.main.UPLOAD_TO)

"instance" in upload_to will be the filer.File instance that is being created on upload.

Cheers

Stefan

Remy Gwaramadze

unread,
Oct 2, 2013, 8:48:18 AM10/2/13
to django...@googlegroups.com
I think I got it!

@receiver(pre_save, sender=Image)
def filer_file_mods(sender, instance, **kwargs):
    instance.file.name = "my-new-filename.jpg"

It's that easy :]
I am going to grab the extension, build the filename dynamically using some data from various models and glue it back with extension.
Still I am gonna tweak 'UPLOAD_TO' to 'filer.utils.generate_filename.by_date' which seems to be more neat than randomized. I humbly suggest to setting it as a default.

Now I'm off to figure out cropping before saving.

Stefan Foulis

unread,
Oct 2, 2013, 8:54:42 AM10/2/13
to django...@googlegroups.com

Awesome that you found a solution :-)


by_date used to be the default, but I changed it to random.

The problem is, that date based is not unique. So if you upload a file with the same name twice on the same day, it will add a "_" to the end of the filename to keep it unique.

The random path solves that problem and also obfuscates file urls. So you can upload files that only people who know the url can download.

Cheers

Stefan

Remy Gwaramadze

unread,
Oct 2, 2013, 3:40:32 PM10/2/13
to django...@googlegroups.com
Good reasoning. But now, I figured I need a solution to prevent duplicates whatsoever. What is the best practice for this?
I tried utilizing my pre_save signal, yet again:

try:
    sender.objects.get(sha1=instance.sha1)
except:
    pass
else:
    raise Exception

And it works but it leaves this nasty 'undefined' in the clipboard.
Reply all
Reply to author
Forward
0 new messages