Django结合Nginx实现文件上传下载时文件无法访问问题求助
问题根因与解决方案
1. 上传逻辑错误(核心问题,导致文件未实际存储)
request.FILES.items()返回的元组结构是(表单字段名, 实际文件对象),你当前代码把file[0](字段名字符串)传给了FileField,仅保存了文件名,没有实际写入文件内容。
修复后的上传代码:
def uploadChallengeFile(request): latestChallenge = Challenge.objects.last() # 遍历取实际文件对象,而非字段名 for field_name, file_obj in request.FILES.items(): file_model = File(challenge=latestChallenge, file=file_obj) file_model.save() data = {"data": [True]} return JsonResponse(data, safe=False)
2. FileField路径配置重复
FileField的upload_to参数会自动拼接在MEDIA_ROOT之后,你当前MEDIA_ROOT已经是BASE_DIR/media,再设置upload_to="media/"会导致文件实际存储路径为BASE_DIR/media/media/xxx.csv,和访问路径不匹配。
修复方式:
调整模型upload_to参数,不需要子目录就留空:
file = models.FileField(default="", upload_to="") # 文件直接存在MEDIA_ROOT根目录
3. Settings配置错误
你把media目录加入了STATICFILES_DIRS,该配置仅用于管理项目静态资源(css/js等),和用户上传的动态media文件无关,多余配置会引发路径冲突。
修复后的配置:
STATICFILES_DIRS = ( os.path.join(BASE_DIR, 'server', 'static'), ) MEDIA_ROOT = os.path.join(BASE_DIR, 'media') MEDIA_URL = '/media/' # 开头加斜杠,避免相对路径错误
4. 下载逻辑错误
代码中用open(file.url)读取文件是错误的:file.url是浏览器访问的URL路径,不是本地文件的物理路径,必须用file.path获取本地绝对路径。另外filter返回的是查询集,不能直接用于外键过滤。
修复后的下载代码:
from django.http import FileResponse import os def downloadFile(request, challenge_id): # 先获取单个challenge对象 challenge = Challenge.objects.get(challenge_id=challenge_id) file_obj = File.objects.get(challenge=challenge) # 用FileResponse处理文件读取,性能更优,避免大文件内存溢出 response = FileResponse(open(file_obj.file.path, 'rb'), content_type='text/csv') response['Content-Disposition'] = f'attachment; filename={os.path.basename(file_obj.file.name)}' return response
5. 路由配置补充
- 开发环境:不需要Nginx,直接在项目根
urls.py中添加media路由即可直接访问上传文件:
from django.conf import settings from django.conf.urls.static import static urlpatterns = [ # 原有其他路由 ] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
- 生产环境:必须配置Nginx代理
/media/路径到MEDIA_ROOT目录,示例配置片段:
location /media/ { alias /你的项目实际绝对路径/media/; expires 30d; }
内容的提问来源于stack exchange,提问作者undefined1010101
相关产品推荐
相关产品推荐

