フラスコ send_file()
 
この説明では、ファイルを SQLAlchemy データベースにアップロードし、それらのファイルを Flask のデータベースからダウンロードする方法を学びます。
Flask で SQLAlchemy データベースからファイルをアップロードおよびダウンロードする
SQLAlchemy を使用した基本的な Flask アプリがあり、テンプレートを使用してデータベースからファイルをアップロードおよびダウンロードします。 send_file() 関数を使用すると、HTML の代わりにファイルを返すことができます。
from flask import Flask, request, send_file, render_template
from flask_sqlalchemy import SQLAlchemy
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite3"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
@app.route("/", methods=["GET", "POST"])
def Main_page():
    return render_template("index.html")
index.html ファイル内に単純なフォームを作成しました。 ファイルをアップロードするフォームで作業する場合は、enctype="multipart/form-data" を使用する必要があります。これがないと機能しません。
ここで、最初に行う必要があるのは、ファイルに関する情報とファイルのデータを保持するモデルを作成することです。 このクラスを File_Uploader と呼びます。これは SQLAlchemy モデルになります。
このモデルにはいくつかのフィールドが必要になるため、主キーとなる ID を作成し、次に、ユーザーがフォームからファイルをアップロードするときのファイル名となる File_Name を追加します。 最後は DATA で、データベース内に保存されているファイルの生データです。
この特定のデータには、LargeBinary と呼ばれるデータ型を使用する必要があります。これにより、任意のバイナリ データをデータベースに格納できます。 通常、ファイルはデータベースに保存されませんが、メタデータはデータベースに保存されることに注意してください。
多くのファイルがない場合、または制限のためにすべてをデータベースに保持したい場合は、データベースにファイルを格納できます。 ファイル データを 1つのテーブル内の他の列と組み合わせると、パフォーマンスの問題が発生する可能性があります。
ファイルデータを含むこのテーブルが大きくなると、パフォーマンスの問題が発生する可能性がありますが、必要に応じて実行できます。 それが私たちがこれを作成している理由です。
class File_Uploader(db.Model):
    File_ID = db.Column(db.Integer, primary_key=True)
    File_Name = db.Column(db.String(50))
    DATA = db.Column(db.LargeBinary)
フォームからファイルを取得し、それが機能することを確認します。 Main_page() 関数内で、投稿リクエストを処理する if ステートメントを設定します。
ここで、request.files['file'] を使用してファイルを取得し、それらを変数に格納して、Got_File という名前を付けます。 これにより、フォームから送信された特定のキーを使用して、リクエストで送信されたすべてのファイルが取得されます。
if request.method == "POST":
    Got_File = request.files["file"]
次のステップでは、これをデータベースにアップロードします。これは、File_Uploader というモデルを使用します。 Got_File.filename を File_Name フィールドに渡し、次にファイルのデータを DATA フィールドに渡します。
Got_File.read() は、ファイルのすべてのバイナリ データを取得し、それをどこにでも割り当てます。 次に、セッションを追加してデータをコミットします。
file_upload = File_Uploader(File_Name=Got_File.filename, DATA=Got_File.read())
db.session.add(file_upload)
db.session.commit()
return f"Uploaded: {Got_File.filename}"
次に、データベースとデータベース内にテーブルを作成する必要があるため、app.py ファイルが配置されているディレクトリと同じディレクトリで Python シェルを開き、次のコマンドを使用します。
from app import db
db.create_all()
ルート ディレクトリを見ると、db というデータベース ファイルがあります。 このファイルを SQLite ビューアー内にドラッグすると、テーブルが作成されていることがわかります。

次に、このアプリを実行してファイルをアップロードします。 次に、フォームからファイルをアップロードできるようになります。
サーバーを実行した後、フォームにアクセスしてファイルを送信するルートにアクセスします。 これらのコマンドを使用して、Flask アプリをセットアップし、このアプリを実行します。
set FLASK_APP='app.py'
flask run
ファイルをアップロードした後、ファイルが正常にアップロードされたことを確認できます。テーブルを見ると、ID とファイル名が表示されます。

あらゆる種類のファイルをアップロードできます。 mp3、ムービー ファイル、コード ファイルなど、どのようなものでもかまいません。
ここで、データベースにアップロードしたファイルをダウンロードするルートを作成します。このルートには、File_ID という変数があります。 次に、その ID を使用してデータベースでクエリを実行し、その特定の行のデータをデータベースから取得します。
@app.route('/download/<File_ID>')
io モジュールから BytesIO クラスをインポートする必要があります。 これにより、データベース内のバイナリ データを取得し、Flask がファイルの再生成に使用できる形式に変換できます。
send_file() 関数を使用してファイルを返します。 次に、BytesIO クラス内で、対応する列でデータを渡します。
次に、添付ファイルを使用するため、attachment_filename キーワード引数を渡します。
def download(File_ID):
    Got_File = File_Uploader.query.filter_by(File_ID=File_ID).first()
    return send_file(
        BytesIO(Got_File.DATA),
        attachment_filename=Got_File.File_Name,
        as_attachment=True,
    )
これを見てみましょう。 ダウンロード ページに移動し、ID を渡します。 このルートに到達すると、ファイルをダウンロードできます。

完全な Python コード:
from flask import Flask, request, send_file, render_template
from flask_sqlalchemy import SQLAlchemy
from io import BytesIO
app = Flask(__name__)
app.config["SQLALCHEMY_DATABASE_URI"] = "sqlite:///db.sqlite3"
app.config["SQLALCHEMY_TRACK_MODIFICATIONS"] = False
db = SQLAlchemy(app)
class File_Uploader(db.Model):
    File_ID = db.Column(db.Integer, primary_key=True)
    File_Name = db.Column(db.String(50))
    DATA = db.Column(db.LargeBinary)
@app.route("/", methods=["GET", "POST"])
def Main_page():
    if request.method == "POST":
        Got_File = request.files["file"]
        file_upload = File_Uploader(File_Name=Got_File.filename, DATA=Got_File.read())
        db.session.add(file_upload)
        db.session.commit()
        return f"Uploaded: {Got_File.filename}"
    return render_template("index.html")
@app.route("/download/<File_ID>")
def download(File_ID):
    Got_File = File_Uploader.query.filter_by(File_ID=File_ID).first()
    return send_file(
        BytesIO(Got_File.DATA),
        attachment_filename=Got_File.File_Name,
        as_attachment=True,
    )
Flask アプリ内で使用した HTML ファイル:
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>File Uploader </title>
    <style>
        body {
          margin: 0;
        }
        .center {
          display: flex;
          justify-content: center;
          align-items: center;
          height: 100vh;
        }
      </style>
</head>
<body>
    <div class="center">
        <form method="POST" action="/" enctype="multipart/form-data">
            <input type="file" name="file">
            <button>Submit</button>
        </form>
    </div>
</body>
</html>
Hello! I am Salman Bin Mehmood(Baum), a software developer and I help organizations, address complex problems. My expertise lies within back-end, data science and machine learning. I am a lifelong learner, currently working on metaverse, and enrolled in a course building an AI application with python. I love solving problems and developing bug-free software for people. I write content related to python and hot Technologies.
LinkedIn