我有一个像下面这样的Flask视图,它生成几个CSV文件并将它们放在一个zip存档中发送给用户。
@route('/download/<int:some_value>')
def download(self, some_value):
"""Return a ZIP archive with several CSVs in"""
# ensure the thing exists
at = (MyModel.SomeModel
.query
.filter((MyModel.SomeModel
.some_primary_key) == some_value)
.first_or_404())
# what queries do we need to run?
queries = cascade_export(at)
# prepare a zip
out = BytesIO()
with zipfile.ZipFile(out, 'w') as zf:
# run each query
for tn, q in queries.items():
# make the query
conn = db.engine.connect()
r = conn.execute(q.query, **q.params)
conn.close()
# map the col names
cols = [c.name for c in r.cursor.description]
col_map = {
c.name: c.key
for c in q.model.__table__.columns
}
col_order = [col_map[c] for c in cols]
# put it into a csv in memory
f = StringIO()
writer = csv.DictWriter(f, fieldnames=col_order)
for row in r:
writer.writerow({
k: v
for k, v in zip(col_order, row)
})
# write it into the zip
f.seek(0)
zf.writestr('{0}.csv'.format(q.model.__name__), f.read())
out.seek(0)
fn = 'export-{0}-{1}.zip'.format(
at.some_name,
datetime.datetime.now().strftime('%d-%m-%Y-%H-%M-%S')
)
return send_file(out,
attachment_filename=fn,
as_attachment=True,
cache_timeout=0)
在我的测试中,r
是一个响应对象,以下两个传递:
assert r.status_code == 200
zf = zipfile.ZipFile(io.BytesIO(r.data))
assert zf.testzip() is None
但是,当我尝试在ubuntu中打开文件时,我得到以下内容:
Archive: ../downloads/export-Something-20-04-2018-11-59-04.zip
warning [../downloads/export-Something-20-04-2018-11-59-04.zip]: 300 extra bytes at beginning or within zipfile
(attempting to process anyway)
error [../downloads/export-Something-20-04-2018-11-59-04.zip]: start of central directory not found;
zipfile corrupt.
(please check that you have transferred or created the zipfile in the
appropriate BINARY mode and that you have compiled UnZip properly)
对此的任何想法/帮助都非常感激。
答案 0 :(得分:0)
问题不在于Python,而在于文件的下载方式。很明显,如果python测试通过,zip文件可能是合法的!如果您发现自己遇到同样的错误,请确保您的HTTP库期望得到正确的响应,对于axios
,这意味着设置responseType to 'bytearray'。