Django FileField with upload_to determined at runtime
I'm trying to set up my uploads so that if user joe uploads a file it goes to MEDIA_ROOT/joe as opposed to having everyone's files go to MEDIA_ROOT. The problem is I don't know how to define this in the model. Here is how it currently looks: class Content(models.Model): name = models.CharField(max_length=200) user = models.ForeignKey(User) file = models.FileField(upload_to='.') So what I want is instead of '.' as the upload_to, have it be the user's name. I understand that as of Django 1.0 you can define your own function to handle the upload_to but that function has no idea of who the user will be either so I'm a bit lost. Thanks for the help!
You’ve probably read the documentation, so here’s an easy example to make it make sense:
def content_file_name(instance, filename): return '/'.join(['content', instance.user.username, filename]) class Content(models.Model): name = models.CharField(max_length=200) user = models.ForeignKey(User) file = models.FileField(upload_to=content_file_name)
As you can see, you don’t even need to use the filename given – you could override that in your upload_to callable too if you liked.
This really helped. For a bit more brevity’s sake, decided to use lambda in my case:
file = models.FileField( upload_to=lambda instance, filename: '/'.join(['mymodel', str(instance.pk), filename]), )
A note on using the ‘instance’ object’s pk value. According to the documentation:
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.
Therefore the validity of using pk depends on how your particular model is defined.
If you have problems with migrations you probably should be using
import datetime import os import unicodedata from django.core.files.storage import default_storage from django.utils.deconstruct import deconstructible from django.utils.encoding import force_text, force_str @deconstructible class UploadToPath(object): def __init__(self, upload_to): self.upload_to = upload_to def __call__(self, instance, filename): return self.generate_filename(filename) def get_directory_name(self): return os.path.normpath(force_text(datetime.datetime.now().strftime(force_str(self.upload_to)))) def get_filename(self, filename): filename = default_storage.get_valid_name(os.path.basename(filename)) filename = force_text(filename) filename = unicodedata.normalize('NFKD', filename).encode('ascii', 'ignore').decode('ascii') return os.path.normpath(filename) def generate_filename(self, filename): return os.path.join(self.get_directory_name(), self.get_filename(filename))
class MyModel(models.Model): file = models.FileField(upload_to=UploadToPath('files/%Y/%m/%d'), max_length=255)
- Database Administration Tutorials
- Programming Tutorials & IT News
- Linux & DevOps World
- Entertainment & General News
- Games & eSport