How to set-up a Django project with django-storages and Amazon S3, but with different folders for static files and media files?

后端 未结 5 1458
情歌与酒
情歌与酒 2020-11-28 00:47

I\'m configuring a Django project that were using the server filesystem for storing the apps static files (STATIC_ROOT) and user uploaded files (MEDIA_ROO

5条回答
  •  失恋的感觉
    2020-11-28 01:34

    I'm currently using this code in a separated s3utils module:

    from django.core.exceptions import SuspiciousOperation
    from django.utils.encoding import force_unicode
    
    from storages.backends.s3boto import S3BotoStorage
    
    
    def safe_join(base, *paths):
        """
        A version of django.utils._os.safe_join for S3 paths.
    
        Joins one or more path components to the base path component intelligently.
        Returns a normalized version of the final path.
    
        The final path must be located inside of the base path component (otherwise
        a ValueError is raised).
    
        Paths outside the base path indicate a possible security sensitive operation.
        """
        from urlparse import urljoin
        base_path = force_unicode(base)
        paths = map(lambda p: force_unicode(p), paths)
        final_path = urljoin(base_path + ("/" if not base_path.endswith("/") else ""), *paths)
        # Ensure final_path starts with base_path and that the next character after
        # the final path is '/' (or nothing, in which case final_path must be
        # equal to base_path).
        base_path_len = len(base_path) - 1
        if not final_path.startswith(base_path) \
           or final_path[base_path_len:base_path_len + 1] not in ('', '/'):
            raise ValueError('the joined path is located outside of the base path'
                             ' component')
        return final_path
    
    
    class StaticRootS3BotoStorage(S3BotoStorage):
        def __init__(self, *args, **kwargs):
            super(StaticRootS3BotoStorage, self).__init__(*args, **kwargs)
            self.location = kwargs.get('location', '')
            self.location = 'static/' + self.location.lstrip('/')
    
        def _normalize_name(self, name):
            try:
                return safe_join(self.location, name).lstrip('/')
            except ValueError:
                raise SuspiciousOperation("Attempted access to '%s' denied." % name)
    
    
    class MediaRootS3BotoStorage(S3BotoStorage):
        def __init__(self, *args, **kwargs):
            super(MediaRootS3BotoStorage, self).__init__(*args, **kwargs)
            self.location = kwargs.get('location', '')
            self.location = 'media/' + self.location.lstrip('/')
    
        def _normalize_name(self, name):
            try:
                return safe_join(self.location, name).lstrip('/')
            except ValueError:
                raise SuspiciousOperation("Attempted access to '%s' denied." % name)
    

    Then, in my settings module:

    DEFAULT_FILE_STORAGE = 'myproyect.s3utils.MediaRootS3BotoStorage'
    STATICFILES_STORAGE = 'myproyect.s3utils.StaticRootS3BotoStorage'
    

    I got to redefine the _normalize_name() private method to use a "fixed" version of the safe_join() function, since the original code is giving me SuspiciousOperation exceptions for legal paths.

    I'm posting this for consideration, if anyone can give a better answer or improve this one, it will be very welcome.

提交回复
热议问题