공식문서를 번역한 내용입니다.
https://fastapi.tiangolo.com/ko/tutorial/body-nested-models/
Body - Nested Models - FastAPI
FastAPI framework, high performance, easy to learn, fast to code, ready for production
fastapi.tiangolo.com
Pydantic를 이용한 FastAPI는 좀 더 복잡한 모델의 자료형에 대해 검증, 정의, 문서화 및 사용할 수 있게한다.
리스트 필드
어트리뷰트를 서브타입으로 정의할 수 있다. 예를 들면, 파이썬의 list이다
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list = []
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
tags의 속성을 보면 리스트로 되어있음.
자료형 매개변수를 사용한 리스트 필드
파이썬은 특정 방법을 통해 내부 자료형, 또는 “자료형 매개변수”와 함께 리스트를 선언할 수 있다.
타이핑의 List 임포트하기
파이썬 3.9 이상의 버전에서는 표준 파이썬의 typing 모듈에서 List를 import 해야한다.
from typing import List, Union
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: Union[str, None] = None
price: float
tax: Union[float, None] = None
tags: List[str] = []
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
자료형 매개변수로 List 선언
list, dict, tuple과 같은 자료형 매개변수(내부 자료형)을 가진 자료형을 선언하기 위해서는
- Python 버전이 3.9보다 낮은 경우 typing모듈에서 동등한 버전을 Import한다.
- 대괄호를 사용하여 내부 유형을 "자료형 매개변수"로 전달한다 : [and]
Python 3.9 이상 버전에서는 다음과 같다.
my_list: list[str]
Python 3.9 이전 버전에서는 다음과 같다.
from typing import List
my_list: List[str]
이렇게 하면 list,dict,tuple에 자료형을 명시할 수 있다
이것은 모두 자료형 선언에 대한 표준 파이썬 문법이다.
내부 유형이 있는 모델 속성에 동일한 표준 구문을 사용한다.
이 예에서는,tags를 "문자열 목록"으로 특정지어 만들 수 있다.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: list[str] = []
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
타입 설정
그러나 tags는 unique한 문자열이기 때문에, 반복되지 않는다
그리고 파이썬은 유니크한 아이템들의 집합을 위한 특별한 데이터 자료형으로, set을 가지고 있다.
따라서 set을 임포트하고 tags를 str의 set으로써 선언할 수 있다.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
이것을 사용하면, 만약 중복된 데이터 요청을 받더라도, 유니크한 요소들의 집합으로 전환된다.
그리고 데이터를 내보낼 때, 만약 데이터가 중복되더라도 유니크한 집합으로 내보내진다.
그리고 이에 따라 주석을 달거나 문서화 된다.
중첩모델
Pydantic의 속성들은 데이터 타입이 있다.
Pydantic의 모델들은 다른 Pydantic의 속성값이 될 수 있다.
그렇기에 복잡하게 얽힌 JSON object들의 각 속성들도 잘 명시되어 있으면 데이터 검증을 통해서 다른 모델의 속성값이 될 수 있다.
서브모델의 정의
예를 들어, image 모델을 다음과 같이 정의할 수 있다.
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
image: Image | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
서브모델을 자료형으로 사용
어트리뷰트의 자료형으로 사용할 수 있다
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
image: Image | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
이것은 FastAPI가 아래와 유사한 바디를 예상한다는 의미이다.
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2,
"tags": ["rock", "metal", "bar"],
"image": {
"url": "<http://example.com/baz.jpg>",
"name": "The Foo live"
}
}
특별한 자료형과 유효성 검사
str,int,float같은 일반적인 자료형 말고, 조금더 복잡한 자료형을 상속받은 str을 사용해보겠다.
위의 Image라는 모델에서 url이라는 속성을 str형태로 정의했는데, 이 대신에 Pydantic이 가지고 있는 HttpUrl을 사용할 수 있다.
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
image: Image | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
문자열은 유효한 URL인지 확인되고, JSON 스키마 / OpenAPI 등에 문서화 된다.
서브모델의 리스트를 사용한 어트리뷰트
list나 set을 Pydantic모델의 자료형으로 선언할 수 있다
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
images: list[Image] | None = None
@app.put("/items/{item_id}")
async def update_item(item_id: int, item: Item):
results = {"item_id": item_id, "item": item}
return results
아래와 같이 JSON바디를 예상 (전환, 유효성 검사, 문서화, 기타 등등)합니다.
{
"name": "Foo",
"description": "The pretender",
"price": 42.0,
"tax": 3.2,
"tags": [
"rock",
"metal",
"bar"
],
"images": [
{
"url": "<http://example.com/baz.jpg>",
"name": "The Foo live"
},
{
"url": "<http://example.com/dave.jpg>",
"name": "The Baz"
}
]
}
🍳 images의 키가 이제 이미지 객체의 리스트를 어떻게 갖는지 명심하자
갚이 중첩된 모델
중첩해서 모델을 담을 수 있다.
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
class Item(BaseModel):
name: str
description: str | None = None
price: float
tax: float | None = None
tags: set[str] = set()
images: list[Image] | None = None
class Offer(BaseModel):
name: str
description: str | None = None
price: float
items: list[Item]
@app.post("/offers/")
async def create_offer(offer: Offer):
return offer
🍳 코드를 보면 Offer는 Item객체를 리스트로 담고 있는데, Item객체는 Image를 리스트로 담고 있다.
Bodies of pure lists
예상하는 JSON 바디의 최상위 값이 만약 JSON array (파이썬 list)라면, Pydantic 모델과 동일한 방법으로, 함수의 매개변수 속 자료형을 선언할 수 있다.
images: list[Image]
이는 아래와 같다
from fastapi import FastAPI
from pydantic import BaseModel, HttpUrl
app = FastAPI()
class Image(BaseModel):
url: HttpUrl
name: str
@app.post("/images/multiple/")
async def create_multiple_images(images: list[Image]):
return images
어디서나 가능한 편집기 지원
어디서나 편집기의 지원을 받을 수 있다
리스트의 내부의 아이템도 아래와 같이 가능하다.
Bodies of arbitrary dicts
dict형태의 값도 바디에 선언할 수 있다.
유효한 필드/어트리뷰트 이름을 (Pydantic 모델 처럼) 미리 알아야 할 필요가 없다
아직 모르는 키를 수신하려는 경우에 유용하다.
다른 유용한 경우는 int와 같은 다른 자료형이 키를 원할 때이다.
이 경우, float 값을 가진 int키가 있는 한 모든 dict을 수락한다.
from fastapi import FastAPI
app = FastAPI()
@app.post("/index-weights/")
async def create_index_weights(weights: dict[int, float]):
return weights
🍳 JSON이 키로 오직 str만 지원한다는걸 명심해야한다. 그러나 Pydantic은 자동으로 데이터 전환을 할 수 있다. 이것은, API클라이언트가 키에 문자열만 보낼 수 있더라도, 이러한 문자열들이 순수한 정수형을 포함하는 한, Pydantic은 이것들을 전환하고 유효성 검사를 진행한다. 그리고 weights로 수신한 dict은 실제로 int키와 float값을 갖게 된다.
'코딩 > FastAPI' 카테고리의 다른 글
FastAPI 배우기 - Extra Data Types (0) | 2023.07.03 |
---|---|
FastAPI 배우기 - Declare Request Example Data (0) | 2023.07.03 |
FastAPI 배우기 - Body - Fields (0) | 2023.07.03 |
FastAPI 배우기 - Body - Multiple Parameters (0) | 2023.06.27 |
FastAPI 배우기 - Path Parameters and Numeric Validations (0) | 2023.06.27 |