플라스크 send_file()

Salman Mehmood 2023년6월21일
플라스크 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"가 없으면 작동하지 않기 때문에 enctype="multipart/form-data"를 사용해야 합니다.

이제 가장 먼저 해야 할 일은 파일에 대한 정보와 파일 데이터를 보유할 모델을 만드는 것입니다. 우리는 SQLAlchemy 모델이 될 이 클래스를 File_Uploader라고 부를 것입니다.

이 모델에는 몇 가지 필드가 필요하므로 기본 키가 될 ID를 만든 다음 사용자가 양식을 통해 파일을 업로드할 때 파일 이름이 될 File_Name을 추가합니다. 마지막은 데이터베이스 내부에 저장된 파일의 원시 데이터인 DATA입니다.

이 특정 데이터의 경우 데이터베이스에 임의의 이진 데이터를 저장할 수 있는 LargeBinary라는 데이터 유형을 사용해야 합니다. 일반적으로 데이터베이스에 파일을 저장하지 않지만 메타데이터는 데이터베이스에 저장합니다.

파일이 많지 않거나 제한으로 인해 모든 것을 데이터베이스에 보관하려는 경우 파일을 데이터베이스에 저장할 수 있습니다. 파일 데이터를 단일 테이블의 다른 열과 결합하면 성능 문제가 발생할 수 있습니다.

파일 데이터가 포함된 이 테이블이 커지면 성능 문제가 발생할 수 있지만 원하는 경우 할 수 있습니다. 그것이 우리가 이것을 만드는 이유입니다.

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.filenameFile_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 Viewer로 드래그하면 테이블이 생성된 것을 확인할 수 있습니다.

Flask send_file() 출력 1

이제 이 앱을 실행하고 파일을 업로드 하겠습니다. 그러면 양식에서 파일을 업로드할 수 있습니다.

서버를 실행한 후 파일을 제출하기 위해 양식에 액세스할 경로를 지정합니다. 이러한 명령을 사용하여 Flask 앱을 설정하고 이 앱을 실행합니다.

set FLASK_APP='app.py'
flask run

파일을 업로드하고 나면 파일이 성공적으로 업로드된 것을 확인할 수 있고 테이블을 보면 id와 파일 이름이 있습니다.

Flask send_file() 출력 2

모든 파일 형식을 업로드할 수 있습니다. 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를 전달합니다. 이 경로에 도달하면 파일을 다운로드할 수 있습니다.

Flask send_file() 출력 3

완전한 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>
Salman Mehmood avatar Salman Mehmood avatar

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

관련 문장 - Flask File