You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Django项目实现客户端从服务端下载pdf、docx等文件的问题求解

Django 服务端文件下载功能实现方案

问题根源

webbrowser.open() 是运行在Django服务端进程中的Python接口,仅能操作服务器本地的浏览器资源,完全无法触达访问应用的客户端用户设备,因此不能用于实现客户端下载功能,必须通过Django的HTTP响应机制实现。

标准实现步骤

1. 编写下载视图函数

适用于100M以下的小文件场景,直接返回FileResponse即可:

import os
from django.conf import settings
from django.http import FileResponse, Http404

def download_file(request, filename):
    # 拼接服务器上的文件存储路径,建议将公开下载文件放在MEDIA_ROOT下的指定目录
    file_base_dir = os.path.join(settings.MEDIA_ROOT, 'internal_documents')
    file_path = os.path.abspath(os.path.join(file_base_dir, filename))
    
    # 路径校验,防止路径遍历攻击
    if not file_path.startswith(file_base_dir) or not os.path.exists(file_path):
        raise Http404("请求的文件不存在")
    
    # 构造下载响应
    response = FileResponse(open(file_path, 'rb'))
    # 设置响应类型为二进制流,触发下载而非浏览器直接打开
    response['Content-Type'] = 'application/octet-stream'
    # 处理中文文件名乱码问题
    encoded_filename = filename.encode('utf-8').decode('latin1')
    response['Content-Disposition'] = f'attachment;filename="{encoded_filename}"'
    return response

2. 绑定路由

在应用的urls.py中添加下载路由:

from django.urls import path
from . import views

urlpatterns = [
    # 其他现有路由
    path('internal/download/<str:filename>/', views.download_file, name='internal_download'),
]

3. 前端调用

在页面中直接通过a标签指向下载路由即可,用户点击后会自动触发客户端本地的下载弹窗:

<a href="{% url 'internal_download' filename='员工手册.pdf' %}">下载员工手册</a>
<a href="{% url 'internal_download' filename='项目规范.docx' %}">下载项目规范</a>

大文件优化方案

如果需要下载超过100M的大文件,建议使用StreamingHttpResponse分片传输,避免占用服务端过多内存:

from django.http import StreamingHttpResponse

def download_large_file(request, filename):
    file_base_dir = os.path.join(settings.MEDIA_ROOT, 'internal_documents')
    file_path = os.path.abspath(os.path.join(file_base_dir, filename))
    
    if not file_path.startswith(file_base_dir) or not os.path.exists(file_path):
        raise Http404("请求的文件不存在")
    
    # 分片读取文件迭代器
    def file_iterator(chunk_size=8192):
        with open(file_path, 'rb') as f:
            while chunk := f.read(chunk_size):
                yield chunk
    
    response = StreamingHttpResponse(file_iterator())
    response['Content-Type'] = 'application/octet-stream'
    encoded_filename = filename.encode('utf-8').decode('latin1')
    response['Content-Disposition'] = f'attachment;filename="{encoded_filename}"'
    return response

注意事项

  • 若需要限制仅内部员工访问,可直接在视图函数中添加登录校验、权限校验逻辑即可
  • 不要省略路径校验步骤,避免攻击者构造../类的特殊路径下载服务器上的敏感文件
  • 若文件存储在对象存储等非本地路径,可修改读取逻辑直接从对象存储接口获取文件流返回即可,无需落地到服务器本地磁盘

内容的提问来源于stack exchange,提问作者Jfka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.18 23:57:03