I,m working with my first project in Django, And I have a model like that:
def get_image_path(instance, filename):
category_name_path = instance.category.category_name
return f"{category_name_path}/{filename}"
class Gallery(models.Model):
description = models.TextField()
category = models.ForeignKey(Category, on_delete=models.SET_NULL, null=True)
image = ResizedImageField(size=[1920, 1920], upload_to=get_image_path)
def __str__(self):
return '%s %s %s' % (self.category, self.image.url, self.description)
It works but I cannot understand how the 'filename' argument is passed to the function? How it works? ;)
The FileField
, which is a superclass of the ImageField
has a method .generate_filename(…)
[GitHub]:
def generate_filename(self, instance, filename): if callable(self.upload_to): filename = self.upload_to(instance, filename) else: # … pass filename = validate_file_name(filename, allow_relative_path=True) return self.storage.generate_filename(filename)
This will thus call the parameter. We can also look where the call to .generate_filename
originates from:
This is by the .save(…)
method [GitHub] of the FieldFile
(not to be confused with FileField
, FieldFile
is the file stored in the field):
def save(self, name, content, save=True): name = self.field.generate_filename(self.instance, name) self.name = self.storage.save(name, content, max_length=self.field.max_length) setattr(self.instance, self.field.attname, self.name) self._committed = True # Save the object because it has changed, unless save is False if save: self.instance.save()
then this simply originates from the FileField
's .pre_save(…)
method [GitHub] that calls .save()
on the FileField
:
def pre_save(self, model_instance, add): file = super().pre_save(model_instance, add) if file and not file._committed: # Commit the file to storage prior to saving the model file.save(file.name, file.file, save=False) return file
and it thus picks the .name
of the FieldFile
.