[Fixed]-Django dynamic FileField upload_to

26👍

You can use some thing like this(i used it in my project):

import os
def get_upload_path(instance, filename):
    return os.path.join(
      "user_%d" % instance.owner.id, "car_%s" % instance.slug, filename)

Now:

photo = models.ImageField(upload_to=get_upload_path)

6👍

Since the file_path is an attribute on the File model, can you not build the full path something like this:

import os

def create_path(instance, filename):
    return os.path.join(
        instance.author.username,
        instance.file_path,
        filename
    )

And then reference it from your File model:

class File(models.Model):
    ...
    file_content = models.FileField(upload_to=create_path)

Link to docs

4👍

The other answers work flawlessly; however, I want to point out the line in the source code that allows such functionality. You can view the function, generate_filename, here, in Django’s source code.

The lines that make the magic happen:

if callable(self.upload_to):
    filename = self.upload_to(instance, filename)

When you pass a callable to the upload_to parameter, Django will call the callable to generate the path. Note that Django expects your callable to handle two arguments:

  • instance
    • the model that contains the FileField/ImageField
  • filename
    • the name of the uploaded file, including the extension (.png, .pdf, …)

Also note that Python does not force your callable‘s arguments to be exactly ‘instance’ and ‘filename’ because Django passes them as positional parameters. For example, I prefer to rename them:

def get_file_path(obj, fname):
    return os.path.join(
        'products',
        obj.slug,
        fname,
    )

And then use it like so:

image = models.ImageField(upload_to=get_file_path)
👤gmdev

Leave a comment