Flask
ファイルのアップロード
サーチ…
構文
- request.files ['name']#単一の必須ファイル
- request.files.get( 'name')#投稿されていない場合はNone
- request.files.getlist( 'name')#投稿された0個以上のファイルのリスト
- CombinedMultiDict((request.files、request.form))#フォームとファイルのデータを結合する
ファイルのアップロード
HTMLフォーム
-
file
タイプの入力を使用すると、ブラウザはアップロードするファイルを選択できるフィールドを提供します。 -
post
メソッドを持つフォームだけがファイルデータを送信できます。 - フォームの
enctype=multipart/form-data
属性を設定してください。それ以外の場合、ファイルの名前は送信されますが、ファイルのデータは送信されません。 - 単一フィールドに複数のファイルを選択できるようにするには、入力の
multiple
属性を使用します。
<form method=post enctype=multipart/form-data>
<!-- single file for the "profile" field -->
<input type=file name=profile>
<!-- multiple files for the "charts" field -->
<input type=file multiple name=charts>
<input type=submit>
</form>
Pythonリクエスト
Requestsは、HTTPリクエストを作成するための強力なPythonライブラリです。ブラウザ(または他のツール)を使用して、ブラウザなしでファイルを投稿することができます 。
- バイナリモードで読み込むファイルを開きます。
-
files
は複数のデータ構造がありfiles
。これは、上記のような複数のファイルを可能にする(name, data)
タプルのリストを示しています。
import requests
with open('profile.txt', 'rb') as f1, open('chart1.csv', 'rb') as f2, open('chart2.csv', 'rb') as f3:
files = [
('profile', f1),
('charts', f2),
('charts', f3)
]
requests.post('http://localhost:5000/upload', files=files)
これは網羅的なリストではありません。好きなツールやもっと複雑なシナリオを使った例については、そのツールのドキュメントを参照してください。
サーバー上のアップロードを保存する
アップロードされたファイルは、 request.files
で利用できます。これは、 MultiDict
マッピングフィールド名で、ファイルオブジェクトです。複数のファイルが同じフィールド名でアップロードされた場合は、 []
またはget
代わりにgetlist
使用します。
request.files['profile'] # single file (even if multiple were sent)
request.files.getlist('charts') # list of files (even if one was sent)
request.files
のオブジェクトには、ファイルをローカルに保存するsave
メソッドがあります。ファイルを保存する共通ディレクトリを作成します。
filename
属性は、ファイルがアップロードされた名前です。これは、クライアントが任意に設定できるので、 secure_filename
メソッドに渡して、有効な安全な名前を生成して保存します。 これは、名前が一意であることを保証するものではないため、既存のファイルを検出するために余分な作業をしない限り、既存のファイルは上書きされます。
import os
from flask import render_template, request, redirect, url_for
from werkzeug import secure_filename
# Create a directory in a known location to save files to.
uploads_dir = os.path.join(app.instance_path, 'uploads')
os.makedirs(uploads_dir, exists_ok=True)
@app.route('/upload', methods=['GET', 'POST'])
def upload():
if request.method == 'POST':
# save the single "profile" file
profile = request.files['profile']
profile.save(os.path.join(uploads_dir, secure_filename(profile.filename)))
# save each "charts" file
for file in request.files.getlist('charts'):
file.save(os.path.join(uploads_dir, secure_filename(file.name)))
return redirect(url_for('upload'))
return render_template('upload.html')
WTFormsとFlask-WTFにデータを渡す
WTFormsは、ファイルタイプの入力をレンダリングするためにFileField
を提供します。アップロードしたデータには特別なことはありません。しかし、Flaskはフォームデータ( request.form
)とファイルデータ( request.files
)を分割するため、フォームの作成時に正しいデータを渡す必要があります。 CombinedMultiDict
を使用して、WTFormsが理解できる単一の構造に2つを組み合わせることができます。
form = ProfileForm(CombinedMultiDict((request.files, request.form)))
FlaskとWTFormを統合する拡張機能であるFlask-WTFを使用している場合、正しいデータを渡すと自動的に処理されます。
WTFormのバグにより、複数のファイルがアップロードされた場合でも、各フィールドには1つのファイルしか存在しません。詳細については、 この問題を参照してください。これは3.0で修正される予定です。
パースCSVファイルは、保存なしでフラッシュ上の辞書のリストとしてアップロードされます
開発者は、ユーザーがCSVファイルをアップロードできるWebサイトを設計する必要があることがよくあります。通常、実際のCSVファイルを保存する理由はありません 。アップロードされると、データは処理され、データベースに保存されるからです。しかし、ほとんどではないにせよ、多くの場合、PYTHONのCSVデータ解析方法では、データをファイルとして読み込む必要があります。 Web開発にFLASKを使用している場合、これは少し頭痛を呈します。
CSVにヘッダー行があり、次のようになっているとします。
h1,h2,h3
'yellow','orange','blue'
'green','white','black'
'orange','pink','purple'
今、ファイルをアップロードするhtmlフォームが次のようになっているとします。
<form action="upload.html" method="post" enctype="multipart/form-data">
<input type="file" name="fileupload" id="fileToUpload">
<input type="submit" value="Upload File" name="submit">
</form>
誰もあなたの車輪を再発明したくないので、あなたはあなたのFLASKスクリプトにcsvをインポートすることに決めました。人々が正しい順序で列を含むcsvファイルをアップロードするという保証はありません。 csvファイルにヘッダー行がある場合は、 csv.DictReaderメソッドの助けを借りて、CSVファイルをヘッダー行のエントリーでキー入力して辞書のリストとして読み取ることができます。しかし、 csv.DictReaderはファイルを必要とし、文字列を直接受け入れません。アップロードされたファイルを最初に保存し、新しいファイル名と場所を取得し 、 csv.DictReaderを使用してファイルを開き 、ファイルを削除するには、 FLASKメソッドを使用する必要があると考えるかもしれません。少し浪費のようです。
幸いなことに、ファイルの内容を文字列として取得し、文字列を終端された行で分割することができます。 csvメソッドcsv.DictReaderはこれをファイルの代用として受け入れます。次のコードは、ファイルを一時的に保存せずにこれを実行する方法を示しています。
@application.route('upload.html',methods = ['POST'])
def upload_route_summary():
if request.method == 'POST':
# Create variable for uploaded file
f = request.files['fileupload']
#store the file contents as a string
fstring = f.read()
#create list of dictionaries keyed by header row
csv_dicts = [{k: v for k, v in row.items()} for row in csv.DictReader(fstring.splitlines(), skipinitialspace=True)]
#do something list of dictionaries
return "success"
変数csv_dictsは次の辞書のリストになりました:
csv_dicts =
[
{'h1':'yellow','h2':'orange','h3':'blue'},
{'h1':'green','h2':'white','h3':'black'},
{'h1':'orange','h2':'pink','h3':'purple'}
]
PYTHONを初めてお使いの場合は、次のようなデータにアクセスできます:
csv_dicts[1]['h2'] = 'white'
csv_dicts[0]['h3'] = 'blue'
その他のソリューションには、 ioモジュールのインポートとio.Streamメソッドの使用が含まれます。私はこれがもっと簡単なアプローチだと感じています。私はコードがioメソッドを使うより少し簡単だと信じています。この方法は、アップロードされたCSVファイルを解析する例に固有です。