विषय पर बढ़ें

सीरियलाइजेशन

मॉडल विशेषताओं को सीधे उनके फ़ील्ड नामों (उदाहरण के लिए model.foobar ) के माध्यम से एक्सेस करने के अलावा, मॉडल को कई तरीकों से परिवर्तित, डंप, क्रमबद्ध और निर्यात किया जा सकता है।

!!! टिप "सीरियलाइज़ बनाम डंप" पाइडेंटिक "सीरियलाइज़" और "डंप" शब्दों का परस्पर उपयोग करता है। दोनों एक मॉडल को शब्दकोश या 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(...)

??? एपीआई "एपीआई दस्तावेज़ीकरण" pydantic.main.BaseModel.model_dump

यह किसी मॉडल को शब्दकोश में परिवर्तित करने का प्राथमिक तरीका है। उप-मॉडलों को पुनरावर्ती रूप से शब्दकोशों में परिवर्तित किया जाएगा।

!!! ध्यान दें उप-मॉडल को शब्दकोशों में परिवर्तित करने का एक अपवाद यह है कि RootModel और इसके उपवर्गों में root फ़ील्ड मान को रैपिंग डिक्शनरी के बिना सीधे डंप किया जाएगा। यह भी पुनरावर्ती रूप से किया जाता है.

!!! नोट आप 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(...)

??? एपीआई "एपीआई दस्तावेज़ीकरण" pydantic.main.BaseModel.model_dump_json

.model_dump_json() विधि एक मॉडल को सीधे JSON-एन्कोडेड स्ट्रिंग पर क्रमबद्ध करती है जो .model_dump() द्वारा उत्पादित परिणाम के बराबर है।

अधिक जानकारी के लिए तर्क देखें।

!!! नोट पाइडेंटिक आमतौर पर उपयोग किए जाने वाले कई प्रकारों को JSON में क्रमबद्ध कर सकता है जो अन्यथा एक साधारण json.dumps(foobar) (उदाहरण के लिए datetime , date या 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) और पुनरावृत्ति

पाइडेंटिक मॉडल को 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' कुंजी के साथ एक शब्दकोश में परिवर्तित हो जाता है

कस्टम सीरियलाइज़र

किसी मॉडल को शब्दकोश या JSON में क्रमबद्ध करने के तरीके को अनुकूलित करने के लिए Pydantic कई कार्यात्मक क्रमांकन प्रदान करता है।

क्रमांकन को फ़ील्ड पर @field_serializer डेकोरेटर का उपयोग करके और मॉडल पर @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"}

!!! नोट @field_serializer डेकोरेटर को विशेष मान '*' पास करके सभी फ़ील्ड पर एक एकल सीरियलाइज़र भी बुलाया जा सकता है।

इसके अलावा, PlainSerializer और WrapSerializer आपको क्रमबद्धता के आउटपुट को संशोधित करने के लिए एक फ़ंक्शन का उपयोग करने में सक्षम बनाता है।

दोनों क्रमबद्धकर्ता वैकल्पिक तर्क स्वीकार करते हैं जिनमें शामिल हैं:

  • return_type फ़ंक्शन के लिए रिटर्न प्रकार निर्दिष्ट करता है। यदि छोड़ दिया जाए तो इसका अनुमान प्रकार एनोटेशन से लगाया जाएगा।
  • when_used निर्दिष्ट करता है कि इस सीरिएलाइज़र का उपयोग कब किया जाना चाहिए। 'हमेशा', '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'}}

!!! चेतावनी "माइग्रेशन चेतावनी" यह व्यवहार पाइडेंटिक V1 में काम करने के तरीके से अलग है, जहां हम मॉडल को डिक्ट्स में पुनरावर्ती रूप से डंप करते समय हमेशा सभी (उपवर्ग) फ़ील्ड शामिल करेंगे। व्यवहार में इस बदलाव के पीछे प्रेरणा यह है कि इससे यह सुनिश्चित करने में मदद मिलती है कि आप सटीक रूप से जानते हैं कि क्रमबद्ध करते समय कौन से फ़ील्ड शामिल किए जा सकते हैं, भले ही ऑब्जेक्ट को इंस्टेंट करते समय उपवर्ग पारित हो जाएं। विशेष रूप से, यह रहस्य जैसी संवेदनशील जानकारी को उपवर्गों के फ़ील्ड के रूप में जोड़ते समय आश्चर्य को रोकने में मदद कर सकता है।

