任俊达
Articles17
Tags9
Categories0
Djano实现下载文件功能 (你没事吧?😁)

Djano实现下载文件功能 (你没事吧?😁)

一、简单介绍文件下载

最简单的文件下载功能的实现
1、将文件流放入HttpResponse对象即可,如

1
2
3
4
5
def file_download(request):
# do something...
with open('file_name.txt') as f:
c = f.read()
return HttpResponse(c)

这种方式简单粗暴,适合小文件的下载,但如果这个文件非常大,这种方式会占用大量的内存,甚至导致服务器崩溃

更合理的文件下载功能

Django的HttpResponse对象允许将迭代器作为传入参数,将上面代码中的传入参数c换成一个迭代器,便可以将上述下载功能优化为对大小文件均适合;而Django更进一步,推荐使StreamingHttpResponse对象取代HttpResponse对象,StreamingHttpResponse对象用于将文件流发送给浏览器,与HttpResponse对象非常相似,对于文件下载功能,使用StreamingHttpResponse对象更合理。

因此,更加合理的文件下载功能,应该先写一个迭代器,用于处理文件,然后将这个迭代器作为参数传递给StreaminghttpResponse对象

HttpResponse会直接使用迭代器对象,将迭代器对象的内容存储城字符串,然后返回给客户端,同时释放内存。可以当文件变大看出这是一个非常耗费时间和内存的过程。
StreamingHttpResponse这是一种非常省时省内存的方法。但是因为StreamingHttpResponse的文件传输过程持续在整个response的过程中,所以这有可能会降低服务器的性能。

代码块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from django.http import StreamingHttpResponse 
def file_download(request):

def file_iterator(file_name, chunk_size=512):
with open(file_name) as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break

the_file_name = "file_name.txt"
response = StreamingHttpResponse(file_iterator(the_file_name))
return response

结合项目使用完整示例代码如下,根据自己需求整改

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# 导入相关依赖文件
import xlsxwriter
from django.http import StreamingHttpResponse, JsonResponse, FileResponse
from django.http import HttpResponse
from django.urls import reverse_lazy
from django.utils.encoding import escape_uri_path

def export_data(request):
filename = '{}.xlsx'.format('人员信息')
if request.method == 'GET':
try:
response = StreamingHttpResponse(file_iterator(filename))
# 以流的形式下载文件,这样可以实现任意格式的文件下载
response['Content-Type'] = 'application/octet-stream'
response["Content-Disposition"] = "attachment; filename*=UTF-8''{}".format(escape_uri_path(filename))
except:
return HttpResponse("生成文件失败")
return response

if request.method == 'POST':
# 表头,为了方便直接再代码中, 平时我们为了规范代码一般写在配置文件中
ping_header = {
'姓名': '1',
'性别': '2',
'年龄': '3',
'居住地址': '4',
}
# 先把数据写死,根据需求自己去数据库查询
data = [
{'name': '刘备', 'sex': '男', 'age': 18, 'addr': '荆州'},
{'name': '关羽', 'sex': '女', 'age': 10, 'addr': '荆州'},
{'name': '张飞', 'sex': '男', 'age': 10, 'addr': '荆州'},
{'name': '黄宇恒', 'sex': '其他', 'age': 99, 'addr': '江西省南昌市进贤县'},
]
workbook = xlsxwriter.Workbook(filename) # 建立文件
worksheet = workbook.add_worksheet("人员信息统计")
head_style = workbook.add_format(xlsx_style(bold=True, bg_color='#95B3D7'))
body_style = workbook.add_format(xlsx_style())
_header = ping_header
for index, value in enumerate(_header):
worksheet.write(0, index + 4, value, head_style)
n_index = 1
if len(data) > 0:
for item in data:
worksheet.write(n_index, 4, item['name'] if item.get('name') else '', body_style)
worksheet.write(n_index, 5, item['sex'] if item.get('sex') else '', body_style)
worksheet.write(n_index, 6, item['age'] if item.get('age') else '', body_style)
worksheet.write(n_index, 7, item['addr'] if item.get('addr') else '', body_style)

n_index += 1

# 将生成的excel放入byte流给response
workbook.close()
url = reverse_lazy('app_name:路由名称') # 将下载路由返回前端,前端通过请求返回的路由实现文件下载
return JsonResponse({'redirect': url, 'code': 0})


def file_iterator(file_path, chunk_size=512):
"""
文件生成器,防止文件过大,导致内存溢出
:param file_path: 文件路径
:param chunk_size: 块大小
:return: 生成器
"""
with open(file_path, mode='rb') as f:
while True:
c = f.read(chunk_size)
if c:
yield c
else:
break


# xlsxwriter的样式公有函数
def xlsx_style(**kwargs):
style = {
'bold': kwargs.get('bold', False), # 加粗
'font_name': kwargs.get('font_name', 'SimSun'), # 字体类型,默认宋体
'font_size': kwargs.get('font_size', 10), # 字体大小,默认12
'font_color': kwargs.get('font_color', '#000000'), # 字体颜色,黑色
'align': kwargs.get('align', 'center'), # 默认水平居中
'valign': kwargs.get('valign', 'vcenter'), # 默认垂直居中
'text_wrap': kwargs.get('text_wrap', True), # 默认自动换行
'top': kwargs.get('top', 1), # 上边界,线条宽度
'bottom': kwargs.get('bottom', 1), # 边界
'left': kwargs.get('left', 1), # 边界
'right': kwargs.get('right', 1), # 边界
'bg_color': kwargs.get('bg_color', '#FFFFFF'), # 背景颜色,白色
# 其他类型设置格式可以接着写
}
return style

文件下载完成后样式展示

except

Author:任俊达
Link:https://renjunda.ren/lxb/6c2328a8.html
版权声明:本文采用 CC BY-NC-SA 3.0 CN 协议进行许可
×