2020/2/7 追記
同僚から指摘があり、以下の修正をしました
- filename=の値もurl encodeする
##目的
リクエストに対してファイルを日本語ファイル名(マルチバイト文字列を含むファイル名)でダウンロードしたい。Djangoに限らずWebアプリ全般に共通のことです。
環境
Django: 1.10.xx
Python: 3系
Content-Diposition
httpでファイルをダウンロードするときはレスポンスのContent-Dispositionフィールドをセットする必要があります。ここでダウンロード時のファイル名や、すぐにダウンロードを実行するかなどを指定できます。
Content-Type='application/pdf'
Content-Disposition: filename="hogehoge.pdf";
DjangoのView
上記設定をDjangoのViewで行うとこのようになります。
肝は普通にファイル名をセットするのではなく、URLエンコーディングしたファイル名をセットしているというところです。
この設定でも行けるときは行ける気がしますが、ブラウザによっては文字化けします。
from django.views.generic import View
import urllib.parse
class DownloadTestView(View):
def get(self, request):
test_filename = 'test.pdf'
response = HttpResponse(status=200, content_type='application/pdf')
"""
〜なんかPDF生成処理する〜
"""
response['Content-Disposition'] = "filename='{}'".format(urllib.parse.quote(test_filename))
return response
解決策
ブラウザによって挙動が違うということは、ブラウザによって処理を変えろということですね。
httpリクエストのUser-Agentフィールドを見ればアクセスしてきたブラウザ名が分かるので、ブラウザごとのif文をに職人が真心込めて…
というようなことをしなくても、Content-Dipositionのfilename*フィールドをセットすることで対応可能のようです。
Content-Disposition = filename="ファイル名"; filename*=UTF-8''URLエンコーディングされたファイル名;
これでなんとかなりそうです。
結論
最終的にDjangoのviewに落とし込むとこんな感じです。
from django.views.generic import View
import urllib.parse
class DownloadTestView(View):
def get(self, request):
test_filename = 'test.pdf'
quoted_filename = urllib.parse.quote(test_filename)
# ついでに、RFC6266準拠しとく ("attachment" を追加)
# https://tools.ietf.org/html/rfc6266#section-5
response = HttpResponse(status=200, content_type='application/pdf')
"""
〜なんかPDF生成処理する〜
"""
response['Content-Disposition'] = "attachment; filename='{}'; filename*=UTF-8''{}".format(quoted_filename, quoted_filename)
return response
filename*にURLエンコードしたファイル名をセットすることで、各種ブラウザに対応できます。
Chrome、Firefox、Safariでは動作確認できました。