FastAPI 공식문서 따라하기[11] - Body - Nested Models
https://fastapi.tiangolo.com/tutorial/body-nested-models/ 공식문서 따라하는 글
☑️ Body Nested Models
Pydantic
를 이용한 FastAPI
는 좀 더 복잡한 모델의 자료형에 대해 검증, 정의, 문서화 및 사용할 수 있게한다.
☑️ List fields
바로 코드예제로 보겠다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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 fields with type parameter
list
에 타입을 명시하고 싶다면 어떻게 해야할까?
Python3.9 버전 ~ Python 3.6 버전에서는 List
를 typing
에서 임포트해야한다.
1
from typing import List, Union
이렇게 하면 list
,dict
,tuple
에 자료형을 명시할 수 있다.
1
2
3
4
5
#python3.9 above
my_list: list[str]
#python3.6 ~ 3.9
from typing import List,Union
my_list: List[str]
이로써 자료구조에 타입을 명시할 수 있게 되었다.
☑️ Set types
데이터가 중복이 되면 안되는 유니크한 값이라면 set
을 사용하고 싶을 것이다. 다행스럽게도 set
을 지원하는데, 다음과 같이 쓰면 된다.
1
2
3
4
5
6
# Python 3.6 above
from typing import Set,Union
my_set: Set[str] = set()
# Python 3.9 above
my_set: set[str] = set()
☑️ Nested Models
Pydantic
의 속성들은 데이터 타입이 있다.
Pydantic
의 모델들은 다른 Pydantic
의 속성값이 될 수 있다.
그렇기에 복잡하게 얽힌 JSON
object들의 각 속성들도 잘 명시되어 있으면 데이터 검증을 통해서 다른 모델의 속성값이 될 수 있다.
예를들어서 이렇게 모델을 정의할 수 있을 것이다.
1
2
3
4
5
6
7
8
9
10
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Image(BaseModel):
url: str
name: str
BaseModel
을 상속받은 Image
는 다른 클래스에서 쓰일 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
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
Item
의 image
라는 속성은 Image
객체를 받거나 None
값을 받는다.
그러면 RequestBody
에 이렇게 담아야 할 것이다.
{
"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"
}
}
☑️ Speical types and validation
str
,int
,float
같은 일반적인 자료형 말고, 조금더 복잡한 자료형을 상속받은 str
을 사용해보겠다.
위의 Image
라는 모델에서 url
이라는 속성을 str
형태로 정의했는데, 이 대신에 Pydantic
이 가지고 있는 HttpUrl
을 사용할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
저렇게 선언하면 Swagger
와 같은 문서들이 URL
의 형태인지 확인한다. 만약 아니라면
1
2
3
4
5
6
7
8
9
10
11
12
13
{
"detail": [
{
"loc": [
"body",
"image",
"url"
],
"msg": "invalid or missing URL scheme",
"type": "value_error.url.scheme"
}
]
}
라며 422 에러를 발생시킨다.
☑️ Attributes with lists of submodels
list
나 set
을 Pydantic
모델의 자료형으로 선언할 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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
이렇게 선언하면 RequestBody
에 다음과 같이 데이터를 넘길 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
{
"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"
}
]
}
☑️ Deeply nested models¶
2중으로 중첩해서 모델을 담을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
요청함수 파라미터로 list
형태를 받을 수 있다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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
데이터는 다음처럼 넣어서 확인하면 된다.
1
2
3
4
5
6
7
8
9
10
[
{
"url": "http://item1.com",
"name": "item1"
},
{
"url": "http://item2.com",
"name": "item2"
}
]
☑️ Bodies of arbitrary dicts¶
dict
형태의 값도 요청함수 파라미터로 받을 수 있다.
1
2
3
4
5
6
7
8
9
from fastapi import FastAPI
app = FastAPI()
@app.post("/index-weights/")
async def create_index_weights(weights: dict[int, float]):
return weights
1
2
3
4
{
"1" : 0.4,
"2" : 4.3
}
이런식으로 키값을 넣어주면 되는데, 의문점이 생길 것이다. key
값을 str
자료형으로 넘겼는데 에러가 뜨지 않는다.
JSON
은 오로지str
형태의 키값을 가진다.Pydantic
은 자동적으로 데이터 자료형을 변환시켜주는데 이로 인해서str
형태로 키를 넘겨도 이를 자동으로integers
로 변환해준다.