Django-compresseur: comment écrire à S3, lire à partir de CloudFront?

<!-Je veux servir mes CSS/JS compressés de CloudFront (ils vivent sur S3), mais je ne peux pas trouver comment le faire via les réglages du compresseur dans settings.py, I have the following:

    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

malgré la COMPRESS_URL, mes fichiers sont lus depuis mon seau s3:

<link rel="stylesheet" href="https://example.s3.amazonaws.com/compressed_static/css/e0684a1d5c25.css?Signature=blahblahblah;Expires=farfuture;AWSAccessKeyId=blahblahblah" type="text/css" />

je suppose que le problème est que je veux écrire le fichier à S3, mais le lire à partir de CloudFront. Est-ce possible?

17
demandé sur Jiaaro 2011-12-31 19:04:32

5 réponses

j'ai écrit un support de stockage d'emballage autour de celui fourni par 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)
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'
33
répondu Jiaaro 2014-07-08 13:06:24

j'ai fait quelques modifications différentes à 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'

Compresseur Docs

cette solution a enregistré les fichiers localement et les a envoyés à s3. Cela me permet de compresser les fichiers hors ligne. Si vous n'êtes pas gzipping, le ci-dessus devrait fonctionner pour servir des fichiers compressés de CloudFront.

Ajout de gzip ajoute une ride:

settings.py

AWS_IS_GZIPPED = True

bien qu'il en résulte une erreur chaque fois qu'un le fichier compressible (css et js selon les stockages) a été poussé à s3 pendant le collectstatic:

AttributeError: 'cStringIO.L'objet StringO' n'a pas d'attribut 'name'

ceci était dû à une erreur bizarre liée à la compression des fichiers css/js que je ne comprends pas. Ces fichiers dont j'ai besoin localement, décompressés, et non sur s3, donc je pourrais faire éviter le problème tout à fait si je peaufine la sous-classe de stockage référencée ci-dessus (et fourni en le compresseur docs).

nouveau 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 

cela a alors tout sauvé .css et .les fichiers js (à l'exclusion des fichiers admin, que je sers non compressé depuis CloudFront) tout en poussant le reste des fichiers vers s3 (et ne prenant pas la peine de les enregistrer localement, bien que pourrait facilement ajouter le soi.local_storage._save ligne).

mais quand j'exécute compress, je veux que mon comprimé .js et .fichiers css pour être poussé à s3 donc je crée une autre sous-classe pour compresseur pour utiliser:

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 

enfin, compte tenu de ces nouvelles sous-classes, je dois mettre à jour quelques paramètres:

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

Et c'est tout ce que j'ai à dire à ce sujet.

11
répondu Matt Parrilla 2012-06-07 17:30:25
https://github.com/django/django/commit/5c954136eaef3d98d532368deec4c19cf892f664

la méthode _get_size problématique pourrait probablement être corrigée localement pour travailler autour d'elle pour les versions plus anciennes de Django.

EDIT: jetez un oeil à https://github.com/jezdez/django_compressor/issues/100 pour un travail autour de.

4
répondu jezdez 2012-05-03 17:16:19

en Fait, cela semble aussi être un problème dans django-entrepôts. Quand compresseur compare les hachages de fichiers sur S3, django-storages ne décompose pas le contenu des fichiers Gzip, mais tente de comparer les différents hachages. J'ai ouvert https://bitbucket.org/david/django-storages/pull-request/33/fix-gzip-support pour résoudre ce problème.

FWIW, il y a aussi https://bitbucket.org/david/django-storages/pull-request/32/s3boto-gzip-fix-and-associated-unit-tests ce qui corrige un autre problème de sauvegarde de fichiers à S3 lorsque AWS_IS_GZIPPED est défini à True. Ce qu'un yak qui a été.

3
répondu jezdez 2012-05-10 10:26:03

de plus, pour les distributions en streaming, il est utile de surcharger le url fonction de permettre rtmp:// url:

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)
1
répondu Chris Lawlor 2012-07-02 01:36:34