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

3

2

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.

Wolof answered 5/1, 2021 at 23:56 Comment(0)
P
3

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:

  • instance ( An instance of the model where the FileField is defined. )
  • filename ( The filename that was originally given to the file )

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)
Polygamist answered 6/1, 2021 at 0:24 Comment(1)
Thanks for your input iklinac! I went off to do more research and came across the soloution which was a formatting issue haha! You got an upvote but it wont show because I've less than 15 rep, thanks again!Wolof
W
2

Found the soloution and wanted to post it for the next person who might need it. It turned out to be a syntax issue on my formatting . This did the trick and now opens a new folder for each ad and their photos. It also updates the original folder with any new photos added to the preexisting ad.

Title and function below:

title = models.CharField(max_length=200, default = "Ad Title & Folder Name")
    def upload_photo_to(self, filename):
        return f'{self.title}/{filename}'

Photo field and how it was applied:

photo_1 = models.ImageField(upload_to=upload_photo_to, blank=True)
Wolof answered 6/1, 2021 at 0:32 Comment(0)
H
0

I had a similar scenario. However, I wanted my file path to have app name and model name in the path. My solution was as follows:

class mymodel(models.Model):
    def get_media_path(self, filename):
       return f'{self._meta.app_label}/{self._meta.object_name}/{filename}'
    myfile = models.ImageField(upload_to=get_media_path)

For your scenario let us assume that the mymodel has a field named car_model. So your implementation would be like:

class mymodel(models.Model):
    def get_media_path(self, filename):
       return f'{self.car_model}/{filename}'
    car_model = models.CharField(max_length=255)
    myfile = models.ImageField(upload_to=get_media_path)
Hooligan answered 15/10 at 12:22 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.