provides an extraordinarily easy way of integrating file uploads into your site in the FileField
(also the ImageField
which provides some nifty image-specific functionality). However as soon as you start dealing with file uploads you have to worry about where those files are going to be stored. To take care of this, the 'upload_to' argument is set when declaring your FileField which is a local filesystem path that will be appended to your MEDIA_ROOT to the upload location (you could also use an absolute path). By default this is just a static string, though it does handle strftime arguments to allow some flexibility and will look something like this:
However that's not always going to cut it. Sometimes you're going to want more flexibility that even just separating the files out by date information. In that case you can take advantage of the fact that a callable can be passed as an argument. In one of my projects I've defined a function that returns the appropriate path depending on a couple of different variables. In this particular case, I know that all uploads for a certain model will be PDFs, while all uploads for certain other models will be images, so I'm able to pretty easily generate appropriate paths for those uploads. We also wanted to obfuscate the filenames so that someone couldn't easily guess the path for other files, and didn't really like the way that Django simply keeps appending '_'s to filenames in the event of a filename collision until it ends up with a unique name. To handle that I simply generate a random string to use as the filename, which fits our needs quite nicely. In my specific case, the function lives in myproject.lib.files and looks like this:
As you can see, it's pretty simple to generate an upload path based on pretty much any characteristics you want. To then tell Django to use this function to get the upload path rather than a static string you modify your model definition like so:
And that's all it takes. Now all my uploads are automatically renamed and uploaded into the particular directory structure that we want. And since all the logic involved is in a single function it's extremely easy to change it at any point if we decide to alter our directory structure.