Serialisierung
Über den direkten Zugriff auf Modellattribute über ihre Feldnamen (z. B. model.foobar
) hinaus können Modelle auf verschiedene Arten konvertiert, ausgegeben, serialisiert und exportiert werden.
!!! Tipp „Serialisieren versus Dump“ Pydantic verwendet die Begriffe „Serialisieren“ und „Dump“ synonym. Beide beziehen sich auf den Prozess der Konvertierung eines Modells in ein Wörterbuch oder eine JSON-codierte Zeichenfolge.
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-Dokumentation“ pydantic.main.BaseModel.model_dump
Dies ist die primäre Methode zum Konvertieren eines Modells in ein Wörterbuch. Untermodelle werden rekursiv in Wörterbücher umgewandelt.
!!! Hinweis Die einzige Ausnahme bei der Konvertierung von Untermodellen in Wörterbücher besteht darin, dass RootModel
und seine Unterklassen den root
direkt ohne ein umschließendes Wörterbuch ausgeben. Dies geschieht ebenfalls rekursiv.
!!! Hinweis Sie können berechnete Felder verwenden, um property
und cached_property
in die Ausgabe model.model_dump(...)
einzuschließen.
Beispiel:
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-Dokumentation“ pydantic.main.BaseModel.model_dump_json
Die Methode .model_dump_json()
serialisiert ein Modell direkt in eine JSON-codierte Zeichenfolge, die dem von .model_dump()
erzeugten Ergebnis entspricht.
Weitere Informationen finden Sie unter arguments.
!!! Hinweis: Pydantic kann viele häufig verwendete Typen in JSON serialisieren, die sonst mit einem einfachen json.dumps(foobar)
nicht kompatibel wären (z. B. datetime
, date
oder 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)
und Iteration¶
Pydantic-Modelle können auch mit dict(model)
in Wörterbücher konvertiert werden, und Sie können mit auch über die Felder eines Modells iterieren for field_name, field_value in model:
. Bei diesem Ansatz werden die Rohfeldwerte zurückgegeben, sodass Untermodelle nicht in Wörterbücher konvertiert werden.
Beispiel:
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
Beachten Sie auch, dass RootModel
mit dem Schlüssel 'root'
in ein Wörterbuch konvertiert wird .
Benutzerdefinierte Serialisierer¶
Pydantic bietet mehrere [funktionale Serialisierer][pydantic.Functional_Serializers], um anzupassen, wie ein Modell in ein Wörterbuch oder JSON serialisiert wird.
- [
@field_serializer
][pydantic.Functional_serializers.field_serializer] - [
@model_serializer
][pydantic.Functional_serializers.model_serializer] - [
PlainSerializer
][pydantic.Functional_serializers.PlainSerializer] - [
WrapSerializer
][pydantic.Functional_serializers.WrapSerializer]
Die Serialisierung kann für ein Feld mit dem Dekorator [@field_serializer
][pydantic.Functional_serializers.field_serializer] und für ein Modell mit dem Dekorator [@model_serializer
][pydantic.Functional_serializers.model_serializer] angepasst werden.
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"}
!!! Hinweis Ein einzelner Serializer kann auch für alle Felder aufgerufen werden, indem der Sonderwert „*“ an den Dekorator [@field_serializer
][pydantic.Functional_serializers.field_serializer] übergeben wird.
Darüber hinaus ermöglichen Ihnen [PlainSerializer
][pydantic.Functional_serializers.PlainSerializer] und [WrapSerializer
][pydantic.Functional_serializers.WrapSerializer] die Verwendung einer Funktion zum Ändern der Ausgabe der Serialisierung.
Beide Serialisierer akzeptieren optionale Argumente, einschließlich:
return_type
gibt den Rückgabetyp für die Funktion an. Wenn es weggelassen wird, wird es aus der Typanmerkung abgeleitet.when_used
gibt an, wann dieser Serializer verwendet werden soll. Akzeptiert eine Zeichenfolge mit den Werten „always“, „unless-none“, „json“ und „json-unless-none“. Der Standardwert ist „immer“.
PlainSerializer
verwendet eine einfache Funktion, um die Ausgabe der Serialisierung zu ändern.
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
empfängt die Roheingaben zusammen mit einer Handlerfunktion, die die Standard-Serialisierungslogik anwendet und den resultierenden Wert ändern kann, bevor er ihn als endgültige Ausgabe der Serialisierung zurückgibt.
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'}
Überschreiben des Rückgabetyps beim Speichern eines Modells¶
Während der Rückgabewert von .model_dump()
normalerweise als dict[str, Any]
beschrieben werden kann, können Sie durch die Verwendung von @model_serializer
tatsächlich bewirken, dass ein Wert zurückgegeben wird, der nicht mit dieser Signatur übereinstimmt:
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
Wenn Sie dies tun und dennoch eine ordnungsgemäße Typprüfung für diese Methode erhalten möchten, können Sie .model_dump()
in einem if TYPE_CHECKING:
-Block überschreiben:
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: ...
Dieser Trick wird in RootModel
tatsächlich genau zu diesem Zweck verwendet.
Unterklassen serialisieren¶
Unterklassen von Standardtypen¶
Unterklassen von Standardtypen werden automatisch wie ihre Oberklassen ausgegeben:
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"}
Unterklasseninstanzen für Felder von BaseModel
, Datenklassen und TypedDict
¶
Bei der Verwendung von Feldern, deren Annotationen selbst strukturähnliche Typen sind (z. B. BaseModel
Unterklassen, Datenklassen usw.), besteht das Standardverhalten darin, den Attributwert so zu serialisieren, als wäre er eine Instanz des annotierten Typs, auch wenn es sich um eine Unterklasse handelt. Genauer gesagt werden nur die Felder des mit Anmerkungen versehenen Typs in das ausgegebene Objekt aufgenommen:
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'}}
!!! Warnung „Migrationswarnung“ Dieses Verhalten unterscheidet sich von der Funktionsweise in Pydantic V1, wo wir beim rekursiven Dumpen von Modellen in Diktate immer alle (Unterklassen-)Felder einbeziehen würden. Der Grund für diese Verhaltensänderung besteht darin, dass Sie genau wissen, welche Felder bei der Serialisierung einbezogen werden könnten, auch wenn bei der Instanziierung des Objekts Unterklassen übergeben werden. Dies kann insbesondere dazu beitragen, Überraschungen zu vermeiden, wenn vertrauliche Informationen wie Geheimnisse als Felder von Unterklassen hinzugefügt werden.
Serialisieren mit Duck-Typing 🦆¶
!!! Frage „Was ist Serialisierung mit 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.
Wenn Sie ein Duck-Typing-Serialisierungsverhalten im v1-Stil wünschen, können Sie eine Laufzeiteinstellung verwenden oder einzelne Typen mit Anmerkungen versehen.
- Feld-/Typebene: Verwenden Sie die Annotation
SerializeAsAny
- Laufzeitebene: Verwenden Sie das Flag
serialize_as_any
, wenn Siemodel_dump()
odermodel_dump_json()
aufrufen.
Im Folgenden gehen wir näher auf diese Optionen ein:
SerializeAsAny
Anmerkung:¶
Wenn Sie ein Duck-Typing-Serialisierungsverhalten wünschen, können Sie dies mithilfe der SerializeAsAny
-Annotation für einen Typ erreichen:
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'},
}
"""
Wenn ein Feld als SerializeAsAny[<SomeType>]
annotiert ist, ist das Validierungsverhalten dasselbe, als ob es als <SomeType>
annotiert wäre, und Typprüfer wie mypy behandeln das Attribut ebenfalls so, als hätte es den entsprechenden Typ. Bei der Serialisierung wird das Feld jedoch so serialisiert, als ob der Typhinweis für das Feld Any
wäre, woher auch der Name stammt.
serialize_as_any
Laufzeiteinstellung¶
Die Laufzeiteinstellung serialize_as_any
kann zum Serialisieren von Modelldaten mit oder ohne Duck-Typ-Serialisierungsverhalten verwendet werden. serialize_as_any
kann als Schlüsselwortargument an die Methoden model_dump()
und model_dump_json
von BaseModel
s und RootModel
s übergeben werden. Es kann auch als Schlüsselwortargument an die Methoden dump_python()
und dump_json()
von TypeAdapter
s übergeben werden.
Wenn serialize_as_any
auf True
gesetzt ist, wird das Modell mit dem Duck-Typ-Serialisierungsverhalten serialisiert, was bedeutet, dass das Modell das Schema ignoriert und stattdessen das Objekt selbst fragt, wie es serialisiert werden soll. Dies bedeutet insbesondere, dass bei der Serialisierung von Modellunterklassen Felder einbezogen werden, die in der Unterklasse, aber nicht im ursprünglichen Schema vorhanden sind.
Wenn serialize_as_any
auf False
gesetzt ist (was die Standardeinstellung ist), wird das Modell mithilfe des Schemas serialisiert, was bedeutet, dass Felder, die in einer Unterklasse, aber nicht im ursprünglichen Schema vorhanden sind, ignoriert werden.
!!! Frage „Warum ist diese Flagge nützlich?“ Manchmal möchten Sie sicherstellen, dass unabhängig davon, welche Felder in Unterklassen hinzugefügt wurden, das serialisierte Objekt nur über die Felder verfügt, die in der ursprünglichen Typdefinition aufgeführt sind. Dies kann nützlich sein, wenn Sie in einer Unterklasse so etwas wie ein Feld password: str
hinzufügen, das Sie nicht versehentlich in die serialisierte Ausgabe einschließen möchten.
Zum Beispiel:
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'}}
- Wenn
serialize_as_any
aufTrue
gesetzt ist, entspricht das Ergebnis dem von V1. - Wenn
serialize_as_any
aufFalse
(V2-Standard) gesetzt ist, werden Felder, die in der Unterklasse, aber nicht in der Basisklasse vorhanden sind, nicht in die Serialisierung einbezogen.
Diese Einstellung wird auch bei verschachtelten und rekursiven Mustern wirksam. Zum Beispiel:
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': []}]}}
"""
- Sogar verschachtelte
User
werden mit Feldern gesichert, die nur fürUser
gelten. - Sogar verschachtelte
User
werden ohne Felder ausgegeben, die nur fürUser
gelten.
!!! Hinweis Das Verhalten des Laufzeitflags serialize_as_any
ist fast dasselbe wie das Verhalten der Annotation SerializeAsAny
. Es gibt ein paar nuancierte Unterschiede, an deren Lösung wir arbeiten, aber im Großen und Ganzen können Sie von beiden das gleiche Verhalten erwarten. Erfahren Sie mehr über die Unterschiede in dieser aktiven Ausgabe
Überschreiben des Standardwerts serialize_as_any
(False)¶
Sie können die Standardeinstellung für serialize_as_any
überschreiben, indem Sie eine Unterklasse von BaseModel
konfigurieren, die die Standardeinstellung für das Argument serialize_as_any
in model_dump()
und model_dump_json()
überschreibt, und diese dann als Basisklasse (anstelle von pydantic.BaseModel
) für jedes von Ihnen verwendete Modell verwenden Ich möchte dieses Standardverhalten haben.
Sie könnten beispielsweise Folgendes tun, wenn Sie standardmäßig die Duck-Typing-Serialisierung verwenden möchten:
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":"**********"}}
- Standardmäßig verwendet
model_dump_json
das Duck-Typing-Serialisierungsverhalten, was bedeutet, dass daspassword
in der Ausgabe enthalten ist.
pickle.dumps(model)
¶
Pydantic-Modelle unterstützen das effiziente Beizen und Entbeizen.
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
Erweitertes Einschließen und Ausschließen¶
Die Methoden model_dump
und model_dump_json
unterstützen include
und exclude
, die entweder Mengen oder Wörterbücher sein können. Dies ermöglicht eine verschachtelte Auswahl der zu exportierenden Felder:
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}}
Der True
gibt an, dass wir einen gesamten Schlüssel ausschließen oder einschließen möchten, so als ob wir ihn in einen Satz aufnehmen würden. Dies kann auf jeder Tiefenebene erfolgen.
Beim Einschließen oder Ausschließen von Feldern aus einer Liste oder einem Tupel von Untermodellen oder Wörterbüchern ist besondere Vorsicht geboten. In diesem Szenario erwarten model_dump
und verwandte Methoden ganzzahlige Schlüssel für den elementweisen Einschluss oder Ausschluss. Um ein Feld von jedem Mitglied einer Liste oder eines Tupels auszuschließen, kann der Wörterbuchschlüssel '__all__'
verwendet werden, wie hier gezeigt:
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'}],
}
"""
Das Gleiche gilt für die Methode model_dump_json
.
Ein- und Ausschluss auf Modell- und Feldebene¶
Zusätzlich zu den expliziten Argumenten exclude
und include
, die an die Methoden model_dump
und model_dump_json
übergeben werden, können wir auch die Argumente exclude: bool
direkt an den Field
Konstruktor übergeben:
Das Festlegen von exclude
auf dem Feldkonstruktor ( Field(..., exclude=True)
) hat Vorrang vor „ exclude
/ include
auf model_dump
und 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
von der Ausgabe ausgeschlossen, da er inField
ausgeschlossen wurde.
Allerdings hat das Festlegen von exclude
im Feldkonstruktor ( Field(..., exclude=True)
) keine Priorität gegenüber den Parametern exclude_unset
, exclude_none
und exclude_default
in model_dump
und 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
wurde von der Ausgabe ausgeschlossen, daexclude_none
aufTrue
gesetzt wurde undage
den WertNone
hat.age
wurde von der Ausgabe ausgeschlossen, daexclude_unset
aufTrue
gesetzt war undage
im Person-Konstruktor nicht festgelegt wurde.age
wird von der Ausgabe ausgeschlossen, daexclude_defaults
aufTrue
gesetzt wurde undage
den StandardwertNone
annimmt.
Serialisierungskontext¶
Sie können ein Kontextobjekt an die Serialisierungsmethoden übergeben, auf das über das info
Argument an dekorierte Serialisierungsfunktionen zugegriffen werden kann. Dies ist nützlich, wenn Sie das Serialisierungsverhalten während der Laufzeit dynamisch aktualisieren müssen. Wenn Sie beispielsweise möchten, dass ein Feld abhängig von einem dynamisch steuerbaren Satz zulässiger Werte ausgegeben wird, können Sie dies durch die Übergabe der zulässigen Werte nach Kontext erreichen:
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'}
Ebenso können Sie einen Kontext zur Validierung verwenden .
model_copy(...)
¶
??? API „API-Dokumentation“ pydantic.main.BaseModel.model_copy
model_copy()
ermöglicht das Duplizieren von Modellen (mit optionalen Aktualisierungen), was besonders nützlich ist, wenn mit eingefrorenen Modellen gearbeitet wird.
Beispiel:
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`
本文总阅读量次