การใช้ Pydantic Model กับ Form Data ใน FastAPI
Published in
2 min readFeb 25, 2022
ปกติถ้าหากจำนวน Fields ใน Form มีไม่มากก็ไม่มีปัญหาเราสามารถเขียนแบบปกติได้
เช่น
@app.post(“/abc”, response_model=bool)
def abc(id: int = Form(…), name: str = Form(default=None),status: str = Form(default=”single”)):
return True
แต่ถ้า Fields มีเยอะ ๆ สัก 10 Fields ขึ้นไป Code ก็จะเริ่มดูยากยาวมาก การใช้ Pydantic model เข้ามาช่วยก็จะจัดการง่ายขึ้น ปกติเราใช้ Pydantic model ใน Body แบบ JSON กันอยู่แล้วแต่สำหรับ Form Data จะมีลูกเล่นนิดหนึ่ง ค้นหาใน internet ไปเจอวิธีที่คิดว่าง่ายที่สุดละเลยบันทึกไว้สักหน่อย
ต้นฉบับที่ผมนำมาใช้
https://stackoverflow.com/a/65547551
ตัวอย่าง model.py
from typing import Optional
from fastapi import Form
from pydantic import BaseModeldef form_body(cls):
cls.__signature__ = cls.__signature__.replace(
parameters=[
arg.replace(default=Form(default=arg.default) if arg.default is not inspect._empty else Form(…))
for arg in cls.__signature__.parameters.values()
]
)
return cls@form_body
class Profile(BaseModel):
passport_no: Optional[str]
hn: Optional[str]
patient_guid: Optional[str]
prefix: str = “นาย”
first_name: str
last_name: str
prefix_eng: str = “Mr”
first_name_eng: Optional[str]
middle_name_eng: Optional[str]
last_name_eng: Optional[str]
gender: int = 1
birth_date: Optional[str]
mobile_phone: Optional[str]
installed_line_connect: Optional[str]
address: Optional[str]
moo: Optional[str]
road: Optional[str]
chw_code: Optional[str]
amp_code: Optional[str]
tmb_code: Optional[str]
address_full_thai: Optional[str]
address_full_english: Optional[str]
nationality: Optional[str]
ในส่วนของ Form มันจะมีหลัก ๆ อยู่สามแบบคือ
* บังคับ
* มีค่า Default
* มีก็ได้ไม่มีก็ได้
ผมเลยปรับในตัว Decorators เพิ่มเติมให้มันปรับตาม Model ที่เรากำหนดไว้
arg.replace(default=Form(default=arg.default) if arg.default is not inspect._empty else Form(…))
ตัวอย่าง Router
from model import Profile
from fastapi import Depends, FastAPI, File, UploadFile
app = FastAPI()@app.post(“/abc”, response_model=bool)
def abc(profile: Profile = Depends(Profile), photo: UploadFile = File(…)):return True
ตอน Render ก็จะได้ประมาณนี้
ลองเอาไปประยุกต์ใช้กันดูครับ