我的任务是从模板生成DOCX文件,然后通过Flask提供该文件.我使用python-docx-templates,它只是python-docx的包装,允许使用jinja模板.最后,他们建议使用StringIO仅将文件保存在内存中,因此我的代码如下所示:def repo...

我的任务是从模板生成DOCX文件,然后通过Flask提供该文件.我使用python-docx-templates,它只是python-docx的包装,允许使用jinja模板.
最后,他们建议使用StringIO仅将文件保存在内存中,因此我的代码如下所示:
def report_doc(user_id):
# Prepare the data...
from docxtpl import DocxTemplate
doc = DocxTemplate(app.root_path+'/templates/report.docx')
doc.render({
# Pass parameters
})
from io import StringIO
file_stream = StringIO()
doc.save(file_stream)
return send_file(file_stream, as_attachment=True, attachment_filename='report_'+user_id+'.docx')
保存时将引发错误TypeError:预期的字符串参数,为“ bytes”.谷歌搜索之后,我发现this answer表示ZipFile需要BytesIO.但是,当我用BytesIO代替StringIO时,它仅返回一个空文件,因此它不会引发任何错误,但绝对不会保存该文件.
在这种情况下究竟能做什么?如果这里有什么完全不对的地方,那么总体上该如何做?
谢谢!
UPD:这是对保存功能调用的完整跟踪的例外:
File "/ms/controllers.py", line 1306, in report_doc
doc.save(file_stream)
File "/.env/lib/python3.5/site-packages/docx/document.py", line 142, in save
self._part.save(path_or_stream)
File "/.env/lib/python3.5/site-packages/docx/parts/document.py", line 129, in save
self.package.save(path_or_stream)
File "/.env/lib/python3.5/site-packages/docx/opc/package.py", line 160, in save
PackageWriter.write(pkg_file, self.rels, self.parts)
File "/.env/lib/python3.5/site-packages/docx/opc/pkgwriter.py", line 33, in write
PackageWriter._write_content_types_stream(phys_writer, parts)
File "/.env/lib/python3.5/site-packages/docx/opc/pkgwriter.py", line 45, in _write_content_types_stream
phys_writer.write(CONTENT_TYPES_URI, cti.blob)
File "/.env/lib/python3.5/site-packages/docx/opc/phys_pkg.py", line 155, in write
self._zipf.writestr(pack_uri.membername, blob)
File "/usr/lib/python3.5/zipfile.py", line 1581, in writestr
self.fp.write(zinfo.FileHeader(zip64))
TypeError: string argument expected, got 'bytes'
解决方法:
使用BytesIO实例是正确的,但是在将其传递到send_file之前需要rewind the file pointer:
Make sure that the file pointer is positioned at the start of data to
send before calling send_file().
所以这应该工作:
import io
from docxtpl import DocxTemplate
def report_doc(user_id):
# Prepare the data...
doc = DocxTemplate(app.root_path+'/templates/report.docx')
doc.render({
# Pass parameters
})
file_stream = io.BytesIO()
doc.save(file_stream)
file_stream.seek(0)
return send_file(file_stream, as_attachment=True, attachment_filename='report_'+user_id+'.docx')
(在Firefox上进行测试,我发现浏览器即使指定了不同的文件名,也一直从缓存中检索文件,因此您可能需要在测试时清除浏览器的缓存,或者如果浏览器支持则禁用开发工具中的缓存,或者调整Flask cache control settings).
本文标题为:如何在Python中生成DOCX并将其保存在内存中?


基础教程推荐
- 如何利用Python快速统计文本的行数 2023-08-04
- 通过VS下载的NuGet包修改其下载存放路径的操作方法 2022-10-20
- Python实现如何根据文件后缀进行分类 2023-08-04
- Python 变量命名规则和定义变量详解 2023-08-04
- python图形界面tkinter的使用技巧 2022-10-20
- Python Multiprocessing.Process如何重用一个进程? 2023-11-12
- Python:忽略后台进程中的信号 2023-11-12
- linux-Centos7安装python3并与python2共存 2023-09-04
- 如何在Linux中包含python模块? 2023-11-13
- Windows下使用python库 curses遇到错误消息的解决方案 2023-09-03