I am using django-extensions.AutoSlugField
and django.db.models.ImageField
.
To customize image name uploaded for django.db.models.ImageField
, what I did:
from django.utils.text import slugify
# idea is to make image name the same as the automatically generated slug, however don't work
def update_image_name(instance, filename):
# this debug instance, and instance.slug is empty string
print(instance.__dict__)
# I attempt to use slugify directly and see that it's not the same as the output generated by AutoSlugField
# E.g. If I create display_name "shawn" 2nd time, AutoSlugField will return "shawn-2", but slugify(display_name) return "shawn"
print(slugify(instance.display_name))
return f"images/{instance.slug}.jpg"
class Object(models.Model):
...
display_name = models.TextField()
...
# to customize uploaded image name
image = models.ImageField(blank=True, upload_to=update_image_name)
...
# create slug automatically from display_name
slug = AutoSlugField(blank=True, populate_from=["display_name"]
Based on what I debug, when I call instance
inside update_image_name
, slug
is empty string.
If I understand correctly slug
is only created at event save, so when I call ImageField
instance, slug
is not yet created, therefore empty string.
I think it might have something to do with event post save. However, I am not sure if that's the real reason or how to do that.
How can I get the automatically generated slug as my customized image name?
That's a tricky one because the order the fields are getting saved matters.
The brute-force attack I'm suggesting would be to override the save
method of your model and manually call the create_slug
method before everything else ensuring the slug is set:
from django.utils.encoding import force_str
[...]
class Object(models.Model):
[...]
def save(self, *args, **kwargs):
self.slug = force_str(self._meta.get_field('slug').create_slug(self, False))
super(Object, self).save(*args, **kwargs)
That's what AutoSlugField
does, refer to the code here. self._meta.get_field('slug')
get's the slug
field definition and then we just call the create_slug
method.
Tested under Python 3.7.9 & Django 3.1.5 like this:
from django.core.files.uploadedfile import SimpleUploadedFile
o = Object()
o.display_name = "foo bar"
o.image = SimpleUploadedFile(name='test_image.png', content=open('/path/to/test/image.png', 'rb').read(), content_type='image/png')
o.save()
Then I see update_image_name
return images/foo-bar.jpg
.