Edited at

Djnagoメモ Content-Dispositionのfilenameに日本語をセットする


目的

リクエストに対してファイルを日本語ファイル名(マルチバイト文字列を含むファイル名)でダウンロードしたい。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エンコーディングしたファイル名をセットしているというところです。

この設定でも行けるときは行ける気がしますが、ブラウザによっては文字化けします。


view.py

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


※上記はクラスベースのViewなので、Djangoのurlsではas_view()を使って呼び出して下しあ。


解決策

ブラウザによって挙動が違うということは、ブラウザによって処理を変えろということですね。

httpリクエストのUser-Agentフィールドを見ればアクセスしてきたブラウザ名が分かるので、ブラウザごとのif文をに職人が真心込めて…

というようなことをしなくても、Content-Dipositionのfilename*フィールドをセットすることで対応可能のようです。

参考: ダウンロードファイル名、文字化けとの格闘


Content-Disposition = filename="ファイル名"; filename*=UTF-8''URLエンコーディングされたファイル名;


これでなんとかなりそうです。


結論

最終的にDjangoのviewに落とし込むとこんな感じです。


view.py

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='{}'; filename*=UTF-8''{}".format(test_filename, urllib.parse.quote(test_filename))
return response


filename*にURLエンコードしたファイル名をセットすることで、各種ブラウザに対応できます。

Chrome、Firefox、Safariでは動作確認できました。