Dynamic File Path in Django

You can use a callable in the upload_to argument rather than using custom storage. See the docs, and note the warning there that the primary key may not yet be set when the function is called. This can happen because the upload may be handled before the object is saved to the database, so using ID might not be possible. You might want to consider using another field on the model such as slug. E.g:

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

then:

photo = models.ImageField(upload_to=get_upload_path)

You can use lambda function as below, take note that if instance is new then it won't have the instance id, so use something else:

logo = models.ImageField(upload_to=lambda instance, filename: 'directory/images/{0}/{1}'.format(instance.owner.id, filename))

https://docs.djangoproject.com/en/stable/ref/models/fields/#django.db.models.FileField.upload_to

def upload_path_handler(instance, filename):
    return "user_{id}/{file}".format(id=instance.user.id, file=filename)

class Car(models.Model):
    ...
    photo = models.ImageField(upload_to=upload_path_handler, storage=fs)

There is a warning in the docs, but it shouldn't affect you since we're after the User ID and not the Car ID.

In most cases, this object will not have been saved to the database yet, so if it uses the default AutoField, it might not yet have a value for its primary key field.


My solution is not elegant, but it works:

In the model, use a the standard function that will need the id/pk

def directory_path(instance, filename):
    return 'files/instance_id_{0}/{1}'.format(instance.pk, filename)

in views.py save the form like this:

f=form.save(commit=False)
ftemp1=f.filefield
f.filefield=None
f.save()
#And now that we have crated the record we can add it
f.filefield=ftemp1
f.save()

It worked for me. Note: My filefield in models and allowed for Null values. Null=True


Well very late to the party but this one works for me.

def content_file_name(instance, filename):
    upload_dir = os.path.join('uploads',instance.albumname)
    if not os.path.exists(upload_dir):
        os.makedirs(upload_dir)
    return os.path.join(upload_dir, filename)

Model like this only

class Album(models.Model):
    albumname = models.CharField(max_length=100)
    audiofile = models.FileField(upload_to=content_file_name)