Flask中国語名ファイルのダウンロード


flaskバックエンドを書くとき、特にデータ関連の操作をするとき、製品は往々にして私たちがデータをエクスポートする必要があります.一般的にはexcel形式のファイルをエクスポートします.
ではflaskでは、リクエスト接続をどのように実現すればブラウザがダウンロードできるのでしょうか.二つの考えがある.
1:
ファイルはローカルディスクにあります.この場合、対応するアドレスを送信するだけでいいです.
2:
ioのBytesIOでファイルをバイナリ形式で送信します.ここではflaskが持参したsend_を使用する必要があります.file.
1つ目のデメリットは、権限制御が不便で、ダウンロードリンクを手に入れてどこでもダウンロードできることであり、2つ目の方法の欠点はgetリクエストしか受信できないことであり、postリクエストが送信するファイルブラウザは認識できないことである.
send_を実装するにはfileは、簡単です.コードは以下の通りです(python 3に適用).
import xlsxwriter
from io import BytesIO
from flask import Flask, send_file

app = Flask(__name__)


@app.route("/download", methods=["GET"])
def download():
    out = BytesIO()
    workbook = xlsxwriter.Workbook(out)
    table = workbook.add_worksheet()
    table.write(0, 0, "name")
    table.write(0, 1, "age")
    workbook.close()
    out.seek(0)
    return send_file(out, as_attachment=True, attachment_filename="dream.xlsx")


if __name__ == "__main__":
    app.run(debug=True)

これは完全なバックエンドプログラムで、直接走ることができます.
ここではxlsxwriterというライブラリを使用して、excelファイルを生成し、BytesIO()に直接送信してデータストリームの形式で送信し、ブラウザはこれらのデータストリームを受信し、自動的にダウンロードし、ファイル名はsend_である.fileパラメータのattachment_filename、ここでdreamです.xlsx .
プログラムを起動し、ブラウザに127.0.0.1:5000/downloadを入力するとdreamという名前をダウンロードできます.xlsxのファイル.
開けてみましょう.
確かに私たちが生成したexcelテーブルです.
今問題が来ました.ここのファイル名は英語ですが、中国語はどうすればいいですか.直接attachment_filenameパラメータをattachment_に変更filename=「テストテーブル.xlsx」でよろしいですか?
試してみましょう.
return send_file(out, as_attachment=True, attachment_filename="    .xlsx")

残りのコードは変更されず、ここでのみ変更されます.
コードを実行し、ブラウザがダウンロードにアクセスしてみます.
ブラウザには何の反応もありません.私たちがデータを伝えていないことを意味します.プログラムを見て、間違っています.情報を間違っています.
UnicodeEncodeError: 'latin-1' codec can't encode characters in position 43-46: ordinal not in range(256)

エンコードの問題.
解決策は次のとおりです.
import xlsxwriter
from io import BytesIO
from flask import Flask, send_file
from urllib.parse import quote

app = Flask(__name__)


@app.route("/download", methods=["GET"])
def download():
    out = BytesIO()
    workbook = xlsxwriter.Workbook(out)
    table = workbook.add_worksheet()
    table.write(0, 0, "name")
    table.write(0, 1, "age")
    workbook.close()
    out.seek(0)
    filename = quote("    .xlsx")
    rv = send_file(out, as_attachment=True, attachment_filename=filename)
    rv.headers['Content-Disposition'] += "; filename*=utf-8''{}".format(filename)
    return rv


if __name__ == "__main__":
    app.run(debug=True)

私たちはurllib.parseはquoteを導入し、まずファイル名を符号化し、send_fileでattachment_としてfilenameのパラメータは、この時点でファイルのダウンロードに成功しますが、ファイル名は符号化された名前で、復号するにはheadersで符号化フォーマットを宣言する必要があります.
rv.headers['Content-Disposition'] += "; filename*=utf-8''{}".format(filename)

これでファイル名をUTF-8復号し、私たちのファイル名は中国語になります.
図:
ファイルを開くのも、図のように私たちが望んでいるものです.
大成功!
もちろん実際の生産作業では、データ量は非常に大きく、excelファイルを生成するのに特に時間がかかります.もちろん、私たちのプログラムがここで詰まっていることを望んでいません.このとき、celly非同期タスクを使用して、フロントエンドのタスクIDに戻って、フロントエンドはこのタスクIDをポーリングして、ファイルが生成されたら、ダウンロードを開始することができます.
複数のネストされたオブジェクトがパラメータとして渡されるなど、getリクエストがパラメータ伝達を満たすことができない場合があるため、postリクエストを使用する必要があります.この場合もcelery非同期タスクを使用して、タスクIDを返し、タスクステータスをポーリングし、ファイルをダウンロードすることができます.
その後、私はチュートリアルを書きます.celery非同期タスクです.