IBM Cloud Foundry部署Django DEBUG=False模式媒体文件加载异常
当前Cloud Foundry部署规则下,仅/static/*路径的请求会转发到staticfile_buildpack提供的Nginx静态服务实例,运行Django应用的主实例在DEBUG=False模式下默认不会兜底服务任何静态、媒体资源。现有配置中MEDIA_URL = '/media/'生成的资源路径完全不在Nginx的路由覆盖范围内,自然会出现JS、CSS等静态资源正常加载,仅媒体资源404的问题。
这个方案完全规避了之前提到的三个思路的缺陷,不需要改模板标签、不需要自定义Nginx配置、不需要开启Django不安全的静态服务模式,同时完全不影响本地DEBUG开发的原有逻辑。
- 调整
settings.py配置,利用Cloud Foundry部署时自动注入的环境变量区分生产/开发环境的媒体路径:
如果媒体资源包含代码内置的固定文件(比如预置的课程封面图),需要把存放这些文件的目录加入import os # 原有基础静态配置保留 STATIC_URL = '/static/' STATIC_ROOT = os.path.join(BASE_DIR, 'static') MEDIA_ROOT = os.path.join(STATIC_ROOT, 'media') # 核心配置:CF生产环境适配Nginx路由,开发环境保持原有路径 if os.getenv('VCAP_APPLICATION'): # Cloud Foundry部署时会自动注入VCAP_APPLICATION环境变量,本地开发无此变量 MEDIA_URL = '/static/media/' else: MEDIA_URL = '/media/'STATICFILES_DIRS,保证python3 manage.py collectstatic命令执行时能把这些文件同步到STATIC_ROOT,部署到Nginx实例后可正常访问:STATICFILES_DIRS = [ os.path.join(BASE_DIR, 'course_images'), # 替换为存放固定媒体资源的实际目录 ]注意:Cloud Foundry应用实例的本地文件系统是临时存储,重启、重新部署后所有运行时写入的文件都会被清空。如果
course.image是后台运营上传的用户生成内容,不要存在本地路径,必须对接对象存储服务持久化。 - 调整
urls.py逻辑,仅在开发DEBUG模式下让Django兜底服务媒体文件,生产环境完全走Nginx处理静态资源:from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 原有业务路由保持不变 ] if settings.DEBUG: urlpatterns += static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
配置完成后,模板里的{{ course.image.url }}不需要做任何修改,Django的ImageField会自动根据当前环境的MEDIA_URL拼接正确的访问路径:本地开发时生成/media/course_images/xxx路径由Django服务,生产环境生成/static/media/course_images/xxx路径由Nginx服务,两边都可以正常访问。
如果不想做环境判断,也可以直接调整manifest.yml的路由规则,给Nginx静态服务实例新增一条/media路径的转发规则:
applications: - name: onlinecourse routes: - route: $HOST.$DOMAIN memory: 128M buildpack: python_buildpack - name: onlinecourse-nginx routes: - route: $HOST.$DOMAIN/static - route: $HOST.$DOMAIN/media # 新增:将/media路径请求也转发到Nginx实例 memory: 64M buildpack: staticfile_buildpack
这个方案需要注意:staticfile_buildpack默认以应用根目录作为Nginx站点根目录,需要保证部署到Nginx实例的代码根目录下存在media目录且包含对应媒体资源,否则依然会返回404,整体配置成本比前一个方案更高。
内容的提问来源于stack exchange,提问作者ILia Gridnev

