Django-compressor:如何写入S3,从CloudFront读取?

Mat*_*lla 17 python django amazon-s3 amazon-cloudfront django-compressor

我想从CloudFront提供我的压缩CSS/JS(他们生活在S3上),但我无法通过settings.py中的压缩器设置来解决这个问题,我有以下内容:

    COMPRESS_OFFLINE = True 
    COMPRESS_URL = 'http://static.example.com/' #same as STATIC_URL, so unnecessary, just here for simplicity
    COMPRESS_STORAGE = 'my_example_dir.storage.CachedS3BotoStorage' #subclass suggested in [docs][1]
    COMPRESS_OUTPUT_DIR = 'compressed_static'
    COMPRESS_ROOT = '/home/dotcloud/current/static/' #location of static files on server
Run Code Online (Sandbox Code Playgroud)

尽管有COMPRESS_URL,我的文件正在从我的s3存储桶中读取:
<link rel="stylesheet" href="https://example.s3.amazonaws.com/compressed_static/css/e0684a1d5c25.css?Signature=blahblahblah;Expires=farfuture;AWSAccessKeyId=blahblahblah" type="text/css" />

我想问题是我想将文件写入S3,但是从CloudFront读取它.这可能吗?

Jia*_*aro 33

我在boto提供的一个后面写了一个包装器存储后端

MYAPP/storage_backends.py:

import urlparse
from django.conf import settings
from storages.backends.s3boto import S3BotoStorage

def domain(url):
    return urlparse.urlparse(url).hostname    

class MediaFilesStorage(S3BotoStorage):
    def __init__(self, *args, **kwargs):
        kwargs['bucket'] = settings.MEDIA_FILES_BUCKET
        kwargs['custom_domain'] = domain(settings.MEDIA_URL)
        super(MediaFilesStorage, self).__init__(*args, **kwargs)

class StaticFilesStorage(S3BotoStorage):
    def __init__(self, *args, **kwargs):
        kwargs['bucket'] = settings.STATIC_FILES_BUCKET
        kwargs['custom_domain'] = domain(settings.STATIC_URL)
        super(StaticFilesStorage, self).__init__(*args, **kwargs)
Run Code Online (Sandbox Code Playgroud)

我的settings.py文件有...

STATIC_FILES_BUCKET = "myappstatic"
MEDIA_FILES_BUCKET = "myappmedia"
STATIC_URL = "http://XXXXXXXX.cloudfront.net/"
MEDIA_URL = "http://XXXXXXXX.cloudfront.net/"

DEFAULT_FILE_STORAGE = 'myapp.storage_backends.MediaFilesStorage'
COMPRESS_STORAGE = STATICFILES_STORAGE = 'myapp.storage_backends.StaticFilesStorage'
Run Code Online (Sandbox Code Playgroud)


Mat*_*lla 11

我对settings.py进行了一些不同的更改

AWS_S3_CUSTOM_DOMAIN = 'XXXXXXX.cloudfront.net' #important: no "http://"
AWS_S3_SECURE_URLS = True #default, but must set to false if using an alias on cloudfront

COMPRESS_STORAGE = 'example_app.storage.CachedS3BotoStorage' #from the docs (linked below)
STATICFILES_STORAGE = 'example_app.storage.CachedS3BotoStorage'
Run Code Online (Sandbox Code Playgroud)

压缩机文件

上面的解决方案在本地保存文件,并将它们上传到s3.这让我可以脱机压缩文件.如果你不是gzipping,上面应该适用于从CloudFront提供压缩文件.

添加gzip会增加皱纹:

settings.py

AWS_IS_GZIPPED = True
Run Code Online (Sandbox Code Playgroud)

虽然这会在collectstatic期间将可压缩文件(根据存储的css和js)推送到s3时导致错误:

AttributeError:'cStringIO.StringO'对象没有属性'name'

这是由于一些奇怪的错误与我不理解的css/js文件的压缩有关.这些文件我需要本地,解压缩,而不是s3,所以如果我调整上面引用的存储子类(并在压缩文档中提供),我可以完全避免这个问题.

新的storage.py

from os.path import splitext 
from django.core.files.storage import get_storage_class  
from storages.backends.s3boto import S3BotoStorage  


class StaticToS3Storage(S3BotoStorage): 

    def __init__(self, *args, **kwargs): 
        super(StaticToS3Storage, self).__init__(*args, **kwargs) 
        self.local_storage = get_storage_class('compressor.storage.CompressorFileStorage')() 

    def save(self, name, content): 
        ext = splitext(name)[1] 
        parent_dir = name.split('/')[0] 
        if ext in ['.css', '.js'] and not parent_dir == 'admin': 
            self.local_storage._save(name, content) 
        else:     
            filename = super(StaticToS3Storage, self).save(name, content) 
            return filename 
Run Code Online (Sandbox Code Playgroud)

然后保存所有.css和.js文件(不包括我从CloudFront解压缩的管理文件),同时将其余文件推送到s3(并且不打算在本地保存它们,但可以轻松添加self.local_storage. _save line).

但是当我运行compress时,我希望我的压缩.js和.css文件被推送到s3,所以我创建了另一个用于压缩器的sublcass:

class CachedS3BotoStorage(S3BotoStorage): 
        """ 
        django-compressor uses this class to gzip the compressed files and send them to s3 
        these files are then saved locally, which ensures that they only create fresh copies 
        when they need to 
        """ 
        def __init__(self, *args, **kwargs): 
            super(CachedS3BotoStorage, self).__init__(*args, **kwargs) 
            self.local_storage = get_storage_class('compressor.storage.CompressorFileStorage')() 


        def save(self, filename, content): 
            filename = super(CachedS3BotoStorage, self).save(filename, content) 
            self.local_storage._save(filename, content) 
            return filename 
Run Code Online (Sandbox Code Playgroud)

最后,鉴于这些新的子类,我需要更新一些设置:

COMPRESS_STORAGE = 'example_app.storage.CachedS3BotoStorage' #from the docs (linked below)
STATICFILES_STORAGE = 'example_app.storage.StaticToS3Storage'
Run Code Online (Sandbox Code Playgroud)

这就是我要说的全部内容.