Source

django-storages / storages / backends / hashpath.py

import os, hashlib, errno

from django.conf import settings
from django.core.files.storage import FileSystemStorage
from django.utils.encoding import force_unicode

class HashPathStorage(FileSystemStorage):
    """
    Creates a hash from the uploaded file to build the path.
    """

    def save(self, name, content):
        # Get the content name if name is not given
        if name is None: name = content.name

        # Get the SHA1 hash of the uploaded file
        sha1 = hashlib.sha1()
        for chunk in content.chunks():
            sha1.update(chunk)
        sha1sum = sha1.hexdigest()

        # Build the new path and split it into directory and filename
        name = os.path.join(os.path.split(name)[0], sha1sum[:1], sha1sum[1:2], sha1sum)
        dir_name, file_name = os.path.split(name)

        # Return the name if the file is already there
        if os.path.exists(name):
            return name

        # Try to create the directory relative to the media root
        try:
            os.makedirs(os.path.join(settings.MEDIA_ROOT, dir_name))
        except OSError as e:
            if e.errno is not errno.EEXIST:
                raise e

        # Save the file
        name = self._save(name, content)

        # Store filenames with forward slashes, even on Windows
        return force_unicode(name.replace('\\', '/'))