在Heroku使用dj-static托管Django媒体文件遇404错误求助
我之前在Heroku部署Django项目时,也碰到过完全一样的媒体文件404问题!结合你的情况,核心问题其实和Heroku的特性以及Django生产环境的配置有关,下面一步步给你解决思路:
1. 先检查MEDIA相关基础配置是否完整
你贴的settings里没看到MEDIA_URL和MEDIA_ROOT的配置,这是基础中的基础,先补上:
# settings.py MEDIA_URL = '/media/' MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
同时在项目根的urls.py里,添加媒体文件的路由(注意:这只在DEBUG=True时生效,生产环境没用):
# urls.py from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 你的其他路由配置,比如path('admin/', admin.site.urls), ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
2. 重点:Heroku的临时文件系统是核心坑
Heroku的dyno使用的是临时文件系统——你通过Django Admin上传的媒体文件,只会存在当前运行的dyno里,一旦dyno重启(比如部署新版本、自动休眠唤醒、资源调整),这些文件就会彻底消失。而且当DEBUG=False时,Django本身不会在生产环境中提供媒体文件的静态服务,这就是你API访问404的根本原因。
解决办法是:把媒体文件托管到第三方云存储服务,比如Cloudinary、AWS S3,这里推荐用Cloudinary,配置起来更简单:
步骤1:安装依赖包
pip install cloudinary django-cloudinary-storage
记得把这两个包加到你的requirements.txt里,不然Heroku部署时会找不到。
步骤2:配置settings.py
在INSTALLED_APPS里添加云存储相关的app:
# settings.py INSTALLED_APPS += [ 'cloudinary', 'cloudinary_storage', ]
然后添加Cloudinary的配置(用decouple从环境变量读取敏感信息,和你现有配置风格一致):
# settings.py CLOUDINARY_STORAGE = { 'CLOUD_NAME': config('CLOUDINARY_CLOUD_NAME'), 'API_KEY': config('CLOUDINARY_API_KEY'), 'API_SECRET': config('CLOUDINARY_API_SECRET'), } # 覆盖Django默认的文件存储后端 DEFAULT_FILE_STORAGE = 'cloudinary_storage.storage.MediaCloudinaryStorage'
步骤3:在Heroku设置环境变量
登录Heroku控制台,找到你的项目,进入「Settings」→「Config Vars」,添加三个变量:
CLOUDINARY_CLOUD_NAME:你的Cloudinary账号云名称CLOUDINARY_API_KEY:你的API密钥CLOUDINARY_API_SECRET:你的API密钥密码
3. 最后检查静态文件配置
你贴的STATIC_ROOT没写完,确保它配置正确:
# settings.py STATIC_ROOT = os.path.join(BASE_DIR, 'staticfiles')
Heroku部署时会自动运行python manage.py collectstatic,把静态文件收集到STATIC_ROOT目录,再通过Whitenoise(如果配置了)提供服务,这个也别漏了。
验证配置
重新部署你的项目到Heroku,再上传一个媒体文件试试——现在文件会直接存在Cloudinary的云存储里,API访问时会返回云存储的URL,再也不会出现404了,而且dyno重启也不会丢失文件。
内容的提问来源于stack exchange,提问作者LSM

