Dynamic upload path - include originating field
I have a Django model with multiple ImageFields and use a callable to determine the upload path. I want to include the originating upload field's name in the upload path, in this case tiny
, small
, medium
or press
.
The only way I could think of was to create a pre_save receiver which replaces file.name
with a uuid. Then the upload_to callable finds the match by comparing it to filename
. Isn't there a less hacky way of doing this?
class SomeDjangoModel(models.Model):
IMAGE_SIZES = ('tiny', 'small', 'medium', 'press')
def image_path(self, filename):
""" Example return: [some-django-model]/[medium]/[product1].[jpg] """
size = None
for field_name in self.IMAGE_SIZES:
field_fn = getattr(getattr(self, field_name), 'name', '')
if field_fn == filename.rpartition('/')[2]:
size = field_name
break
return u'{}/{}/{}.{}'.format(
slugify(self._meta.verbose_name),
size or 'undetermined',
self.slug,
filename.rpartition('.')[2].lower(),
)
tiny = models.ImageField(upload_to=image_path, blank=True, null=True)
small = models.ImageField(upload_to=image_path, blank=True, null=True)
medium = models.ImageField(upload_to=image_path, blank=True, null=True)
p开发者_如何学编程ress = models.ImageField(upload_to=image_path, blank=True, null=True)
The pre_save
receiver:
@receiver(pre_save, sender=SomeDjangoModel)
def set_unique_fn(sender, instance, **kwargs):
""" Set a unique (but temporary) filename on all newly uploaded files. """
for size in instance.IMAGE_SIZES:
field = getattr(instance, '{}_img'.format(size), None)
if not field:
continue
fieldfile = getattr(field, 'file', None)
if isinstance(fieldfile, UploadedFile):
fieldfile.name = u'{}.{}'.format(
uuid.uuid4().hex,
fieldfile.name.rpartition('.')[2],
)
You can change image_path()
so that it returns a callable which already knows the size:
def image_path(size):
def callback(self, filename)
""" Example return: [some-django-model]/[medium]/[product1].[jpg] """
return u'{}/{}/{}.{}'.format(
slugify(self._meta.verbose_name),
size,
self.slug,
filename.rpartition('.')[2].lower(),
)
return callback
class SomeDjangoModel(models.Model):
tiny = models.ImageField(upload_to=image_path('tiny'), blank=True, null=True)
small = models.ImageField(upload_to=image_path('small'), blank=True, null=True)
medium = models.ImageField(upload_to=image_path('medium'), blank=True, null=True)
press = models.ImageField(upload_to=image_path('press'), blank=True, null=True)
精彩评论