डक-टाइपिंग के साथ क्रमबद्ध करना 🦆

!!! प्रश्न "डक टाइपिंग के साथ क्रमबद्धता क्या है?"

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 s और RootModel s के model_dump() और model_dump_json तरीकों के लिए एक कीवर्ड तर्क के रूप में पारित किया जा सकता है। इसे TypeAdapter एस के dump_python() और dump_json() तरीकों के लिए एक कीवर्ड तर्क के रूप में भी पारित किया जा सकता है।

यदि serialize_as_any को True पर सेट किया गया है, तो मॉडल को डक टाइप सीरियलाइज़ेशन व्यवहार का उपयोग करके क्रमबद्ध किया जाएगा, जिसका अर्थ है कि मॉडल स्कीमा को अनदेखा कर देगा और इसके बजाय ऑब्जेक्ट से स्वयं पूछेगा कि इसे कैसे क्रमबद्ध किया जाना चाहिए। विशेष रूप से, इसका मतलब यह है कि जब मॉडल उपवर्गों को क्रमबद्ध किया जाता है, तो उपवर्ग में मौजूद फ़ील्ड शामिल किए जाएंगे, लेकिन मूल स्कीमा में नहीं।

यदि 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'}}
  1. serialize_as_any True पर सेट करने पर, परिणाम V1 से मेल खाता है।
  2. 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': []}]}}
"""
  1. यहां तक कि नेस्टेड User मॉडल उदाहरणों को User उपवर्गों के लिए अद्वितीय फ़ील्ड के साथ डंप किया जाता है।
  2. यहां तक कि नेस्टेड User मॉडल उदाहरणों को User उपवर्गों के लिए अद्वितीय फ़ील्ड के बिना डंप कर दिया जाता है।

!!! नोट serialize_as_any रनटाइम ध्वज का व्यवहार लगभग SerializeAsAny एनोटेशन के व्यवहार के समान है। कुछ बारीक अंतर हैं जिन्हें हम दूर करने के लिए काम कर रहे हैं, लेकिन अधिकांश भाग के लिए, आप दोनों से समान व्यवहार की उम्मीद कर सकते हैं। इस सक्रिय मुद्दे में अंतर के बारे में और देखें

serialize_as_any डिफ़ॉल्ट को ओवरराइड करना (गलत)

आप BaseModel के एक उपवर्ग को कॉन्फ़िगर करके serialize_as_any के लिए डिफ़ॉल्ट सेटिंग को ओवरराइड कर सकते हैं जो serialize_as_any तर्क के लिए डिफ़ॉल्ट को model_dump() और model_dump_json() पर ओवरराइड करता है, और फिर उसे किसी भी मॉडल के लिए बेस क्लास ( 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":"**********"}}
  1. डिफ़ॉल्ट रूप से, model_dump_json डक-टाइपिंग क्रमांकन व्यवहार का उपयोग करेगा, जिसका अर्थ है कि password फ़ील्ड आउटपुट में शामिल है।

pickle.dumps(model)

पाइडेंटिक मॉडल कुशल अचार और अचार निकालने का समर्थन करते हैं।

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 , हम Field कंस्ट्रक्टर को सीधे exclude: bool तर्क भी पास कर सकते हैं:

फ़ील्ड कंस्ट्रक्टर ( Field(..., exclude=True) ) पर exclude सेट करना 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'}
  1. 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'}
  1. age आउटपुट से बाहर रखा गया है क्योंकि exclude_none True पर सेट किया गया था, और age None है।
  2. age आउटपुट से बाहर रखा गया है क्योंकि exclude_unset True पर सेट किया गया था, और पर्सन कंस्ट्रक्टर में age सेट नहीं की गई थी।
  3. age आउटपुट से बाहर रखा गया है क्योंकि exclude_defaults True पर सेट किया गया था, और age None का डिफ़ॉल्ट मान लेती है।

क्रमांकन प्रसंग

आप एक संदर्भ ऑब्जेक्ट को क्रमांकन विधियों में पास कर सकते हैं जिसे 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(...)

??? एपीआई "एपीआई दस्तावेज़ीकरण" 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`

本文总阅读量