Store files with secured urls in Django
First, we add random UUID
before the filename when uploading a new file. It will make URL
"secured" which means that only someone who will know URL
will be able to get the file. One another benefit here - this will prevent renaming files with the same names. Also, we group files into directories by year, month, and date to prevent lagging when we have too many files in one directory:
def file_upload_path(instance, filename):
shortuuid.set_alphabet(ascii_lowercase + digits) # will generate 25-char uuids
return timezone.now().strftime('uploads/%Y/%m/%d/{0}-{1}').format(shortuuid.uuid(), filename)
class File(Model):
file = FileField(upload_to=file_upload_path)
Note that we use shortuuid
python module here which allows to generate shorter UUID
then default uuid.uuid4
function (becouse default uses smaler set of chars and several hyphens).
But such a way will have some negative effect - users will download files with modified names which is not cool. To solve this in most performant way we can add some magic header to response which will cut off UUID
from filename when user will request file. To do it in nginx proxy we can use:
location ~ "^/media/(?<path>uploads/\d+?/\d+?/\d+?/[\da-z]{25}-(?<name>.*\.(jpg|gif|png|svg)))$" {
alias /path/to/media/$path;
add_header Content-Disposition 'inline; filename="$name"';
}
location ~ "^/media/(?<path>uploads/\d+?/\d+?/\d+?/[\da-z]{25}-(?<name>.*))$" {
alias /path/to/media/$path;
add_header Content-Disposition 'attachment; filename="$name"';
}
We use two locations here because we want to give images in inline
mode (if the user will click Open in new tab
file will be opened in the browser tab). But other files we will give in attachment
mode and when the user tries to follow anchors to these files he will see a save dialog or downloading process.