νμΌ μμ²¶
File
μ μ¬μ©νμ¬ ν΄λΌμ΄μΈνΈκ° μ
λ‘λν νμΌλ€μ μ μν μ μμ΅λλ€.
μ 보
μ
λ‘λλ νμΌμ μ λ¬λ°κΈ° μν΄ λ¨Όμ python-multipart
λ₯Ό μ€μΉν΄μΌν©λλ€.
μμ) pip install python-multipart
.
μ λ‘λλ νμΌλ€μ "νΌ λ°μ΄ν°"μ ννλ‘ μ μ‘λκΈ° λλ¬Έμ μ΄ μμ μ΄ νμν©λλ€.
File
μν¬νΈ¶
fastapi
μμ File
κ³Ό UploadFile
μ μν¬νΈ ν©λλ€:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File()):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
File
λ§€κ°λ³μ μ μ¶
Body
λ° Form
κ³Ό λμΌν λ°©μμΌλ‘ νμΌμ λ§€κ°λ³μλ₯Ό μμ±ν©λλ€:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File()):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
μ 보
File
μ Form
μΌλ‘λΆν° μ§μ μμλ ν΄λμ€μ
λλ€.
νμ§λ§ fastapi
λ‘λΆν° Query
, Path
, File
λ±μ μν¬νΈ ν λ, μ΄κ²λ€μ νΉλ³ν ν΄λμ€λ€μ λ°ννλ ν¨μλΌλ κ²μ κΈ°μ΅νκΈ° λ°λλλ€.
ν
Fileμ λ³Έλ¬Έμ μ μΈν λ, λ§€κ°λ³μκ° μΏΌλ¦¬ λ§€κ°λ³μ λλ λ³Έλ¬Έ(JSON) λ§€κ°λ³μλ‘ ν΄μλλ κ²μ λ°©μ§νκΈ° μν΄ File
μ μ¬μ©ν΄μΌν©λλ€.
νμΌλ€μ "νΌ λ°μ΄ν°"μ ννλ‘ μ λ‘λ λ©λλ€.
κ²½λ‘ μλ ν¨μμ λ§€κ°λ³μλ₯Ό bytes
λ‘ μ μΈνλ κ²½μ° FastAPIλ νμΌμ μ½κ³ bytes
ννμ λ΄μ©μ μ λ¬ν©λλ€.
μ΄κ²μ μ 체 λ΄μ©μ΄ λ©λͺ¨λ¦¬μ μ μ₯λλ€λ κ²μ μλ―Ένλ€λ κ±Έ μΌλνκΈ° λ°λλλ€. μ΄λ μμ ν¬κΈ°μ νμΌλ€μ μ ν©ν©λλ€.
μ΄λ€ κ²½μ°μλ UploadFile
μ μ¬μ©νλ κ²μ΄ λ μ 리ν©λλ€.
File
λ§€κ°λ³μμ UploadFile
¶
File
λ§€κ°λ³μλ₯Ό UploadFile
νμ
μΌλ‘ μ μν©λλ€:
from fastapi import FastAPI, File, UploadFile
app = FastAPI()
@app.post("/files/")
async def create_file(file: bytes = File()):
return {"file_size": len(file)}
@app.post("/uploadfile/")
async def create_upload_file(file: UploadFile):
return {"filename": file.filename}
UploadFile
μ μ¬μ©νλ κ²μ bytes
κ³Ό λΉκ΅ν΄ λ€μκ³Ό κ°μ μ₯μ μ΄ μμ΅λλ€:
- "μ€ν νμΌ"μ μ¬μ©ν©λλ€.
- μ΅λ ν¬κΈ° μ νκΉμ§λ§ λ©λͺ¨λ¦¬μ μ μ₯λλ©°, μ΄λ₯Ό μ΄κ³Όνλ κ²½μ° λμ€ν¬μ μ μ₯λ©λλ€.
- λ°λΌμ μ΄λ―Έμ§, λμμ, ν° μ΄μ§μ½λμ κ°μ λμ©λ νμΌλ€μ λ§μ λ©λͺ¨λ¦¬λ₯Ό μλͺ¨νμ§ μκ³ μ²λ¦¬νκΈ°μ μ ν©ν©λλ€.
- μ λ‘λ λ νμΌμ λ©νλ°μ΄ν°λ₯Ό μ»μ μ μμ΅λλ€.
- file-like
async
μΈν°νμ΄μ€λ₯Ό κ°κ³ μμ΅λλ€. - file-like objectλ₯Ό νμλ‘νλ λ€λ₯Έ λΌμ΄λΈλ¬λ¦¬μ μ§μ μ μΌλ‘ μ λ¬ν μ μλ νμ΄μ¬
SpooledTemporaryFile
κ°μ²΄λ₯Ό λ°νν©λλ€.
UploadFile
¶
UploadFile
μ λ€μκ³Ό κ°μ μ΄νΈλ¦¬λ·°νΈκ° μμ΅λλ€:
filename
: λ¬Έμμ΄(str
)λ‘ λ μ λ‘λλ νμΌμ νμΌλͺ μ λλ€ (μ:myimage.jpg
).content_type
: λ¬Έμμ΄(str
)λ‘ λ νμΌ νμ(MIME type / media type)μ λλ€ (μ:Βimage/jpeg
).file
:SpooledTemporaryFile
(νμΌλ₯ κ°μ²΄)μ λλ€. μ΄κ²μ "νμΌλ₯" κ°μ²΄λ₯Ό νμλ‘νλ λ€λ₯Έ λΌμ΄λΈλ¬λ¦¬μ μ§μ μ μΌλ‘ μ λ¬ν μ μλ μ€μ§μ μΈ νμ΄μ¬ νμΌμ λλ€.
UploadFile
μλ λ€μμ async
λ©μλλ€μ΄ μμ΅λλ€. μ΄λ€μ λ΄λΆμ μΈ SpooledTemporaryFile
μ μ¬μ©νμ¬ ν΄λΉνλ νμΌ λ©μλλ₯Ό νΈμΆν©λλ€.
write(data)
:data
(str
λλbytes
)λ₯Ό νμΌμ μμ±ν©λλ€.read(size)
: νμΌμ λ°μ΄νΈ λ° κΈμμsize
(int
)λ₯Ό μ½μ΅λλ€.seek(offset)
: νμΌ λ΄offset
(int
) μμΉμ λ°μ΄νΈλ‘ μ΄λν©λλ€.- μ)
await myfile.seek(0)
λ₯Ό μ¬μ©νλ©΄ νμΌμ μμλΆλΆμΌλ‘ μ΄λν©λλ€. await myfile.read()
λ₯Ό μ¬μ©ν ν λ΄μ©μ λ€μ μ½μ λ μ μ©ν©λλ€.
- μ)
close()
: νμΌμ λ«μ΅λλ€.
μκΈ° λͺ¨λ λ©μλλ€μ΄ async
λ©μλμ΄κΈ° λλ¬Έμ βawaitβμ μ¬μ©νμ¬μΌ ν©λλ€.
μλ₯Όλ€μ΄, async
κ²½λ‘ μλ ν¨μμ λ΄λΆμμ λ€μκ³Ό κ°μ λ°©μμΌλ‘ λ΄μ©μ κ°μ Έμ¬ μ μμ΅λλ€:
contents = await myfile.read()
λ§μ½ μΌλ°μ μΈ def
κ²½λ‘ μλ ν¨μμ λ΄λΆλΌλ©΄, λ€μκ³Ό κ°μ΄ UploadFile.file
μ μ§μ μ κ·Όν μ μμ΅λλ€:
contents = myfile.file.read()
async
κΈ°μ μ μΈλΆμ¬ν
async
λ©μλλ€μ μ¬μ©ν λ FastAPIλ μ€λ λνμμ νμΌ λ©μλλ€μ μ€ννκ³ κ·Έλ€μ κΈ°λ€λ¦½λλ€.
Starlette κΈ°μ μ μΈλΆμ¬ν
FastAPIμ UploadFile
μ Starletteμ UploadFile
μ μ§μ μ μΌλ‘ μμλ°μ§λ§, Pydantic λ° FastAPIμ λ€λ₯Έ λΆλΆλ€κ³Όμ νΈνμ±μ μν΄ νμν λΆλΆλ€μ΄ μΆκ°λμμ΅λλ€.
"νΌ λ°μ΄ν°"λ¶
HTMLμ νΌλ€(<form></form>
)μ΄ μλ²μ λ°μ΄ν°λ₯Ό μ μ‘νλ λ°©μμ λκ° λ°μ΄ν°μ JSONκ³Όλ λ€λ₯Έ "νΉλ³ν" μΈμ½λ©μ μ¬μ©ν©λλ€.
FastAPIλ JSON λμ μ¬λ°λ₯Έ μμΉμμ λ°μ΄ν°λ₯Ό μ½μ μ μλλ‘ ν©λλ€.
κΈ°μ μ μΈλΆμ¬ν
νΌμ λ°μ΄ν°λ νμΌμ΄ ν¬ν¨λμ§ μμ κ²½μ° μΌλ°μ μΌλ‘ "λ―Έλμ΄ μ ν" application/x-www-form-urlencoded
μ μ¬μ©ν΄ μΈμ½λ© λ©λλ€.
νμ§λ§ νμΌμ΄ ν¬ν¨λ κ²½μ°, multipart/form-data
λ‘ μΈμ½λ©λ©λλ€. File
μ μ¬μ©νμλ€λ©΄, FastAPIλ λ³Έλ¬Έμ μ ν©ν λΆλΆμμ νμΌμ κ°μ ΈμμΌ νλ€λ κ²μ μΈμ§ν©λλ€.
μΈμ½λ©κ³Ό νΌ νλμ λν΄ λ μκ³ μΆλ€λ©΄, POST
μ κ΄νMDNμΉ λ¬Έμ λ₯Ό μ°Έκ³ νκΈ° λ°λλλ€,.
μ£Όμ
λ€μμ File
κ³Ό Form
λ§€κ°λ³μλ₯Ό ν κ²½λ‘ μλμ μ μΈνλ κ²μ΄ κ°λ₯νμ§λ§, μμ²μ λ³Έλ¬Έμ΄ application/json
κ° μλ multipart/form-data
λ‘ μΈμ½λ© λκΈ° λλ¬Έμ JSONμΌλ‘ λ°μμΌνλ Body
νλλ₯Ό ν¨κ» μ μΈν μλ μμ΅λλ€.
μ΄λ FastAPIμ νκ³κ° μλλΌ, HTTP νλ‘ν μ½μ μν κ²μ λλ€.
λ€μ€ νμΌ μ λ‘λ¶
μ¬λ¬ νμΌμ λμμ μ λ‘λ ν μ μμ΅λλ€.
κ·Έλ€μ "νΌ λ°μ΄ν°"λ₯Ό μ¬μ©νμ¬ μ μ‘λ λμΌν "νΌ νλ"μ μ°κ²°λ©λλ€.
μ΄ κΈ°λ₯μ μ¬μ©νκΈ° μν΄ , bytes
μ List
λλ UploadFile
λ₯Ό μ μΈνκΈ° λ°λλλ€:
from typing import List
from fastapi import FastAPI, File, UploadFile
from fastapi.responses import HTMLResponse
app = FastAPI()
@app.post("/files/")
async def create_files(files: List[bytes] = File()):
return {"file_sizes": [len(file) for file in files]}
@app.post("/uploadfiles/")
async def create_upload_files(files: List[UploadFile]):
return {"filenames": [file.filename for file in files]}
@app.get("/")
async def main():
content = """
<body>
<form action="/files/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
<form action="/uploadfiles/" enctype="multipart/form-data" method="post">
<input name="files" type="file" multiple>
<input type="submit">
</form>
</body>
"""
return HTMLResponse(content=content)
μ μΈνλλ‘, bytes
μ list
λλ UploadFile
λ€μ μ μ‘λ°μ κ²μ
λλ€.
μ°Έκ³
2019λ 4μ 14μΌλΆν° Swagger UIκ° νλμ νΌ νλλ‘ λ€μμ νμΌμ μ λ‘λνλ κ²μ μ§μνμ§ μμ΅λλ€. λ λ§μ μ 보λ₯Ό μνλ©΄, #4276κ³Ό #3641μ μ°Έκ³ νμΈμ.
κ·ΈλΌμλ, FastAPIλ νμ€ Open APIλ₯Ό μ¬μ©ν΄ μ΄λ―Έ νΈνμ΄ κ°λ₯ν©λλ€.
λ°λΌμ Swagger UI λλ κΈ°ν κ·Έ μΈμ OpenAPIλ₯Ό μ§μνλ ν΄μ΄ λ€μ€ νμΌ μ λ‘λλ₯Ό μ§μνλ κ²½μ°, μ΄λ€μ FastAPIμ νΈνλ©λλ€.
κΈ°μ μ μΈλΆμ¬ν
from starlette.responses import HTMLResponse
μμ μ¬μ©ν μ μμ΅λλ€.
FastAPIλ κ°λ°μμ νΈμλ₯Ό μν΄ fastapi.responses
μ λμΌν starlette.responses
λ μ 곡ν©λλ€. νμ§λ§ λλΆλΆμ μλ΅λ€μ Starletteλ‘λΆν° μ§μ μ 곡λ©λλ€.
μμ½¶
νΌ λ°μ΄ν°λ‘μ¨ μ
λ ₯ λ§€κ°λ³μλ‘ μ
λ‘λν νμΌμ μ μΈν κ²½μ° File
μ μ¬μ©νκΈ° λ°λλλ€.