openpyxl结合django框架操作Excel数据流实践

357 阅读2分钟

上一篇向 大家展示了如何利用openpyxl库和临时文件将表格文件数据流化,数据流的主要目的是放于网络 展示,本篇向大家展示如何在网站使用这个数据流。

此次操作使用的网络框架是django,如果对其基本配置还不了解,也没关系,和其他的框架并不是很大区别,可以参考我去年写的一些文章。

数据流转换文件

源数据

因为简单demo,所以没有设置数据库,在这里直接读取本地文件转换为二进制,下面的file_content就代表了这个文件。

with open('static/data.xlsx', 'rb') as f:  
    file_content = f.read()

响应头

headers = {  
    'Content-Type': 'application/octet-stream',  
    'Content-Disposition': 'attachment;filename=data.xlsx'  
}

配置响应头以后,可以在下载的时候对文件带上文件名。

基础响应方式HttpResponse

利用django中的HttpResponse响应二进制数据,访问对应的路由,可以直接获得文件下载。

resp = HttpResponse(content=file_content, headers=headers)

image.png

打开文件也是个正常的文件。

文件响应方式FileResponse

借助上一篇提到的NamedTemporaryFile,我们将其传递出去,设置了文件名参数后,不需要额外填写响应头。

tmp = NamedTemporaryFile(delete=False)  
tmp.write(file_content)  
tmp.seek(0)  
  
resp = FileResponse(tmp, filename='data2.xlsx')

这里不能用前文所述的上下文管理器,对于网站来说,在他响应的过程中,文件会被关闭。对于上面的临时文件而言,这是一个糟糕的特性,意味着我们既不能手动删除,也不能用管理器删除。长期使用这种方式会导致临时文件堆积。建议还是用基础响应返回。

操作excel数据流

结合前两篇文章的操作方法,在这里实现一次Excel文件的修改和响应,完整的django视图函数如下:

def download(request):

    with open('static/data.xlsx', 'rb') as f:

        file_content = f.read()

    headers = {

        'Content-Type': 'application/octet-stream',

        'Content-Disposition': 'attachment;filename=data.xlsx'

    }

    with NamedTemporaryFile(delete=False) as tmp:

        tmp.write(file_content)

        tmp.seek(0)

        wb = load_workbook(tmp)

    os.remove(tmp.name)

    ws = wb.active

    print(ws.cell(1, 1).value)

    wb.copy_worksheet(ws)

    with NamedTemporaryFile(delete=False) as tmp2:

        wb.save(tmp2.name)

        tmp2.seek(0)

        stream = tmp2.read()
    os.remove(tmp2.name)
    resp = HttpResponse(content=stream, headers=headers)  
    return resp

代码中借助临时文件,将excel文件数据流先写入文件,再通过openpyxl读取,最后将其保存为新的临时文件后返回响应。

数据压缩

如果要存储这部分数据,没必要完整存储原始部分,我们可以用zlib来压缩这个数据,zlib是个自带的库。

压缩与解压:

new_content = zlib.compress(file_content)
old_content = zlib.decompress(new_content)

对于这个文件,默认的压缩等级下,新数据占比为78%

对于数据库而言,使用二进制字段就会比字符串占的空间小很多,经过压缩会更小一些。