2011-12-31 63 views
17

我想爲我的壓縮CSS/JS從CloudFront的(他們住在S3),但我無法工作,如何通過在settings.py壓縮機設置做到這一點,我有以下幾點:Django-compressor:如何寫入S3,從CloudFront讀取?

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 

儘管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的閱讀。這可能嗎?

+0

看到了你的票在github上......你是否介意發佈您的解決方案? – Jiaaro 2012-01-17 01:41:07

+0

對於沒有及時看到這件事,我表示誠摯的歉意,明天我會在明天下發布我的解決方案(希望) – 2012-01-19 02:17:16

回答

33

我寫周圍的博託

的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) 

凡我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' 
+0

請仔細研究ASAP @Jaoao。我已經實現了我自己的黑客解決方案,但我會檢查這個對我的,看看它是如何工作的。我確認後會馬上回來檢查你!謝謝你。 – 2012-01-19 02:15:41

11

我對settings.py做了一些不同的修改.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' 

Compressor Docs

以上解決方案將文件保存在本地以及將其上傳到s3。這讓我離線壓縮文件。如果您不是gzip,則上述內容應適用於從CloudFront提供壓縮文件。

gzip的添加增加了皺紋:

settings.py

AWS_IS_GZIPPED = True 

儘管這導致錯誤每當可壓縮文件(CSS和JS根據存儲器)中的溶液被推動期間collectstatic至S3:

AttributeError: 'cStringIO.StringO' object has no attribute 'name'

這是由於其與我不明白的CSS/JS文件的壓縮做一些奇怪的錯誤。這些文件我需要本地解壓縮,而不是s3,所以如果我調整上面提到的存儲子類(並在壓縮器docs中提供),我可以完全避免這個問題。

新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 

這則保存了所有的.css和.js文件(不包括管理的文件,這是我擔任非壓縮從CloudFront的),同時推動這些文件的其餘部分S3(而不是打擾在本地保存它們,但可以輕鬆添加self.local_storage._save行)。

但是當我運行壓縮,我想我的壓縮的.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 

最後,考慮到這些新的子類,我需要更新一些設置:

COMPRESS_STORAGE = 'example_app.storage.CachedS3BotoStorage' #from the docs (linked below) 
STATICFILES_STORAGE = 'example_app.storage.StaticToS3Storage' 

,這是所有我要說的就是這些。

+0

這是偉大的,完美的工作。謝謝您的幫助。 – 2012-05-10 22:02:08

4

好像這個問題是在Django實際上固定的上游,https://github.com/django/django/commit/5c954136eaef3d98d532368deec4c19cf892f664

的問題_get_size方法可以是在本地的補丁來解決它的老版本的Django的。

編輯:看看https://github.com/jezdez/django_compressor/issues/100實際工作。

+0

這個解決方法爲我提供了遞歸深度錯誤。我剛剛複製了原樣複製的修補程序,將默認存儲類更改爲新的修補程序,並打開AWS_IS_GZIPPED標誌。 – sbidwai 2012-08-21 09:59:39

+0

我有同樣的問題,是否有任何消息導致它或什麼因爲它工作而發生了變化?非常感謝任何提示! – tiwei 2012-11-04 21:57:00

3

其實這似乎也是django-storages中的一個問題。當壓縮程序比較S3上文件的散列值時,django-storages不會解壓縮Gzip文件的內容,但會嘗試比較不同的散列值。我已經打開https://bitbucket.org/david/django-storages/pull-request/33/fix-gzip-support來解決這個問題。

FWIW,還有https://bitbucket.org/david/django-storages/pull-request/32/s3boto-gzip-fix-and-associated-unit-tests修復了當AWS_IS_GZIPPED設置爲True時實際將文件保存到S3的另一個問題。這是多麼的犛牛。

1

此外,對於流媒體分發它的覆蓋url功能非常有用,讓rtmp://的網址,如:

import urlparse 
class VideoStorageForCloudFrontStreaming(S3BotoStorage): 
    """ 
    Use when needing rtmp:// urls for a CloudFront Streaming distribution. Will return 
    a proper CloudFront URL. 

    Subclasses must be sure to set custom_domain. 
    """ 
    def url(self, name): 
     name = urlparse.quote(self._normalize_name(self._clean_name(name))) 
     return "rtmp://%s/cfx/st/%s" % (self.custom_domain, name) 

    # handy for JW Player: 
    @Property 
    def streamer(self): 
     return "rtmp://%s/cfx/st" % (self.custom_domain)