0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

マルチアップロード Flask-Form-Model+JS埋め込み

Last updated at Posted at 2020-11-03

#内容
Flaskでファイル送信FORMを動的に作っていて、自分なりに解を見出したのでまとめる。
関連質問は以下となる
https://teratail.com/questions/300488
https://teratail.com/questions/302044

#結論
Flaskからのレンダリングは、フォームの個数だけを指示する。
JS側でフォームの成形をする → VUEの出る幕は無し

最終的にはVue.Jsは使わないことにしました。

#解決した方法
HTMLフォームとFLASKのFORM-MODEL処理について、下記の辞書を使い紐付けを行った。

JS
dict = { "title1:"db1","title2":"db2", "title3":"db3","title4":"db4" }

python
model_table = {"db1",database1,"db2":database2,"db3":database3,"db4":database4}

全体的なループカウンタは、Flask側からJINJA2でループを回して、レンダリング時にloop.index0を使いIDタグに命名している。
DOM完成後にJSでdictのループを回して、MAPのINDEXからIDを生成し、html本文を書き換えている。


          {% for i in forms %}
          <h1 id = "t{{loop.index0}}"></h1>
          <p>
              <form id = "f{{loop.index0}}" class="form form-horizontal" method="POST" action="{{url_for('data_import')}}"  enctype="multipart/form-data">
                  <input type="file" name="file">
                  <input type="submit" >
              </form>
          </p>
          {% endfor %}

<script>
var dict =  { "title1:"db1","title2":"db2", "title3":"db3","title4":"db4" }

    Object.keys(dict).map(function(key,index){
        document.getElementById('t'+index).textContent = key;
        document.getElementById('f'+index).action += "/"+dict[key];
    });
</script>

Flask側はURLエンドでデータベースのモデルを特定できるようにした。
モデルを自体を直接的に辞書に突っ込んでおり、model_nameを介して
共通コードで処理している。

いったんモデルクラスに実装したdata_importというメソッドで
処理はモデル毎にカスタマイズしており、
returnされるobjectは、データのインスタンス群であり、これを一括で更新する。

model_table = {"db1",database1,"db2":database2,"db3":database3,"db4":database4}

#データインポート処理
@app.route('/import')
@app.route('/import/<model_name>',methods=["GET", "POST"])
def data_import(model_name):
    if request.method == 'POST': 
        if 'file' not in request.files:
            flash('No file part')
            return redirect(request.url)
        file = request.files['file']
        if file.filename == '':
            flash(name + "ファイルを選択してください。", "failed")
            return redirect(request.url)
        if file and allowed_file(file.filename): 
            filename = secure_filename(file.filename)
            filename =os.path.join(app.config['UPLOAD_FOLDER'], filename)
            file.save(filename)
            model = model_table[model_name]
            objects = model.data_import(filename)

            db.session.bulk_save_objects(objects)
            db.session.commit()

        return render_template(
            'table_viewer.html',
            forms = range(4)
        )

    return render_template( 
        'import.html',
        forms = [1,2,3,4]
    )

#あとがき
 何故ここまで複雑化したのかというと、いろんな理由がある。

・バックエンドの処理において、フォーム毎にバインディングしているデータベースが違うこと
・FLASK側ではORMライブラリを使い、複数ファイルに分かれたSQLITEに対して、共通化した処理でコミットさせたかった
・Flaskのテンプレート内のVIEWに関わる情報については、受け側のHTML内で処理したかった。
・POST送信はHTMLのデフォルトでやりたく、AJAX通信の複雑さをコードに入れたくなかった。

 最近は便利なフレームワークが多いが、無理をせずにバニラjsで十分できることもある。
工夫されたコードはいたってシンプルであり、かつ美しいものである。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?