직렬화
필드 이름(예: model.foobar
)을 통해 직접 모델 속성에 액세스하는 것 외에도 다양한 방법으로 모델을 변환, 덤프, 직렬화 및 내보낼 수 있습니다.
!!! 팁 "직렬화 대 덤프" Pydantic은 "직렬화"와 "덤프"라는 용어를 같은 의미로 사용합니다. 둘 다 모델을 사전 또는 JSON 인코딩 문자열로 변환하는 프로세스를 나타냅니다.
Outside of Pydantic, the word "serialize" usually refers to converting in-memory data into a string or bytes.
However, in the context of Pydantic, there is a very close relationship between converting an object from a more
structured form — such as a Pydantic model, a dataclass, etc. — into a less structured form comprised of
Python built-ins such as dict.
While we could (and on occasion, do) distinguish between these scenarios by using the word "dump" when converting to
primitives and "serialize" when converting to string, for practical purposes, we frequently use the word "serialize"
to refer to both of these situations, even though it does not always imply conversion to a string or bytes.
model.model_dump(...)
¶
??? api "API 문서" pydantic.main.BaseModel.model_dump
이는 모델을 사전으로 변환하는 기본 방법입니다. 하위 모델은 재귀적으로 사전으로 변환됩니다.
!!! note 사전으로 변환되는 하위 모델에 대한 한 가지 예외는 RootModel
과 해당 하위 클래스가 래핑 사전 없이 root
필드 값을 직접 덤프한다는 것입니다. 이 작업도 재귀적으로 수행됩니다.
!!! note 계산된 필드를 사용하여 model.model_dump(...)
출력에 property
및 cached_property
데이터를 포함할 수 있습니다.
예:
from typing import Any, List, Optional
from pydantic import BaseModel, Field, Json
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: Optional[float] = 1.1
foo: str = Field(serialization_alias='foo_alias')
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
# returns a dictionary:
print(m.model_dump())
#> {'banana': 3.14, 'foo': 'hello', 'bar': {'whatever': 123}}
print(m.model_dump(include={'foo', 'bar'}))
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(m.model_dump(exclude={'foo', 'bar'}))
#> {'banana': 3.14}
print(m.model_dump(by_alias=True))
#> {'banana': 3.14, 'foo_alias': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(foo='hello', bar={'whatever': 123}).model_dump(
exclude_unset=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(banana=1.1, foo='hello', bar={'whatever': 123}).model_dump(
exclude_defaults=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(foo='hello', bar={'whatever': 123}).model_dump(
exclude_defaults=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
print(
FooBarModel(banana=None, foo='hello', bar={'whatever': 123}).model_dump(
exclude_none=True
)
)
#> {'foo': 'hello', 'bar': {'whatever': 123}}
class Model(BaseModel):
x: List[Json[Any]]
print(Model(x=['{"a": 1}', '[1, 2]']).model_dump())
#> {'x': [{'a': 1}, [1, 2]]}
print(Model(x=['{"a": 1}', '[1, 2]']).model_dump(round_trip=True))
#> {'x': ['{"a":1}', '[1,2]']}
model.model_dump_json(...)
¶
??? api "API 문서" pydantic.main.BaseModel.model_dump_json
.model_dump_json()
메서드는 .model_dump()
에서 생성된 결과와 동일한 JSON 인코딩 문자열로 모델을 직접 직렬화합니다.
자세한 내용은 인수을 참조하세요.
!!! note Pydantic은 일반적으로 사용되는 많은 유형을 간단한 json.dumps(foobar)
(예: datetime
, date
또는 UUID
)와 호환되지 않는 JSON으로 직렬화할 수 있습니다.
from datetime import datetime
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
foo: datetime
bar: BarModel
m = FooBarModel(foo=datetime(2032, 6, 1, 12, 13, 14), bar={'whatever': 123})
print(m.model_dump_json())
#> {"foo":"2032-06-01T12:13:14","bar":{"whatever":123}}
print(m.model_dump_json(indent=2))
"""
{
"foo": "2032-06-01T12:13:14",
"bar": {
"whatever": 123
}
}
"""
dict(model)
및 반복¶
Pydantic 모델은 dict(model)
사용하여 사전으로 변환할 수도 있고, 다음을 사용하여 모델의 필드를 반복할 수도 있습니다. for field_name, field_value in model:
. 이 접근 방식을 사용하면 원시 필드 값이 반환되므로 하위 모델이 사전으로 변환되지 않습니다.
예:
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: float
foo: str
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
print(dict(m))
#> {'banana': 3.14, 'foo': 'hello', 'bar': BarModel(whatever=123)}
for name, value in m:
print(f'{name}: {value}')
#> banana: 3.14
#> foo: hello
#> bar: whatever=123
또한 RootModel
'root'
키를 사용하여 사전으로 변환 됩니다 .
사용자 정의 직렬 변환기¶
Pydantic은 모델이 사전 또는 JSON으로 직렬화되는 방식을 사용자 정의하기 위해 여러 [기능적 직렬 변환기][pydantic.function_serializers]를 제공합니다.
- [
@field_serializer
][pydantic.function_serializers.field_serializer] - [
@model_serializer
][pydantic.function_serializers.model_serializer] - [
PlainSerializer
][pydantic.function_serializers.PlainSerializer] - [
WrapSerializer
][pydantic.function_serializers.WrapSerializer]
직렬화는 [@field_serializer
][pydantic.function_serializers.field_serializer] 데코레이터를 사용하여 필드에서, 그리고 [@model_serializer
][pydantic.function_serializers.model_serializer] 데코레이터를 사용하여 모델에서 사용자 정의할 수 있습니다.
from datetime import datetime, timedelta, timezone
from typing import Any, Dict
from pydantic import BaseModel, ConfigDict, field_serializer, model_serializer
class WithCustomEncoders(BaseModel):
model_config = ConfigDict(ser_json_timedelta='iso8601')
dt: datetime
diff: timedelta
@field_serializer('dt')
def serialize_dt(self, dt: datetime, _info):
return dt.timestamp()
m = WithCustomEncoders(
dt=datetime(2032, 6, 1, tzinfo=timezone.utc), diff=timedelta(hours=100)
)
print(m.model_dump_json())
#> {"dt":1969660800.0,"diff":"P4DT4H"}
class Model(BaseModel):
x: str
@model_serializer
def ser_model(self) -> Dict[str, Any]:
return {'x': f'serialized {self.x}'}
print(Model(x='test value').model_dump_json())
#> {"x":"serialized test value"}
!!! note 특수 값 '*'를 [@field_serializer
][pydantic.function_serializers.field_serializer] 데코레이터에 전달하여 모든 필드에서 단일 직렬 변환기를 호출할 수도 있습니다.
또한 [PlainSerializer
][pydantic.function_serializers.PlainSerializer] 및 [WrapSerializer
][pydantic.function_serializers.WrapSerializer]를 사용하면 직렬화 출력을 수정하는 함수를 사용할 수 있습니다.
두 직렬 변환기 모두 다음을 포함한 선택적 인수를 허용합니다.
return_type
함수의 반환 유형을 지정합니다. 생략하면 유형 주석에서 추론됩니다.when_used
이 직렬 변환기를 사용해야 하는 시기를 지정합니다. 값이 'always', 'unless-none', 'json' 및 'json-unless-none'인 문자열을 허용합니다. 기본값은 '항상'입니다.
PlainSerializer
간단한 함수를 사용하여 직렬화 출력을 수정합니다.
from typing_extensions import Annotated
from pydantic import BaseModel
from pydantic.functional_serializers import PlainSerializer
FancyInt = Annotated[
int, PlainSerializer(lambda x: f'{x:,}', return_type=str, when_used='json')
]
class MyModel(BaseModel):
x: FancyInt
print(MyModel(x=1234).model_dump())
#> {'x': 1234}
print(MyModel(x=1234).model_dump(mode='json'))
#> {'x': '1,234'}
WrapSerializer
표준 직렬화 논리를 적용하는 처리기 함수와 함께 원시 입력을 수신하고 직렬화의 최종 출력으로 반환하기 전에 결과 값을 수정할 수 있습니다.
from typing import Any
from typing_extensions import Annotated
from pydantic import BaseModel, SerializerFunctionWrapHandler
from pydantic.functional_serializers import WrapSerializer
def ser_wrap(v: Any, nxt: SerializerFunctionWrapHandler) -> str:
return f'{nxt(v + 1):,}'
FancyInt = Annotated[int, WrapSerializer(ser_wrap, when_used='json')]
class MyModel(BaseModel):
x: FancyInt
print(MyModel(x=1234).model_dump())
#> {'x': 1234}
print(MyModel(x=1234).model_dump(mode='json'))
#> {'x': '1,235'}
모델을 덤프할 때 반환 유형 재정의¶
.model_dump()
의 반환 값은 일반적으로 dict[str, Any]
로 설명될 수 있지만 @model_serializer
를 사용하면 실제로 이 서명과 일치하지 않는 값을 반환하도록 할 수 있습니다.
from pydantic import BaseModel, model_serializer
class Model(BaseModel):
x: str
@model_serializer
def ser_model(self) -> str:
return self.x
print(Model(x='not a dict').model_dump())
#> not a dict
이 작업을 수행하고 이 메서드에 대한 적절한 유형 검사를 얻으려면 if TYPE_CHECKING:
블록에서 .model_dump()
재정의할 수 있습니다.
from typing import TYPE_CHECKING, Any
from typing_extensions import Literal
from pydantic import BaseModel, model_serializer
class Model(BaseModel):
x: str
@model_serializer
def ser_model(self) -> str:
return self.x
if TYPE_CHECKING:
# Ensure type checkers see the correct return type
def model_dump(
self,
*,
mode: Literal['json', 'python'] | str = 'python',
include: Any = None,
exclude: Any = None,
by_alias: bool = False,
exclude_unset: bool = False,
exclude_defaults: bool = False,
exclude_none: bool = False,
round_trip: bool = False,
warnings: bool = True,
) -> str: ...
이 트릭은 실제로 정확히 이 목적을 위해 RootModel
에서 사용됩니다.
서브클래스 직렬화¶
표준 유형의 하위 클래스¶
표준 유형의 하위 클래스는 슈퍼 클래스처럼 자동으로 덤프됩니다.
from datetime import date, timedelta
from typing import Any, Type
from pydantic_core import core_schema
from pydantic import BaseModel, GetCoreSchemaHandler
class DayThisYear(date):
"""
Contrived example of a special type of date that
takes an int and interprets it as a day in the current year
"""
@classmethod
def __get_pydantic_core_schema__(
cls, source: Type[Any], handler: GetCoreSchemaHandler
) -> core_schema.CoreSchema:
return core_schema.no_info_after_validator_function(
cls.validate,
core_schema.int_schema(),
serialization=core_schema.format_ser_schema('%Y-%m-%d'),
)
@classmethod
def validate(cls, v: int):
return date(2023, 1, 1) + timedelta(days=v)
class FooModel(BaseModel):
date: DayThisYear
m = FooModel(date=300)
print(m.model_dump_json())
#> {"date":"2023-10-28"}
BaseModel
, 데이터 클래스, TypedDict
필드에 대한 서브클래스 인스턴스¶
주석 자체가 구조체형 유형(예: BaseModel
하위 클래스, 데이터 클래스 등)인 필드를 사용할 때 기본 동작은 하위 클래스인 경우에도 주석이 달린 유형의 인스턴스인 것처럼 속성 값을 직렬화하는 것입니다. 더 구체적으로 말하면, 주석이 달린 유형의 필드만 덤프된 객체에 포함됩니다.
from pydantic import BaseModel
class User(BaseModel):
name: str
class UserLogin(User):
password: str
class OuterModel(BaseModel):
user: User
user = UserLogin(name='pydantic', password='hunter2')
m = OuterModel(user=user)
print(m)
#> user=UserLogin(name='pydantic', password='hunter2')
print(m.model_dump()) # note: the password field is not included
#> {'user': {'name': 'pydantic'}}
!!! warning "Migration Warning" 이 동작은 모델을 dicts에 재귀적으로 덤프할 때 항상 모든 (하위 클래스) 필드를 포함하는 Pydantic V1에서 작동하는 방식과 다릅니다. 이러한 동작 변경의 이면에 있는 동기는 객체를 인스턴스화할 때 하위 클래스가 전달되더라도 직렬화할 때 포함될 수 있는 필드를 정확하게 알 수 있도록 돕는 것입니다. 특히 이는 비밀과 같은 민감한 정보를 하위 클래스의 필드로 추가할 때 예상치 못한 상황을 방지하는 데 도움이 될 수 있습니다.
duck-typing으로 직렬화 🦆¶
오리 타이핑을 이용한 직렬화란 무엇입니까?
Duck-typing serialization is the behavior of serializing an object based on the fields present in the object itself, rather than the fields present in the schema of the object. This means that when an object is serialized, fields present in a subclass, but not in the original schema, will be included in the serialized output.
This behavior was the default in Pydantic V1, but was changed in V2 to help ensure that you know precisely which fields would be included when serializing, even if subclasses get passed when instantiating the object. This helps prevent security risks when serializing subclasses with sensitive information, for example.
v1 스타일의 오리 유형 직렬화 동작을 원하는 경우 런타임 설정을 사용하거나 개별 유형에 주석을 달 수 있습니다.
- 필드/유형 수준:
SerializeAsAny
주석을 사용합니다. - 런타임 수준:
model_dump()
또는model_dump_json()
호출할 때serialize_as_any
플래그를 사용합니다.
아래에서 이러한 옵션에 대해 자세히 설명합니다.
SerializeAsAny
주석:¶
오리 유형 직렬화 동작을 원하는 경우 유형에 SerializeAsAny
주석을 사용하여 수행할 수 있습니다.
from pydantic import BaseModel, SerializeAsAny
class User(BaseModel):
name: str
class UserLogin(User):
password: str
class OuterModel(BaseModel):
as_any: SerializeAsAny[User]
as_user: User
user = UserLogin(name='pydantic', password='password')
print(OuterModel(as_any=user, as_user=user).model_dump())
"""
{
'as_any': {'name': 'pydantic', 'password': 'password'},
'as_user': {'name': 'pydantic'},
}
"""
필드에 SerializeAsAny[<SomeType>]
로 주석이 달린 경우 유효성 검사 동작은 <SomeType>
로 주석이 달린 것과 동일하며 mypy와 같은 유형 검사기도 해당 속성을 적절한 유형으로 처리합니다. 그러나 직렬화할 때 필드의 유형 힌트가 이름의 출처인 Any
인 것처럼 필드가 직렬화됩니다.
serialize_as_any
런타임 설정¶
serialize_as_any
런타임 설정을 사용하면 덕 유형의 직렬화 동작을 포함하거나 포함하지 않고 모델 데이터를 직렬화할 수 있습니다. serialize_as_any
BaseModel
및 RootModel
의 model_dump()
및 model_dump_json
메서드에 키워드 인수로 전달될 수 있습니다. TypeAdapter
의 dump_python()
및 dump_json()
메서드에 키워드 인수로 전달할 수도 있습니다.
serialize_as_any
가 True
로 설정되면 모델은 duck 형식의 직렬화 동작을 사용하여 직렬화됩니다. 즉, 모델은 스키마를 무시하고 대신 객체 자체에 직렬화 방법을 묻습니다. 특히 이는 모델 하위 클래스가 직렬화될 때 하위 클래스에는 있지만 원래 스키마에는 없는 필드가 포함된다는 것을 의미합니다.
serialize_as_any
False
(기본값)로 설정된 경우 모델은 스키마를 사용하여 직렬화됩니다. 즉, 하위 클래스에는 있지만 원래 스키마에는 없는 필드가 무시됩니다.
!!! 질문 "이 플래그가 왜 유용한가요?" 때로는 하위 클래스에 어떤 필드가 추가되었더라도 직렬화된 객체에는 원래 유형 정의에 나열된 필드만 있는지 확인하고 싶을 때가 있습니다. 이는 직렬화된 출력에 실수로 포함하고 싶지 않은 하위 클래스에 password: str
필드와 같은 항목을 추가하는 경우 유용할 수 있습니다.
예를 들어:
from pydantic import BaseModel
class User(BaseModel):
name: str
class UserLogin(User):
password: str
class OuterModel(BaseModel):
user1: User
user2: User
user = UserLogin(name='pydantic', password='password')
outer_model = OuterModel(user1=user, user2=user)
print(outer_model.model_dump(serialize_as_any=True)) # (1)!
"""
{
'user1': {'name': 'pydantic', 'password': 'password'},
'user2': {'name': 'pydantic', 'password': 'password'},
}
"""
print(outer_model.model_dump(serialize_as_any=False)) # (2)!
#> {'user1': {'name': 'pydantic'}, 'user2': {'name': 'pydantic'}}
serialize_as_any
True
로 설정하면 결과는 V1의 결과와 일치합니다.serialize_as_any
False
(V2 기본값)로 설정하면 기본 클래스가 아닌 하위 클래스에 있는 필드가 직렬화에 포함되지 않습니다.
이 설정은 중첩 패턴과 재귀 패턴에도 적용됩니다. 예를 들어:
from typing import List
from pydantic import BaseModel
class User(BaseModel):
name: str
friends: List['User']
class UserLogin(User):
password: str
class OuterModel(BaseModel):
user: User
user = UserLogin(
name='samuel',
password='pydantic-pw',
friends=[UserLogin(name='sebastian', password='fastapi-pw', friends=[])],
)
print(OuterModel(user=user).model_dump(serialize_as_any=True)) # (1)!
"""
{
'user': {
'name': 'samuel',
'friends': [
{'name': 'sebastian', 'friends': [], 'password': 'fastapi-pw'}
],
'password': 'pydantic-pw',
}
}
"""
print(OuterModel(user=user).model_dump(serialize_as_any=False)) # (2)!
"""
{'user': {'name': 'samuel', 'friends': [{'name': 'sebastian', 'friends': []}]}}
"""
- 중첩된
User
모델 인스턴스도User
하위 클래스에 고유한 필드와 함께 덤프됩니다. - 중첩된
User
모델 인스턴스도User
하위 클래스에 고유한 필드 없이 덤프됩니다.
!!! note serialize_as_any
런타임 플래그의 동작은 SerializeAsAny
주석의 동작과 거의 동일합니다. 해결하기 위해 노력하고 있는 몇 가지 미묘한 차이점이 있지만 대부분의 경우 두 가지 모두에서 동일한 동작을 기대할 수 있습니다. 이 활성 문제 의 차이점에 대해 자세히 알아보세요.
serialize_as_any
기본값 재정의(False)¶
model_dump()
및 model_dump_json()
에 대한 serialize_as_any
인수의 기본값을 재정의하는 BaseModel
의 하위 클래스를 구성하여 serialize_as_any
에 대한 기본 설정을 재정의한 다음 이를 사용하려는 모든 모델의 기본 클래스( pydantic.BaseModel
대신)로 사용할 수 있습니다. 이 기본 동작을 원합니다.
예를 들어, 기본적으로 오리 입력 직렬화를 사용하려는 경우 다음을 수행할 수 있습니다.
from typing import Any, Dict
from pydantic import BaseModel, SecretStr
class MyBaseModel(BaseModel):
def model_dump(self, **kwargs) -> Dict[str, Any]:
return super().model_dump(serialize_as_any=True, **kwargs)
def model_dump_json(self, **kwargs) -> str:
return super().model_dump_json(serialize_as_any=True, **kwargs)
class User(MyBaseModel):
name: str
class UserInfo(User):
password: SecretStr
class OuterModel(MyBaseModel):
user: User
u = OuterModel(user=UserInfo(name='John', password='secret_pw'))
print(u.model_dump_json()) # (1)!
#> {"user":{"name":"John","password":"**********"}}
- 기본적으로
model_dump_json
오리 입력 직렬화 동작을 사용합니다. 즉,password
필드가 출력에 포함됩니다.
pickle.dumps(model)
¶
Pydantic 모델은 효율적인 산세 및 역세척을 지원합니다.
import pickle
from pydantic import BaseModel
class FooBarModel(BaseModel):
a: str
b: int
m = FooBarModel(a='hello', b=123)
print(m)
#> a='hello' b=123
data = pickle.dumps(m)
print(data[:20])
#> b'\x80\x04\x95\x95\x00\x00\x00\x00\x00\x00\x00\x8c\x08__main_'
m2 = pickle.loads(data)
print(m2)
#> a='hello' b=123
고급 포함 및 제외¶
model_dump
및 model_dump_json
메소드는 세트 또는 사전이 될 수 있는 include
및 exclude
인수를 지원합니다. 이를 통해 내보낼 필드를 중첩하여 선택할 수 있습니다.
from pydantic import BaseModel, SecretStr
class User(BaseModel):
id: int
username: str
password: SecretStr
class Transaction(BaseModel):
id: str
user: User
value: int
t = Transaction(
id='1234567890',
user=User(id=42, username='JohnDoe', password='hashedpassword'),
value=9876543210,
)
# using a set:
print(t.model_dump(exclude={'user', 'value'}))
#> {'id': '1234567890'}
# using a dict:
print(t.model_dump(exclude={'user': {'username', 'password'}, 'value': True}))
#> {'id': '1234567890', 'user': {'id': 42}}
print(t.model_dump(include={'id': True, 'user': {'id'}}))
#> {'id': '1234567890', 'user': {'id': 42}}
True
는 마치 키를 세트에 포함시킨 것처럼 전체 키를 제외하거나 포함하고자 함을 나타냅니다. 이는 모든 깊이 수준에서 수행될 수 있습니다.
하위 모델이나 사전의 목록이나 튜플에서 필드를 포함하거나 제외할 때는 특별한 주의를 기울여야 합니다. 이 시나리오에서 model_dump
및 관련 메서드는 요소별 포함 또는 제외를 위해 정수 키를 기대합니다. 목록이나 튜플의 모든 멤버에서 필드를 제외하려면 다음과 같이 사전 키 '__all__'
사용할 수 있습니다.
import datetime
from typing import List
from pydantic import BaseModel, SecretStr
class Country(BaseModel):
name: str
phone_code: int
class Address(BaseModel):
post_code: int
country: Country
class CardDetails(BaseModel):
number: SecretStr
expires: datetime.date
class Hobby(BaseModel):
name: str
info: str
class User(BaseModel):
first_name: str
second_name: str
address: Address
card_details: CardDetails
hobbies: List[Hobby]
user = User(
first_name='John',
second_name='Doe',
address=Address(
post_code=123456, country=Country(name='USA', phone_code=1)
),
card_details=CardDetails(
number='4212934504460000', expires=datetime.date(2020, 5, 1)
),
hobbies=[
Hobby(name='Programming', info='Writing code and stuff'),
Hobby(name='Gaming', info='Hell Yeah!!!'),
],
)
exclude_keys = {
'second_name': True,
'address': {'post_code': True, 'country': {'phone_code'}},
'card_details': True,
# You can exclude fields from specific members of a tuple/list by index:
'hobbies': {-1: {'info'}},
}
include_keys = {
'first_name': True,
'address': {'country': {'name'}},
'hobbies': {0: True, -1: {'name'}},
}
# would be the same as user.model_dump(exclude=exclude_keys) in this case:
print(user.model_dump(include=include_keys))
"""
{
'first_name': 'John',
'address': {'country': {'name': 'USA'}},
'hobbies': [
{'name': 'Programming', 'info': 'Writing code and stuff'},
{'name': 'Gaming'},
],
}
"""
# To exclude a field from all members of a nested list or tuple, use "__all__":
print(user.model_dump(exclude={'hobbies': {'__all__': {'info'}}}))
"""
{
'first_name': 'John',
'second_name': 'Doe',
'address': {
'post_code': 123456,
'country': {'name': 'USA', 'phone_code': 1},
},
'card_details': {
'number': SecretStr('**********'),
'expires': datetime.date(2020, 5, 1),
},
'hobbies': [{'name': 'Programming'}, {'name': 'Gaming'}],
}
"""
model_dump_json
메서드에도 동일하게 적용됩니다.
모델 및 필드 수준 포함 및 제외¶
model_dump
및 model_dump_json
메소드에 전달된 명시적 인수인 exclude
및 include
외에도, exclude: bool
인수를 Field
생성자에 직접 전달할 수도 있습니다.
필드 생성자에서 exclude
설정( Field(..., exclude=True)
) model_dump
및 model_dump_json
의 exclude
/ include
보다 우선합니다.
from pydantic import BaseModel, Field, SecretStr
class User(BaseModel):
id: int
username: str
password: SecretStr = Field(..., exclude=True)
class Transaction(BaseModel):
id: str
value: int = Field(exclude=True)
t = Transaction(
id='1234567890',
value=9876543210,
)
print(t.model_dump())
#> {'id': '1234567890'}
print(t.model_dump(include={'id': True, 'value': True})) # (1)!
#> {'id': '1234567890'}
value
Field
에서 제외되었기 때문에 출력에서 제외되었습니다.
즉, 필드 생성자( Field(..., exclude=True)
)에서 exclude
설정하는 것은 model_dump
및 model_dump_json
의 exclude_unset
, exclude_none
및 exclude_default
매개변수보다 우선순위를 갖지 않습니다.
from typing import Optional
from pydantic import BaseModel, Field
class Person(BaseModel):
name: str
age: Optional[int] = Field(None, exclude=False)
person = Person(name='Jeremy')
print(person.model_dump())
#> {'name': 'Jeremy', 'age': None}
print(person.model_dump(exclude_none=True)) # (1)!
#> {'name': 'Jeremy'}
print(person.model_dump(exclude_unset=True)) # (2)!
#> {'name': 'Jeremy'}
print(person.model_dump(exclude_defaults=True)) # (3)!
#> {'name': 'Jeremy'}
exclude_none
True
로 설정되고age
None
이기 때문에 출력에서age
제외되었습니다.exclude_unset
True
로 설정되었고 Person 생성자에age
설정되지 않았기 때문에 출력에서age
제외되었습니다.exclude_defaults
True
로 설정되어 있고age
기본값인None
사용하기 때문에 출력에서age
제외되었습니다.
직렬화 컨텍스트¶
info
인수에서 데코레이팅된 직렬 변환기 함수에 액세스할 수 있는 직렬화 메서드에 컨텍스트 개체를 전달할 수 있습니다. 이는 런타임 중에 직렬화 동작을 동적으로 업데이트해야 할 때 유용합니다. 예를 들어 동적으로 제어 가능한 허용 값 집합에 따라 필드를 덤프하려는 경우 컨텍스트별로 허용 값을 전달하면 됩니다.
from pydantic import BaseModel, SerializationInfo, field_serializer
class Model(BaseModel):
text: str
@field_serializer('text')
def remove_stopwords(self, v: str, info: SerializationInfo):
context = info.context
if context:
stopwords = context.get('stopwords', set())
v = ' '.join(w for w in v.split() if w.lower() not in stopwords)
return v
model = Model.model_construct(**{'text': 'This is an example document'})
print(model.model_dump()) # no context
#> {'text': 'This is an example document'}
print(model.model_dump(context={'stopwords': ['this', 'is', 'an']}))
#> {'text': 'example document'}
print(model.model_dump(context={'stopwords': ['document']}))
#> {'text': 'This is an example'}
마찬가지로 검증을 위해 컨텍스트를 사용할 수 있습니다.
model_copy(...)
¶
??? api "API 문서" pydantic.main.BaseModel.model_copy
model_copy()
하면 모델을 복제할 수 있으며(선택적 업데이트 포함) 이는 고정된 모델로 작업할 때 특히 유용합니다.
예:
from pydantic import BaseModel
class BarModel(BaseModel):
whatever: int
class FooBarModel(BaseModel):
banana: float
foo: str
bar: BarModel
m = FooBarModel(banana=3.14, foo='hello', bar={'whatever': 123})
print(m.model_copy(update={'banana': 0}))
#> banana=0 foo='hello' bar=BarModel(whatever=123)
print(id(m.bar) == id(m.model_copy().bar))
#> True
# normal copy gives the same object reference for bar
print(id(m.bar) == id(m.model_copy(deep=True).bar))
#> False
# deep copy gives a new object reference for `bar`
本文总阅读量次