如何在Django中将字节转换为用户可下载文件?含JS实现方案
Django 数据库字节数据转可下载文件实现方案
方案一:后端直接返回下载响应
这种方式无需前端额外处理,后端构造响应头让浏览器直接触发下载,是最常用的实现方式。
实现步骤
- 假设数据模型(根据你的实际模型调整):
from django.db import models class StoredFile(models.Model): filename = models.CharField(max_length=255) file_bytes = models.BinaryField() content_type = models.CharField(max_length=100) # 例如 'image/png'、'application/pdf' file_size = models.IntegerField()
- 编写视图函数:
from django.http import HttpResponse from django.utils.http import urlquote def download_file(request, file_id): # 从数据库获取文件信息 stored_file = StoredFile.objects.get(id=file_id) # 构造响应,传入字节数据和正确的内容类型 response = HttpResponse(stored_file.file_bytes, content_type=stored_file.content_type) # 设置下载头:attachment 强制浏览器下载,filename 指定保存的文件名 # 使用 urlquote 处理含特殊字符的文件名 response['Content-Disposition'] = f'attachment; filename="{urlquote(stored_file.filename)}"' # 可选:设置文件大小,帮助浏览器显示下载进度 response['Content-Length'] = str(stored_file.file_size) return response
- 配置路由:
在项目的urls.py中添加路由:
from django.urls import path from .views import download_file urlpatterns = [ # 其他路由... path('download/<int:file_id>/', download_file, name='download_file'), ]
- 前端使用:
直接通过链接触发下载:
<a href="{% url 'download_file' file_id=1 %}">下载文件</a>
方案二:前端JavaScript处理下载
如果需要前端做前置逻辑(比如下载确认、批量操作),可以让后端返回字节数据,前端通过JS生成下载链接。
实现步骤
- 后端接口视图:
from django.http import HttpResponse from django.views.decorators.csrf import csrf_exempt @csrf_exempt # POST请求需要,GET请求可省略 def get_file_bytes(request, file_id): stored_file = StoredFile.objects.get(id=file_id) # 返回字节数据,同时在响应头传递文件名和内容类型 response = HttpResponse(stored_file.file_bytes, content_type=stored_file.content_type) response['X-Filename'] = stored_file.filename response['X-Content-Type'] = stored_file.content_type return response
- 前端JavaScript代码:
async function triggerDownload(fileId) { try { const res = await fetch(`/get-file-bytes/${fileId}/`); if (!res.ok) throw new Error('文件请求失败'); // 从响应头读取文件名和内容类型 const filename = res.headers.get('X-Filename'); const contentType = res.headers.get('X-Content-Type'); // 将响应转为Blob对象 const blob = await res.blob(); // 创建临时下载链接并触发点击 const downloadUrl = URL.createObjectURL(blob); const aTag = document.createElement('a'); aTag.href = downloadUrl; aTag.download = filename; document.body.appendChild(aTag); aTag.click(); // 清理临时资源 document.body.removeChild(aTag); URL.revokeObjectURL(downloadUrl); } catch (err) { console.error('下载错误:', err); alert('文件下载失败,请重试'); } }
- 前端调用示例:
<button onclick="triggerDownload(1)">点击下载</button>
注意事项
- 处理大文件时,推荐使用
FileResponse替代HttpResponse,它支持流式传输,避免内存占用过高:
from django.http import FileResponse from io import BytesIO def download_large_file(request, file_id): stored_file = StoredFile.objects.get(id=file_id) file_stream = BytesIO(stored_file.file_bytes) response = FileResponse(file_stream, content_type=stored_file.content_type) response['Content-Disposition'] = f'attachment; filename="{urlquote(stored_file.filename)}"' return response
- 文件名包含中文或特殊字符时,必须用
urlquote编码,避免浏览器解析错误。
内容的提问来源于stack exchange,提问作者user19661285
相关产品推荐
相关产品推荐

