Dan*_*nra 11 python deployment django amazon-s3 django-storage
我有一个在Heroku上运行的Django应用程序.为了存储和提供我的静态文件,我将django-storage与我的S3存储桶以及标准的Django一起使用ManifestFilesMixin.我也在使用django-pipeline.
在代码中:
from django.contrib.staticfiles.storage import ManifestFilesMixin
from storages.backends.s3boto import S3BotoStorage
from pipeline.storage import PipelineMixin
class S3PipelineManifestStorage(PipelineMixin, ManifestFilesMixin, S3BotoStorage):
pass
Run Code Online (Sandbox Code Playgroud)
设置有效,但staticfiles.json清单也存储在S3上.我可以看到两个问题:
我的应用程序的存储实例必须staticfiles.json从S3 获取,而不是仅从本地文件系统获取它.这在性能方面毫无意义.清单文件的唯一使用者是服务器应用程序本身,因此它也可以存储在本地文件系统而不是远程.
我不确定这个问题有多重要,因为我想(或希望)服务器应用程序在读取一次后缓存该文件.
清单文件是在部署期间编写的collectstatic,因此,如果任何已运行的服务器应用程序版本的实例在部署完成之前从S3读取清单文件并且新的slug接管,则它们可能会获取错误的静态文件 -只应该为新的slug实例提供服务.
请注意,特别是在Heroku上,新的应用程序实例可能会动态弹出,因此即使应用程序确实缓存了清单文件,它的第一次获取也可能是在部署新的slug期间.
所描述的场景特定于Heroku,但我想其他环境会出现类似的问题.
显而易见的解决方案是将清单文件存储在本地文件系统上.每个slug都有自己的清单文件,性能最佳,并且不会有如上所述的任何部署比赛.
可能吗?
前段时间我读了这篇文章,我认为这篇文章很适合你.
在最后一段中存在以下内容:
staticfiles.json在哪里?
默认情况下
staticfiles.json将驻留在STATIC_ROOT收集所有静态文件的目录中.
我们将所有静态资产托管在S3存储桶上,这意味着staticfiles.json默认情况下最终会同步到S3.但是,我们希望它存在于代码目录中,以便我们可以打包并将其发送到每个应用服务器.由于这一结果,
ManifestStaticFilesStorage将寻找staticfiles.json在STATIC_ROOT以阅读的映射.我们不得不覆盖这种行为,所以我们将子类化ManifestStaticFilesStorage:Run Code Online (Sandbox Code Playgroud)from django.contrib.staticfiles.storage import ManifestStaticFilesStorage from django.conf import settings class KoganManifestStaticFilesStorage(ManifestStaticFilesStorage): def read_manifest(self): """ Looks up staticfiles.json in Project directory """ manifest_location = os.path.abspath( os.path.join(settings.PROJECT_ROOT, self.manifest_name) ) try: with open(manifest_location) as manifest: return manifest.read().decode('utf-8') except IOError: return None通过上述更改,Django静态模板标记现在将读取
staticfiles.json项目根目录中驻留的映射.
没有自己使用它,所以如果有帮助请告诉我!
@John 和Kogan的回答很好,但没有提供完成这项工作所需的完整代码:正如@Danra 提到的,您还需要将 保存staticfiles.json在源文件夹中才能完成这项工作。这是我根据上述答案创建的代码:
import json
import os
from django.conf import settings
from django.core.files.base import ContentFile
from django.core.files.storage import FileSystemStorage
from whitenoise.storage import CompressedManifestStaticFilesStorage
# or if you don't use WhiteNoiseMiddlware:
# from django.contrib.staticfiles.storage import ManifestStaticFilesStorage
class LocalManifestStaticFilesStorage(CompressedManifestStaticFilesStorage):
"""
Saves and looks up staticfiles.json in Project directory
"""
manifest_location = os.path.abspath(settings.BASE_DIR) # or settings.PROJECT_ROOT depending on how you've set it up in your settings file.
manifest_storage = FileSystemStorage(location=manifest_location)
def read_manifest(self):
try:
with self.manifest_storage.open(self.manifest_name) as manifest:
return manifest.read().decode('utf-8')
except IOError:
return None
def save_manifest(self):
payload = {'paths': self.hashed_files, 'version': self.manifest_version}
if self.manifest_storage.exists(self.manifest_name):
self.manifest_storage.delete(self.manifest_name)
contents = json.dumps(payload).encode('utf-8')
self.manifest_storage._save(self.manifest_name, ContentFile(contents))
Run Code Online (Sandbox Code Playgroud)
现在你可以使用LocalManifestStaticFilesStorage你的STATICFILES_STORAGE. 运行时manage.py collectstatic,您的清单将保存到您的根项目文件夹中,Django 将在提供内容时在那里寻找它。
如果您的部署包含多个虚拟机,请确保collectstatic只运行一次并将staticfiles.json文件复制到部署中的所有计算机作为代码部署的一部分。这样做的好处是,即使有些机器还没有最新的更新,它们仍然会提供正确的内容(对应于当前版本的代码),因此您可以在有问题的地方执行逐步部署混合状态。