如何在heroku上设置django-compressor,离线压缩到S3
Posted
技术标签:
【中文标题】如何在heroku上设置django-compressor,离线压缩到S3【英文标题】:How to setup django-compressor on heroku, offline compression to S3 【发布时间】:2014-01-23 16:59:48 【问题描述】:我遵循了在 SO 和不同博客中找到的每一个 QA 建议,在我的开发机器上一切正常,而在 heroku 上却没有。
这是我的设置:
DEFAULT_FILE_STORAGE = 'arena.utils.MediaRootS3BotoStorage' # media files
# storage
AWS_ACCESS_KEY_ID = os.environ.get('AWS_ACCESS_KEY_ID')
AWS_SECRET_ACCESS_KEY = os.environ.get('AWS_SECRET_ACCESS_KEY')
AWS_STORAGE_BUCKET_NAME = os.environ.get('AWS_STORAGE_BUCKET_NAME')
AWS_PRELOAD_METADATA = True # necessary to fix manage.py collectstatic command to only upload changed files instead of all files
S3_URL = 'https://%s.s3.amazonaws.com' % AWS_STORAGE_BUCKET_NAME
MEDIA_URL = S3_URL + '/media/'
STATIC_URL = S3_URL + '/static/'
ADMIN_MEDIA_PREFIX = STATIC_URL + 'admin/'
COMPRESS_URL = STATIC_URL
COMPRESS_OFFLINE = True
COMPRESS_STORAGE = 'utils.CachedS3BotoStorage'
STATICFILES_STORAGE = COMPRESS_STORAGE
当我运行 collectstatic/compress 一切正常时,我看到文件被收集到 S3 并放在适当的位置。我看到了清单文件。
使用压缩器标签加载任何页面,显示错误OfflineGenerationError: You have offline compression enabled but key "d2a53169c44dec41ce3ee7da19b2b9d4" is missing from offline manifest.
再次运行python manage.py compress
无法解决任何问题。当我检查清单文件时,它寻找的密钥确实不存在。
这里出了什么问题?
我已经检查过的问题:
How to configure django-compressor and django-staticfiles with Amazon's S3?
Django Compressor with S3 URL Heroku
Configuring django-compressor with remote storage (django-storage - amazon s3)
【问题讨论】:
我认为这与您向模板中添加较少文件的方式有关。我在开发中动态添加了它们,这很好。当您使用manage.py compress
命令时,它看不到动态添加的,也无法压缩这些。
@JacobValenta 我在模板中没有更少的文件。我有一个编译器会在 Pycharm 中的每次保存时自动运行。 manage.py compress
在 heroku 上工作,不会抛出任何错误,但是当我尝试加载页面时,每次都会遇到相同的错误。好像它无法读取清单什么的
【参考方案1】:
就我而言,我的配置非常相似,并且我成功使用了 2 年多的压缩器。
settings.py
COMPRESS_STORAGE = 'MyAwesomeApp.app.CachedS3BotoStorage.CachedS3BotoStorage'
AWS_ACCESS_KEY_ID = '#######'
AWS_SECRET_ACCESS_KEY = '########################+#########+BqoQ'
AWS_STORAGE_BUCKET_NAME = 'myAmazonS3cdn.myawesomewebsite.com'
AWS_S3_SECURE_URLS = False
AWS_QUERYSTRING_AUTH = False
COMPRESS_ROOT = 'MyAwesomeApp/static'
STATIC_ROOT = 'MyAwesomeApp/static/javascript'
COMPRESS_OUTPUT_DIR = 'compressed'
STATICFILES_STORAGE = COMPRESS_STORAGE
STATIC_URL = "http://myAmazonS3cdn.myawesomewebsite.com/"
COMPRESS_URL = STATIC_URL
COMPRESS_ENABLED = True
CachedS3BotoStorage.py
from django.core.files.storage import get_storage_class
from storages.backends.s3boto import S3BotoStorage
from django.core.files.base import File
class CachedS3BotoStorage(S3BotoStorage):
"""
S3 storage backend that saves the files locally, too.
"""
def __init__(self, *args, **kwargs):
super(CachedS3BotoStorage, self).__init__(*args, **kwargs)
self.local_storage = get_storage_class("compressor.storage.CompressorFileStorage")()
def save(self, name, content):
name = super(CachedS3BotoStorage, self).save(name, content)
self.local_storage._save(name, content)
return name
我在本地运行 python managep.py compress,并在我的静态文件目录中生成清单。 Heroku 只处理集合并将最新的清单版本传送到我的 cdn。
问候,
【讨论】:
我遇到了一个问题,添加AWS_QUERYSTRING_AUTH = False
终于让它工作了。因为签名会随着时间而改变。
没有很好的文档记录,但在使用 AWS_QUERYSTRING_AUTH 参数之前,我遇到了“请求已过期”错误。
是的,我之前所做的是AWS_QUERYSTRING_EXPIRE = 63115200
。这将请求到期设置为从现在起 2 年。但即使这样也不是最好的解决方案。【参考方案2】:
我用几行完成了上述解决方案,以解决在 Amazon S3 中创建许多(多个)manifest_%.json 的问题
在setting.py中:
STATICFILES_STORAGE = 'your_package.s3utils.CachedS3BotoStorage'
在 s3utils.py 中:
from storages.backends.s3boto import S3BotoStorage
from django.core.files.storage import get_storage_class
class CachedS3BotoStorage(S3BotoStorage):
"""
S3 storage backend that saves the files locally, too.
"""
location = 'static'
def __init__(self, *args, **kwargs):
super(CachedS3BotoStorage, self).__init__(*args, **kwargs)
self.local_storage = get_storage_class(
"compressor.storage.CompressorFileStorage")()
def url(self, name):
"""
Fix problem images admin Django S3 images
"""
url = super(CachedS3BotoStorage, self).url(name)
if name.endswith('/') and not url.endswith('/'):
url += '/'
return url
def save(self, name, content):
name = super(CachedS3BotoStorage, self).save(name, content)
self.local_storage._save(name, content)
return name
# HERE is secret to dont generating multiple manifest.json and to delete manifest.json in Amazon S3
def get_available_name(self, name):
if self.exists(name):
self.delete(name)
return name
【讨论】:
【参考方案3】:我找到了一个包含 post_compile 钩子的 git 存储库来解决这个问题。它在 Heroku 构建 Django 应用程序后运行 compress(如果您在压缩器设置中需要更少,还安装 lessc
)。
https://github.com/nigma/heroku-django-cookbook
【讨论】:
以上是关于如何在heroku上设置django-compressor,离线压缩到S3的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 MongoLab 在 Heroku 上设置 MongoDB 数据库?
如何在heroku上设置django-compressor,离线压缩到S3
如何在 Heroku 上为 Django 应用程序设置数据库?