Flaskにて、アップロードされたファイルをローカル保存せずに扱う方法です。
先駆者さん⇒Flask にアップロードされたCSVファイルを保存せずに読み込む
上記の記事ではCSVファイルとして直接読み込む方法なので、S3転送する方法を書いておきます。
AWS SDKとしてboto3を使用します。
動作環境
いずれも 2019/9 時点の(おおよそ)最新。
- Python: 3.7.4
- Flask: 1.1.1
- boto3: 1.9.230
ファイルアップロードファイルを受け付ける
htmlのフォームタグにenctype="multipart/form-data"
属性を指定する必要があります。
詳細は本記事の対象外とします。
参考 - Flaskでmultipart/form-dataのファイルアップロードを実現する方法
S3への転送
boto3 の put_object
メソッドでbytesオブジェクトを指定できるため、受け取ったファイルをbytesオブジェクトに変換して渡すことでS3アップロードが行えます。
参考 - S3 - Boto3 Doc
put_object(**kwargs)
Request Syntax
response = client.put_object(
ACL='private'|'public-read'|'public-read-write'|'authenticated-read'|'aws-exec-read'|'bucket-owner-read'|'bucket-owner-full-control',
Body=b'bytes'|file, ←★これ。
※アップロード先のバケット名やパスはconfig.py
で定義しておくのが良いと思います。
import io
import boto3
from Flask import jsonify
@app.route('/upload', methods=['POST'])
def workflow_create():
if request.method == 'POST':
# アップロードファイルを取得
uploaded_file = request.files['file']
# エラーチェック
if uploaded_file.filename == '':
return jsonify(message='ファイルを指定してください'), 400
# S3アップロード処理
s3_bucket = app.config['S3_BUCKET']
s3_dir = app.config['S3_DIR']
s3 = boto3.client('s3', region_name = 'ap-northeast-1')
response = s3.put_object(
Body = io.BufferedReader(uploaded_file).read(),
Bucket = s3_bucket,
Key = f'{s3_dir}/{uploaded_file.filename}'
)
if response['ResponseMetadata']['HTTPStatusCode'] != 200:
return jsonify(message='S3へのアップロードでエラーが発生しました'), 500
return redirect(url_for('index'))
response = s3.put_object(
Body = io.BufferedReader(uploaded_file).read()
~~~
上記の部分でアップロードファイルをキャストしています。
これにより以下のコードで得られるファイルオブジェクトと同じ型で扱えます。
file = open('local/path/file.txt', 'rb')