一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第24天,点击查看活动详情。
0 环境
- 编辑器:idea
- 系统版本:win10
- python版本:3.9.6
1 前期准备
后端库需要pip安装好xlsxwriter,还有一点导入时用到xlrd的时候,要注意xlrd的版本,不能超过2.xx版本,超过了出现提示不支持xlsx这类,请卸载,安装旧版本,比如我用的是1.2.0版本。
2 后端(django)
主要的重担在于后端,由于刚用django开发,时间紧,drf的精髓还么有时间去学习应用,先用fbv垫垫肚子吧。其实并不是直接发给前端的,而是先服务器保存成excel,前端直接读取那个相对于的url即可。
1 设置excel写入路径
1、settings设置写入路径
import os
from pathlib import Path
BASE_DIR = Path(__file__).resolve().parent.parent
# 路由地址
MEDIA_URL = "/upload/"
# 写入路径
MEDIA_ROOT = BASE_DIR / 'upload'
2、urls挂载 在urls中输入如下代码:
from . import settings
from django.conf.urls.static import static
urlpatterns = [
这里建一个导出功能的路由
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)
2 导出功能的代码实现
由于前端是url,不需要加相应访问方式限制。我们的需求是将标题和数据写入到一个sheet中去,首先设置文件名,并且文件名被格式化为文件名后面追加当前时间,这样的好处不会使文件名重名。标题,设置写入到服务器的位置。xlsxwriter创建一个excel,添加sheet,第一行写入相应的标题,从第二行开始写入数据,我们先要从数据库中获取数据(values里加入对应的标题名的字段),在循环中若是需要转换,具体转换,不需要的话,直接将数据传给临时列表,然后写入行,行加1,循环往复,直接最终写入结束,关闭写入。这里的写入到excel用到了yield,性能上会好很多。
还有一点:后端要配置好前端发送的url相对应的路由,不要设置get,post。
import datetime
import os
import xlsxwriter
from 某个app名 import settings
def download(request):
file_name = "download"
title = [u'a', u'b', u'c', u'd' , u'e', u'f',u'g', u'f']
filename = '{}_{}.xlsx'.format(file_name,datetime.datetime.now().strftime("%Y%m%d%H%M%S")) #指定excel文件名
# PROJECT_HOME = os.path.dirname(os.path.abspath(__file__))
DOWNLOAD_DIR = os.path.join(settings.MEDIA_ROOT, "excel") #指定存放文件的目录
file_path = "{}/{}".format(DOWNLOAD_DIR,filename)
workbook = xlsxwriter.Workbook(file_path) # 这里我用的xlsxwriter导出文件
table = workbook.add_worksheet()
table.write_row('A1', title)
tmp_line = 2
list_obj = 对应model.objects.all().values("id","xx","xx","xx","xx","xx","xx")
# print("list_obj ==>", list_obj)
for l in list_obj:
# tmp = [] #todo 指定每一行的数据
tmp = []
try:
在这里对需要转换的数据进行改造,存入到tmp中,
比如需要读取其他model,可以用filter + values_list得到一个元组,当然还有其他更好的方式
except Exception:
pass
table.write_row("A{}".format(tmp_line), tmp) #自行去查一下write_row方法
tmp_line += 1
workbook.close()
response = StreamingHttpResponse(file_iterator(file_path))
response['Content-Type'] = 'application/octet-stream'
# 适应 中文.xlsx
response['Content-Disposition'] = "attachment; filename*=utf-8''{}".format(escape_uri_path(file_name+".xlsx"))
# response['Content-Disposition'] = "attachment;filename={0}".format(filename)
return response
def file_iterator(file_name):
with open(file_name, 'rb') as f: # 切记open打开文件的方式
while True:
c = f.read()
if c:
yield c
else:
break
5 前后端联调
当我们点击前端的导出功能,相应的后端会在这个upload/excel目录生成一个带有时间的xlsx。
6 总结
前端点击了导出按钮,触发了a标签,发送了一个URL给后端,后端设置了相应的路由,我们在相应的路由对应了相应的方法,在这个方法,写出excel用的是xlsxwriter,因为它可以满足大数据量。重回方法里,一个表格是不是要有文件名,文件薄又分为头和数据(字段的中文标题和字段的数据库数据),需要提供数据库相关字段的数组(标题名数组,数据数组),因为要先保存到服务器上,需要先设置保存的路径,创建excel,将标题名数组写入到excel中,若是数据数组需要转换,先循环转化,在行写入到excel,直接循环结束,关闭写操作,保存到服务器上指定的路径。设置响应Content-Type和Content-Disposition,然后返回给前端。