dash-uploaderでアップローダを楽に実装する
Dashでファイルのアップロードを取り扱う
ファイルをアップロードすると、何らかの処理をしてくれて、その結果がダウンロードできるテンプレートアプリが作りたかった。よくあるdocを送るとpdfを返してくれるようなサービスで、中の処理をいろいろといじれるようなものかな。Dashでアップローダを実装する場合、dash-core-componentのUploadコンポーネントを使う方法が公式には紹介されている。
この方法はあくまでのアップロードそのものの機能しかないので、アップローダとして一般的に必要な機能、例えば
- アップロードしたデータのパース
- アップロードの進捗
- 正常にアップロードされたかのチェック
- セッション管理
といったものは都度callbackを自分で書く必要がある。
これはなかなかに面倒だが、こういった悩みはdash-uploaderというライブラリを使うことで簡単に実現できる。
dash-uploader
アップローダのコンポーネントの定義は非常にシンプルで、
upload_box = dbc.Container([
html.Hr(),
html.H4("Upload with Dash-uploader"),
du.Upload(
id='input',
max_file_size=1800,
filetypes=['csv'],
max_files=1,
cancel_button=True,
),
html.P(id='input_info'),
html.Br(),
])
上記のように記載するだけで、
- アップロード時の最大ファイルサイズ
- ファイルタイプの制限
- 1回あたりの最大アップロード数
- アップロードの進捗
- キャンセルボタン
- セッション管理
を実現できる。
dash-uploaderでは基本的にセッションごとにユニークなディレクトリが生成され、ユーザがアップロードされたデータはそのディレクトリにアップロードされる。dash-uploaderのコンポーネントはプロパティとして、アップロード先のディレクトリ(upload_id)、アップロードしたファイルの名前(fileName)を持っているため、これをcallbackのInputとして用いることで、アップロードされたファイルに対して何らかの処理を行うことが可能となる。
例えば、アップロードされたファイルに対して、ファイルのバリデーションを行い、さらに別途設定されたRunボタンによって処理を走らせるcallbackは次のように実装できる。
@app.callback(
[
Output("input_info", "children"),
Output("btn-run", "n_clicks"),
Output("output", "children"),
],
[
{
"fileNames":Input("input", "fileNames"),
"upload_id":Input("input", "upload_id"),
"isCompleted":Input("input", "isCompleted"),
},
Input("btn-run", "n_clicks"),
],
prevent_inital_call=True,
)
def validation(args, n_clicks):
is_invalid, message = validator.before_run(args)
if is_invalid:
return message, 0, ""
else:
if n_clicks > 0:
return message, 0, logic.main(args)
else:
return message, 0, ""
最終的にできたテンプレートはこちら。
ファイルをアップロードすると、ファイルの有無を検知してRUNボタンが有効になる。RUNを押すと裏で処理が走り、処理が完了するとRESULTボタンが有効になり、結果がダウンロードできるようになる。めっちゃ便利!
Discussion