python-3.xdjangodjango-modelsfile-uploaddynamic-programming

How can I create an upload_to folder that is named a field belonging to the model that is simultaneously being created?


Context: I'm building a car dealership app using Django 3.1.4, and trying to implement a feature where by every time a new ad is created, so is a new folder (via the upload_to method) within /media/ that will only contain that newly created ad's photos.

I've gotten this working somewhat using date formatting (see below) but I need this new folder to be named one of the fields belonging to the model(see the second code snippet).

photo_4 = models.ImageField(upload_to='photos/%Y/%m/%d', blank=True)

For example, every newly created ad would use the title field..

class Vehicles(models.Model):
    CONDITION_CHOICES = [("Brand New","Brand New"),("Used", "Used")]
    FUEL_CHOICES = [("Petrol","Petrol"),("Diesel", "Diesel"),("Electric", "Electric"),("Hybrid", "Hybrid")]
    TRANSMISSION_CHOICES = [("Automatic","Automatic"),("Manual", "Manual")]
    title = models.CharField(max_length=200, default = "Ad Title & Folder Name")
    def folder_name(self, title):
        return self.title
    make = models.CharField(max_length=100)

Ideally then, the media folder would look something like

/media/
    Opel Astra VXR/
    Mercedes E200/

I understand that many others have done something similar but all the examples I found use the 'user' and instead I need to use a model field (belonging to the model that is being created) as the folder name.

Closing notes: The function in the second code snippet was just something I was trialing.

Also, this is still in development, so in prod I fully intent to direct all media to an S3 bucket down the line.


Solution

  • As documented

    upload_to may also be a callable, such as a function. This will be called to obtain the upload path, including the filename. This callable must accept two arguments and return a Unix-style path (with forward slashes) to be passed along to the storage system. The two arguments are:

    For example:

    def user_directory_path(instance, filename):
        # file will be uploaded to MEDIA_ROOT/user_<id>/<filename>
        return 'user_{0}/{1}'.format(instance.user.id, filename)