ปกติถ้าหากจำนวน 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 ไปเจอวิธีที่คิดว่าง่ายที่สุดละเลยบันทึกไว้สักหน่อย
ต้นฉบับที่ผมนำมาใช้
ตัวอย่าง model.py
from typing import Optional
from fastapi import Form
from pydantic import BaseModel
def 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 ก็จะได้ประมาณนี้
ลองเอาไปประยุกต์ใช้กันดูครับ
Top comments (4)
คือเอาไว้ทำอะไรนะครับ ?
แค่เอาไว้ลดการเขียน arguments ใน router function ให้สั้นลงครับ ถ้าไม่ใช้ model ก็ต้องยัดทั้งหมดลงใน arguments และอีกอย่างก็สามารถเอา model ไป reused ได้ด้วยครับ
Python นี่รับ request เข้ามาตัวแปรเดียวไม่ได้ใช่เปล่าครับ เลยต้องทำแบบนี้ ?
ถ้าเป็น json ส่งมาเป็น object แล้วใช้ model รับแบบนี้ได้เเลย แต่ form data มันมาแบบ field หรืออาจจะมีแล้วหว่ายังไม่ได้อ่าน doc ใหม่ 😂 ครับ