django: playing with upload_to field
Django provides models.FileField & models.ImageField to save uploaded files & images respectively. Both these fields take a parameters ‘upload_to’ which defines the path where the uploaded file will be saved (complete path is settings.MEDIA_ROOT + upload_to). You can play some neat tricks with this little feature.
Creating the date based folders at run time
You can use the upload_to parameter to upload files in folders named on the file date.
Suppose you are creating a photo album and want images to be uploaded in folders containing the year and month in name. This is convenient for files management as well as for backups.
class Photo(models.Model): original = models.ImageField(upload_to='album/%m-%Y/') #other fields
Now every time you save an image using Photo, django will create (if not already exists) a folder ‘MM-YYYY’ in MEDIA_ROOT/album/ and save the image in it.
Dynamically changing the folder
What if you want to change the upload_to path at run time? Consider the following model,
class MediaContent(models.Model): content_file = models.FileField() content_type = models.CharField(max_length=1, choices=(('I','Image'),('V','Video'),('A','Audio'),('D','Doc'))) #other fields
The MediaContent file caters for various media content files like image, video, audio, docs and pdf files. I want to treat all media files in the same manner but upload these files to different folders based on the content type. This means that I need to change upload_to before I want to save a MediaContent instance.
Using a callback as upload_to
django enables you to provide a callback as upload_to value. This callable is nothing more than a function that takes following arguments,
- self – instance of MediaContent
- instance – instance of actual FileField or ImageField (content_file in this case)
- filename – the file name that was passed while saving the file
class MediaContent(models.Model): content_file = models.FileField(upload_to=get_media_upload_to) content_type = models.CharField(max_length=1, choices=(('I','Image'),('V','Video'),('A','Audio'),('D','Doc'))) #other fields def get_media_upload_to(instance, filename): """ A simple way to return the full path """ paths = { 'I':'images/', 'V':'videos/', 'A':'audio/', 'D':'documents'/ } return settings.MEDIA_ROOT + 'content/' + paths[instance.content_type] + filename
Every time you call media_content_object.content_file.save(filename, mem_file), get_media_upload_to will be called and you can determine the file path based on content_type
Modify the upload_to at run-time
You can set upload_to to a fixed value and then change it to your desired location just before saving the object.
def save_content(request): #if image MediContent._meta.get_field('content_file').upload_to='content/images/' #if video MediContent._meta.get_field('content_file').upload_to='content/videos/' #if audio MediContent._meta.get_field('content_file').upload_to='content/audios/' #if doc MediContent._meta.get_field('content_file').upload_to='content/documents/' #if pdf MediContent._meta.get_field('content_file').upload_to='content/acrobat/' #other types
Edit: It seems that in the latest version of django, self is not passed to the get_media_upload_to function, which I have fixed
Related posts:



I was trying to repeat this examples and failed.
I am curious to see full code and version of the django your are using. In my case only instance, filename will be passed to get_media_upload_to.
Any hints?