Serialisasi
Selain mengakses atribut model secara langsung melalui nama fieldnya (misalnya model.foobar
), model dapat dikonversi, dibuang, diserialkan, dan diekspor dalam beberapa cara.
!!! tip "Serialize versus dump" Pydantic menggunakan istilah "serialize" dan "dump" secara bergantian. Keduanya merujuk pada proses mengonversi model ke kamus atau string yang dikodekan 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 "Dokumentasi API" pydantic.main.BaseModel.model_dump
Ini adalah cara utama untuk mengubah model menjadi kamus. Sub-model akan dikonversi secara rekursif ke kamus.
!!! catatan Satu-satunya pengecualian pada sub-model yang dikonversi ke kamus adalah bahwa RootModel
dan subkelasnya akan memiliki nilai bidang root
yang dibuang secara langsung, tanpa kamus pembungkus. Ini juga dilakukan secara rekursif.
!!! catatan Anda dapat menggunakan bidang terhitung untuk memasukkan data property
dan cached_property
dalam keluaran model.model_dump(...)
.
Contoh:
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 "Dokumentasi API" pydantic.main.BaseModel.model_dump_json
Metode .model_dump_json()
membuat serial model secara langsung ke string berkode JSON yang setara dengan hasil yang dihasilkan oleh .model_dump()
.
Lihat argumen untuk informasi selengkapnya.
!!! catatan Pydantic dapat membuat serialisasi banyak tipe yang umum digunakan ke JSON yang seharusnya tidak kompatibel dengan json.dumps(foobar)
sederhana (misalnya datetime
, date
atau UUID
) .
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)
dan iterasi¶
Model Pydantic juga dapat dikonversi ke kamus menggunakan dict(model)
, dan Anda juga dapat mengulangi bidang model menggunakan for field_name, field_value in model:
. Dengan pendekatan ini, nilai bidang mentah dikembalikan, sehingga submodel tidak akan dikonversi ke kamus.
Contoh:
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
Perhatikan juga bahwa RootModel
dapat dikonversi ke kamus dengan kunci 'root'
.
Serializer khusus¶
Pydantic menyediakan beberapa [serialisasi fungsional][pydantic.fungsional_serializers] untuk menyesuaikan cara model diserialkan ke kamus atau JSON.
- [
@field_serializer
][pydantic.fungsional_serializers.field_serializer] - [
@model_serializer
][pydantic.fungsional_serializers.model_serializer] - [
PlainSerializer
][pydantic.fungsional_serializers.PlainSerializer] - [
WrapSerializer
][pydantic.fungsional_serializers.WrapSerializer]
Serialisasi dapat dikustomisasi pada bidang menggunakan dekorator [@field_serializer
][pydantic.fungsional_serializers.field_serializer], dan pada model menggunakan dekorator [@model_serializer
][pydantic.fungsional_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"}
!!! catatan Sebuah serializer tunggal juga dapat dipanggil di semua bidang dengan meneruskan nilai khusus '*' ke dekorator [@field_serializer
][pydantic.function_serializers.field_serializer].
Selain itu, [PlainSerializer
][pydantic.function_serializers.PlainSerializer] dan [WrapSerializer
][pydantic.function_serializers.WrapSerializer] memungkinkan Anda menggunakan fungsi untuk mengubah output serialisasi.
Kedua serializer menerima argumen opsional termasuk:
return_type
menentukan tipe kembalian untuk fungsi tersebut. Jika dihilangkan maka akan disimpulkan dari anotasi tipe.when_used
menentukan kapan serializer ini harus digunakan. Menerima string dengan nilai 'selalu', 'kecuali-tidak ada', 'json', dan 'json-kecuali-tidak ada'. Defaultnya adalah 'selalu'.
PlainSerializer
menggunakan fungsi sederhana untuk mengubah output serialisasi.
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
menerima input mentah bersama dengan fungsi handler yang menerapkan logika serialisasi standar, dan dapat mengubah nilai yang dihasilkan sebelum mengembalikannya sebagai output akhir serialisasi.
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'}
Mengganti tipe pengembalian saat membuang model¶
Meskipun nilai kembalian .model_dump()
biasanya dapat dideskripsikan sebagai dict[str, Any]
, melalui penggunaan @model_serializer
Anda sebenarnya dapat menyebabkannya mengembalikan nilai yang tidak cocok dengan tanda tangan ini:
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
Jika Anda ingin melakukan ini dan masih mendapatkan pemeriksaan tipe yang tepat untuk metode ini, Anda dapat mengganti .model_dump()
di blok if TYPE_CHECKING:
::
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: ...
Trik ini sebenarnya digunakan di RootModel
untuk tujuan ini.
Membuat serial subkelas¶
Subkelas tipe standar¶
Subkelas tipe standar secara otomatis dibuang seperti kelas supernya:
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"}
Instance subkelas untuk bidang BaseModel
, kelas data, TypedDict
¶
Saat menggunakan bidang yang anotasinya merupakan tipe mirip struct (misalnya, subkelas BaseModel
, kelas data, dll.), perilaku defaultnya adalah membuat serial nilai atribut seolah-olah itu adalah turunan dari tipe yang dianotasi, meskipun itu adalah subkelas. Lebih khusus lagi, hanya bidang dari tipe beranotasi yang akan disertakan dalam objek yang dibuang:
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'}}
!!! peringatan "Peringatan Migrasi" Perilaku ini berbeda dari cara kerjanya di Pydantic V1, di mana kami akan selalu menyertakan semua bidang (subkelas) saat membuang model ke dikt secara rekursif. Motivasi di balik perubahan perilaku ini adalah untuk membantu memastikan bahwa Anda mengetahui dengan tepat bidang mana yang dapat disertakan saat membuat serial, bahkan jika subkelas diteruskan saat membuat instance objek. Secara khusus, hal ini dapat membantu mencegah kejutan ketika menambahkan informasi sensitif seperti rahasia sebagai bidang subkelas.
Membuat serial dengan mengetik bebek 🦆¶
Apa itu serialisasi dengan pengetikan bebek?
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.
Jika Anda menginginkan perilaku serialisasi pengetikan bebek gaya v1, Anda dapat menggunakan pengaturan runtime, atau memberi anotasi pada masing-masing tipe.
- Tingkat bidang/jenis: gunakan anotasi
SerializeAsAny
- Level runtime: gunakan flag
serialize_as_any
saat memanggilmodel_dump()
ataumodel_dump_json()
Kami membahas opsi di bawah ini secara lebih rinci:
Anotasi SerializeAsAny
:¶
Jika Anda menginginkan perilaku serialisasi pengetikan bebek, ini dapat dilakukan menggunakan anotasi SerializeAsAny
pada tipe:
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'},
}
"""
Ketika sebuah bidang diberi anotasi sebagai SerializeAsAny[<SomeType>]
, perilaku validasi akan sama seperti jika diberi anotasi sebagai <SomeType>
, dan pemeriksa tipe seperti mypy akan memperlakukan atribut tersebut sebagai memiliki tipe yang sesuai juga. Namun ketika membuat serial, bidang tersebut akan diserialisasi seolah-olah petunjuk tipe untuk bidang tersebut adalah Any
, dari situlah nama tersebut berasal.
serialize_as_any
waktu proses apa pun¶
Pengaturan runtime serialize_as_any
dapat digunakan untuk membuat serialisasi data model dengan atau tanpa perilaku serialisasi yang diketik bebek. serialize_as_any
dapat diteruskan sebagai argumen kata kunci ke metode model_dump()
dan model_dump_json
dari BaseModel
s dan RootModel
s. Itu juga dapat diteruskan sebagai argumen kata kunci ke metode dump_python()
dan dump_json()
dari TypeAdapter
s.
Jika serialize_as_any
disetel ke True
, model akan diserialkan menggunakan perilaku serialisasi yang diketik bebek, yang berarti model akan mengabaikan skema dan malah menanyakan objek itu sendiri bagaimana seharusnya membuat serialisasi. Secara khusus, ini berarti bahwa ketika subkelas model diserialkan, bidang yang ada di subkelas tetapi tidak ada dalam skema asli akan disertakan.
Jika serialize_as_any
diatur ke False
(yang merupakan default), model akan diserialkan menggunakan skema, yang berarti bahwa bidang yang ada dalam subkelas tetapi tidak dalam skema asli akan diabaikan.
!!! pertanyaan "Mengapa bendera ini berguna?" Terkadang, Anda ingin memastikan bahwa bidang apa pun yang mungkin telah ditambahkan di subkelas, objek serial hanya akan memiliki bidang yang tercantum dalam definisi tipe asli. Ini bisa berguna jika Anda menambahkan sesuatu seperti bidang password: str
di subkelas yang tidak ingin Anda sertakan secara tidak sengaja dalam keluaran serial.
Misalnya:
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'}}
- Dengan
serialize_as_any
disetel keTrue
, hasilnya cocok dengan V1. - Dengan
serialize_as_any
disetel keFalse
(default V2), bidang yang ada di subkelas, namun bukan kelas dasar, tidak disertakan dalam serialisasi.
Pengaturan ini bahkan berlaku dengan pola bersarang dan rekursif juga. Misalnya:
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': []}]}}
"""
- Bahkan instance model
User
yang disarangkan dibuang dengan bidang unik untuk subkelasUser
. - Bahkan instans model
User
yang disarangkan dibuang tanpa bidang unik untuk subkelasUser
.
!!! catatan Perilaku flag runtime serialize_as_any
hampir sama dengan perilaku anotasi SerializeAsAny
. Ada beberapa perbedaan kecil yang sedang kami upayakan untuk diselesaikan, namun secara umum, Anda dapat mengharapkan perilaku yang sama dari keduanya. Lihat selengkapnya tentang perbedaan dalam terbitan aktif ini
Mengganti default serialize_as_any
(False)¶
Anda dapat mengganti pengaturan default untuk serialize_as_any
dengan mengonfigurasi subkelas BaseModel
yang menggantikan argumen default serialize_as_any
ke model_dump()
dan model_dump_json()
, lalu menggunakannya sebagai kelas dasar (bukan pydantic.BaseModel
) untuk model apa pun yang Anda pilih. ingin memiliki perilaku default ini.
Misalnya, Anda dapat melakukan hal berikut jika ingin menggunakan serialisasi pengetikan bebek secara default:
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":"**********"}}
- Secara default,
model_dump_json
akan menggunakan perilaku serialisasi pengetikan bebek, yang berarti kolompassword
disertakan dalam output.
pickle.dumps(model)
¶
Model Pydantic mendukung pengawetan dan pembongkaran yang efisien.
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
Penyertaan dan pengecualian tingkat lanjut¶
Metode model_dump
dan model_dump_json
mendukung argumen include
dan exclude
yang dapat berupa kumpulan atau kamus. Hal ini memungkinkan pemilihan bersarang bidang mana yang akan diekspor:
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
menunjukkan bahwa kita ingin mengecualikan atau menyertakan seluruh kunci, sama seperti jika kita menyertakannya dalam satu set. Hal ini dapat dilakukan pada tingkat kedalaman apa pun.
Perhatian khusus harus diberikan saat memasukkan atau mengecualikan bidang dari daftar atau tuple submodel atau kamus. Dalam skenario ini, model_dump
dan metode terkait mengharapkan kunci bilangan bulat untuk penyertaan atau pengecualian berdasarkan elemen. Untuk mengecualikan field dari setiap anggota daftar atau tupel, kunci kamus '__all__'
dapat digunakan, seperti yang ditunjukkan di sini:
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'}],
}
"""
Hal yang sama berlaku untuk metode model_dump_json
.
Penyertaan dan pengecualian tingkat model dan bidang¶
Selain argumen eksplisit exclude
dan include
yang diteruskan ke metode model_dump
dan model_dump_json
, kita juga dapat meneruskan argumen exclude: bool
langsung ke konstruktor Field
:
Menyetel exclude
pada konstruktor bidang ( Field(..., exclude=True)
) lebih diprioritaskan daripada exclude
/ include
pada model_dump
dan model_dump_json
:
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
dikecualikan dari output karena dikecualikan diField
.
Meskipun demikian, pengaturan exclude
pada konstruktor bidang ( Field(..., exclude=True)
) tidak mengambil prioritas di atas parameter exclude_unset
, exclude_none
, dan exclude_default
pada model_dump
dan model_dump_json
:
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'}
age
dikecualikan dari output karenaexclude_none
disetel keTrue
, danage
disetel keNone
.age
dikecualikan dari output karenaexclude_unset
disetel keTrue
, danage
tidak disetel di konstruktor Person.age
dikecualikan dari output karenaexclude_defaults
disetel keTrue
, danage
mengambil nilai defaultNone
.
Konteks Serialisasi¶
Anda dapat meneruskan objek konteks ke metode serialisasi yang dapat diakses dari argumen info
ke fungsi serializer yang dihias. Ini berguna ketika Anda perlu memperbarui perilaku serialisasi secara dinamis selama runtime. Misalnya, jika Anda ingin sebuah bidang dibuang bergantung pada kumpulan nilai yang diizinkan yang dapat dikontrol secara dinamis, hal ini dapat dilakukan dengan meneruskan nilai yang diizinkan berdasarkan konteks:
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'}
Demikian pula, Anda dapat menggunakan konteks untuk validasi .
model_copy(...)
¶
??? api "Dokumentasi API" pydantic.main.BaseModel.model_copy
model_copy()
memungkinkan model diduplikasi (dengan pembaruan opsional), yang sangat berguna saat bekerja dengan model yang dibekukan.
Contoh:
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`
本文总阅读量次