Docker部署Django应用后download属性失效,如何解决文件下载异常?
Django Docker部署后文件下载失效的解决方法
问题根源
本地开发时Django自带的服务器会自动处理媒体文件请求,但生产环境用gunicorn作为WSGI服务器时,默认不负责静态/媒体文件的路由;同时你的路径配置错误,把容器内部的绝对路径传给了前端,导致Web服务器无法找到目标文件,最终返回当前网页副本。
修复步骤
1. 修正Django媒体文件核心配置
在项目的settings.py中,确保正确设置媒体文件的存储根目录和访问URL:
import os BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__))) # 媒体文件配置 MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/'
2. 修正视图中的路径生成逻辑
在main/views.py中,使用Django配置的MEDIA_URL生成前端可访问的路径,而非容器内部的/app路径:
from django.conf import settings import os # 生成文件名和相对路径 report_filename = f"{request.user.username}{now.hour}{now.minute}{now.second}.txt" report_relative_path = f"Reports/{request.user.username}/{report_filename}" # 生成Web可访问的完整URL path_to_report = f"{settings.MEDIA_URL}{report_relative_path}" # 确保存储目录存在,避免写入失败 full_file_path = os.path.join(settings.MEDIA_ROOT, report_relative_path) os.makedirs(os.path.dirname(full_file_path), exist_ok=True) # 此处写入文件内容到full_file_path # 传递正确路径到模板 return render(request, "main/result.html", { "dic_files": dic_files, "nbr": len(files), "dic_small": dic_small, "dic_projects": dic_projects, "path_to_report": path_to_report })
3. 修正模板中的下载链接
在main/result.html中,直接使用视图传递的路径,无需额外添加斜杠:
<a href="{{ path_to_report }}" download> <button class="btn btn-success" name="rapport" value="rapport"> Télécharger votre rapport</button> </a>
4. 处理生产环境媒体文件服务
gunicorn不负责静态/媒体文件的请求处理,需选以下方案之一配置:
方案A:用WhiteNoise处理媒体文件
适合小型应用,无需额外反向代理:
- 安装WhiteNoise:
pip install whitenoise
- 在
settings.py中修改配置:
INSTALLED_APPS = [ 'whitenoise.runserver_nostatic', 'django.contrib.staticfiles', # 其他应用... ] MIDDLEWARE = [ 'django.middleware.security.SecurityMiddleware', 'whitenoise.middleware.WhiteNoiseMiddleware', # 其他中间件... ] # 允许WhiteNoise处理媒体文件 WHITENOISE_USE_FINDERS = True WHITENOISE_MEDIA_PREFIX = '/media/'
方案B:用Nginx反向代理处理媒体文件
适合流量较大的应用,配置Nginx直接接管媒体文件请求:
server { listen 80; server_name your-domain.com; # 直接处理媒体文件请求 location /media/ { alias /app/media/; # 容器内的媒体目录路径 expires 30d; } # 其他请求转发给gunicorn location / { proxy_pass http://gunicorn:8000; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }
5. 优化Docker配置
在Dockerfile中添加媒体目录权限设置,确保Django有写入权限:
# ... 现有内容 ... RUN python manage.py collectstatic --no-input # 创建媒体目录并设置权限 RUN mkdir -p media/Reports && chmod -R 755 media ENTRYPOINT ["gunicorn", "myteam.wsgi:application", "--bind=0.0.0.0:8000", "--workers=4", "--timeout=300", "--log-level=debug"]
另外建议将数据库迁移命令从镜像构建阶段移到容器启动时,避免镜像绑定特定数据库状态:
创建entrypoint.sh脚本:
#!/bin/bash python manage.py makemigrations python manage.py migrate exec gunicorn myteam.wsgi:application --bind=0.0.0.0:8000 --workers=4 --timeout=300 --log-level=debug
修改Dockerfile:
# ... 现有内容 ... RUN chmod +x entrypoint.sh ENTRYPOINT ["./entrypoint.sh"]
内容的提问来源于stack exchange,提问作者thomas
相关产品推荐
相关产品推荐

