विषय पर बढ़ें

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

पाइडेंटिक में स्कीमा को परिभाषित करने का प्राथमिक तरीका मॉडल के माध्यम से है। मॉडल केवल वे वर्ग हैं जो pydantic.BaseModel से प्राप्त होते हैं और फ़ील्ड को एनोटेटेड विशेषताओं के रूप में परिभाषित करते हैं।

आप मॉडलों को सी जैसी भाषाओं में संरचनाओं के समान या एपीआई में एकल समापन बिंदु की आवश्यकताओं के रूप में सोच सकते हैं।

मॉडल पायथन के डेटाक्लास के साथ कई समानताएं साझा करते हैं, लेकिन कुछ सूक्ष्म-लेकिन-महत्वपूर्ण अंतरों के साथ डिजाइन किए गए हैं जो सत्यापन, क्रमबद्धता और JSON स्कीमा पीढ़ी से संबंधित कुछ वर्कफ़्लो को सुव्यवस्थित करते हैं। आप दस्तावेज़ों के डेटाक्लास अनुभाग में इसके बारे में अधिक चर्चा पा सकते हैं।

अविश्वसनीय डेटा को एक मॉडल में पारित किया जा सकता है और, पार्सिंग और सत्यापन के बाद, पाइडेंटिक गारंटी देता है कि परिणामी मॉडल उदाहरण के फ़ील्ड मॉडल पर परिभाषित फ़ील्ड प्रकारों के अनुरूप होंगे।

!!! नोट "सत्यापन - एक जानबूझकर गलत नाम" ### टीएल;डीआर

We use the term "validation" to refer to the process of instantiating a model (or other type) that adheres to specified types and
constraints. This task, which Pydantic is well known for, is most widely recognized as "validation" in colloquial terms,
even though in other contexts the term "validation" may be more restrictive.

---

### The long version

The potential confusion around the term "validation" arises from the fact that, strictly speaking, Pydantic's
primary focus doesn't align precisely with the dictionary definition of "validation":

> ### validation
> _noun_
> the action of checking or proving the validity or accuracy of something.

In Pydantic, the term "validation" refers to the process of instantiating a model (or other type) that adheres to specified
types and constraints. Pydantic guarantees the types and constraints of the output, not the input data.
This distinction becomes apparent when considering that Pydantic's `ValidationError` is raised
when data cannot be successfully parsed into a model instance.

While this distinction may initially seem subtle, it holds practical significance.
In some cases, "validation" goes beyond just model creation, and can include the copying and coercion of data.
This can involve copying arguments passed to the constructor in order to perform coercion to a new type
without mutating the original input data. For a more in-depth understanding of the implications for your usage,
refer to the [Data Conversion](#data-conversion) and [Attribute Copies](#attribute-copies) sections below.

In essence, Pydantic's primary goal is to assure that the resulting structure post-processing (termed "validation")
precisely conforms to the applied type hints. Given the widespread adoption of "validation" as the colloquial term
for this process, we will consistently use it in our documentation.

While the terms "parse" and "validation" were previously used interchangeably, moving forward, we aim to exclusively employ "validate",
with "parse" reserved specifically for discussions related to [JSON parsing](../concepts/json.md).

बुनियादी मॉडल का उपयोग

from pydantic import BaseModel


class User(BaseModel):
    id: int
    name: str = 'Jane Doe'

इस उदाहरण में, User दो फ़ील्ड वाला एक मॉडल है:

  • id , जो एक पूर्णांक है और आवश्यक है
  • name , जो एक स्ट्रिंग है और इसकी आवश्यकता नहीं है (इसका एक डिफ़ॉल्ट मान है)।

उपयोगकर्ता = उपयोगकर्ता(आईडी='123')

इस उदाहरण में, user User का एक उदाहरण है। ऑब्जेक्ट का आरंभीकरण सभी पार्सिंग और सत्यापन करेगा। यदि कोई ValidationError नहीं उठाया गया है, तो आप जानते हैं कि परिणामी मॉडल उदाहरण मान्य है।

assert user.id == 123
assert isinstance(user.id, int)
# Note that '123' was coerced to an int and its value is 123

पाइडेंटिक के जबरदस्ती तर्क पर अधिक विवरण डेटा रूपांतरण में पाया जा सकता है। किसी मॉडल के फ़ील्ड को user ऑब्जेक्ट की सामान्य विशेषताओं के रूप में एक्सेस किया जा सकता है। फ़ील्ड प्रकार के अनुसार स्ट्रिंग '123' को इंट में परिवर्तित कर दिया गया है।

assert user.name == 'Jane Doe'

जब user प्रारंभ किया गया था तब name सेट नहीं किया गया था, इसलिए इसका डिफ़ॉल्ट मान है।

assert user.model_fields_set == {'id'}

वे फ़ील्ड जो उपयोगकर्ता के प्रारंभ होने पर आपूर्ति की गई थीं।

assert user.model_dump() == {'id': 123, 'name': 'Jane Doe'}

या तो .model_dump() या dict(user) फ़ील्ड का एक निर्देश प्रदान करेगा, लेकिन .model_dump() कई अन्य तर्क ले सकता है। (ध्यान दें कि dict(user) पुनरावर्ती रूप से नेस्टेड मॉडल को dict में परिवर्तित नहीं करेगा, लेकिन .model_dump() करेगा।)

user.id = 321
assert user.id == 321

डिफ़ॉल्ट रूप से, मॉडल परिवर्तनशील होते हैं और फ़ील्ड मानों को विशेषता असाइनमेंट के माध्यम से बदला जा सकता है।

मॉडल के तरीके और गुण

उपरोक्त उदाहरण केवल हिमशैल का टिप दिखाता है कि मॉडल क्या कर सकते हैं। मॉडल में निम्नलिखित विधियाँ और विशेषताएँ होती हैं:

!!! नोट विधियों और विशेषताओं की पूरी सूची सहित वर्ग परिभाषा के लिए BaseModel देखें।

!!! टिप Pydantic V1 से परिवर्तनों के विवरण के लिए माइग्रेशन गाइड में pydantic.BaseModel में परिवर्तन देखें।

नेस्टेड मॉडल

अधिक जटिल पदानुक्रमित डेटा संरचनाओं को एनोटेशन में प्रकार के रूप में मॉडल का उपयोग करके परिभाषित किया जा सकता है।

from typing import List, Optional

from pydantic import BaseModel


class Foo(BaseModel):
    count: int
    size: Optional[float] = None


class Bar(BaseModel):
    apple: str = 'x'
    banana: str = 'y'


class Spam(BaseModel):
    foo: Foo
    bars: List[Bar]


m = Spam(foo={'count': 4}, bars=[{'apple': 'x1'}, {'apple': 'x2'}])
print(m)
"""
foo=Foo(count=4, size=None) bars=[Bar(apple='x1', banana='y'), Bar(apple='x2', banana='y')]
"""
print(m.model_dump())
"""
{
    'foo': {'count': 4, 'size': None},
    'bars': [{'apple': 'x1', 'banana': 'y'}, {'apple': 'x2', 'banana': 'y'}],
}
"""

स्व-संदर्भित मॉडल के लिए, स्थगित एनोटेशन देखें।

!!! नोट अपने मॉडल को परिभाषित करते समय, अपने फ़ील्ड नाम और उसके प्रकार, पहले से परिभाषित मॉडल या आयातित लाइब्रेरी के बीच नामकरण टकराव पर ध्यान दें।

For example, the following would yield a validation error:
```py
from typing import Optional

from pydantic import BaseModel


class Boo(BaseModel):
    int: Optional[int] = None


m = Boo(int=123)  # errors
```
An error occurs since the field  `int` is set to a default value of `None` and has the exact same name as its type, so both are interpreted to be `None`.

मॉडल स्कीमा का पुनर्निर्माण करें

मॉडल स्कीमा को model_rebuild() का उपयोग करके फिर से बनाया जा सकता है। यह पुनरावर्ती सामान्य मॉडल बनाने के लिए उपयोगी है।

from pydantic import BaseModel, PydanticUserError


class Foo(BaseModel):
    x: 'Bar'


try:
    Foo.model_json_schema()
except PydanticUserError as e:
    print(e)
    """
    `Foo` is not fully defined; you should define `Bar`, then call `Foo.model_rebuild()`.

    For further information visit https://errors.pydantic.dev/2/u/class-not-fully-defined
    """


class Bar(BaseModel):
    pass


Foo.model_rebuild()
print(Foo.model_json_schema())
"""
{
    '$defs': {'Bar': {'properties': {}, 'title': 'Bar', 'type': 'object'}},
    'properties': {'x': {'$ref': '#/$defs/Bar'}},
    'required': ['x'],
    'title': 'Foo',
    'type': 'object',
}
"""

पाइडेंटिक स्वचालित रूप से यह निर्धारित करने का प्रयास करता है कि यह कब आवश्यक है और यदि ऐसा नहीं किया गया तो त्रुटि होती है, लेकिन आप पुनरावर्ती मॉडल या जेनेरिक से निपटने के दौरान सक्रिय रूप से model_rebuild() को कॉल करना चाह सकते हैं।

V2 में, model_rebuild() ने update_forward_refs() V1 से बदल दिया। नए व्यवहार में कुछ मामूली अंतर हैं. सबसे बड़ा परिवर्तन यह है कि जब सबसे बाहरी मॉडल पर model_rebuild() को कॉल किया जाता है, तो यह पूरे मॉडल (नेस्टेड मॉडल और सभी) के सत्यापन के लिए उपयोग किया जाने वाला एक कोर स्कीमा बनाता है, इसलिए सभी प्रकार के model_rebuild() को कॉल करने से पहले स्तरों को तैयार करने की आवश्यकता है।

मनमाना वर्ग उदाहरण

(पूर्व में "ओआरएम मोड"/ from_orm के नाम से जाना जाता था।)

मॉडल फ़ील्ड नामों के अनुरूप इंस्टेंस विशेषताओं को पढ़कर पाइडेंटिक मॉडल मनमाने वर्ग उदाहरणों से भी बनाए जा सकते हैं। इस कार्यक्षमता का एक सामान्य अनुप्रयोग ऑब्जेक्ट-रिलेशनल मैपिंग (ओआरएम) के साथ एकीकरण है।

ऐसा करने के लिए, कॉन्फिग विशेषता सेट करें model_config['from_attributes'] = True . अधिक जानकारी के लिए मॉडल कॉन्फ़िग और ConfigDict देखें।

यहां उदाहरण SQLAlchemy का उपयोग करता है, लेकिन किसी भी ORM के लिए वही दृष्टिकोण काम करना चाहिए।

from typing import List

from sqlalchemy import Column, Integer, String
from sqlalchemy.dialects.postgresql import ARRAY
from sqlalchemy.orm import declarative_base
from typing_extensions import Annotated

from pydantic import BaseModel, ConfigDict, StringConstraints

Base = declarative_base()


class CompanyOrm(Base):
    __tablename__ = 'companies'

    id = Column(Integer, primary_key=True, nullable=False)
    public_key = Column(String(20), index=True, nullable=False, unique=True)
    name = Column(String(63), unique=True)
    domains = Column(ARRAY(String(255)))


class CompanyModel(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    id: int
    public_key: Annotated[str, StringConstraints(max_length=20)]
    name: Annotated[str, StringConstraints(max_length=63)]
    domains: List[Annotated[str, StringConstraints(max_length=255)]]


co_orm = CompanyOrm(
    id=123,
    public_key='foobar',
    name='Testing',
    domains=['example.com', 'foobar.com'],
)
print(co_orm)
#> <__main__.CompanyOrm object at 0x0123456789ab>
co_model = CompanyModel.model_validate(co_orm)
print(co_model)
"""
id=123 public_key='foobar' name='Testing' domains=['example.com', 'foobar.com']
"""

आरक्षित नाम

हो सकता है कि आप किसी Column नाम आरक्षित SQLAlchemy फ़ील्ड के नाम पर रखना चाहें। उस स्थिति में, Field उपनाम सुविधाजनक होंगे:

import typing

import sqlalchemy as sa
from sqlalchemy.orm import declarative_base

from pydantic import BaseModel, ConfigDict, Field


class MyModel(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    metadata: typing.Dict[str, str] = Field(alias='metadata_')


Base = declarative_base()


class SQLModel(Base):
    __tablename__ = 'my_table'
    id = sa.Column('id', sa.Integer, primary_key=True)
    # 'metadata' is reserved by SQLAlchemy, hence the '_'
    metadata_ = sa.Column('metadata', sa.JSON)


sql_model = SQLModel(metadata_={'key': 'val'}, id=1)

pydantic_model = MyModel.model_validate(sql_model)

print(pydantic_model.model_dump())
#> {'metadata': {'key': 'val'}}
print(pydantic_model.model_dump(by_alias=True))
#> {'metadata_': {'key': 'val'}}

!!! नोट उपरोक्त उदाहरण काम करता है क्योंकि फ़ील्ड जनसंख्या के लिए उपनामों को फ़ील्ड नामों पर प्राथमिकता दी जाती है। SQLModel की metadata विशेषता तक पहुँचने से ValidationError हो जाएगा।

नेस्टेड विशेषताएँ

मॉडल को पार्स करने के लिए विशेषताओं का उपयोग करते समय, मॉडल उदाहरण शीर्ष-स्तरीय विशेषताओं और गहरे-नेस्टेड विशेषताओं दोनों से उचित रूप से बनाए जाएंगे।

यहां सिद्धांत को प्रदर्शित करने वाला एक उदाहरण दिया गया है:

from typing import List

from pydantic import BaseModel, ConfigDict


class PetCls:
    def __init__(self, *, name: str, species: str):
        self.name = name
        self.species = species


class PersonCls:
    def __init__(self, *, name: str, age: float = None, pets: List[PetCls]):
        self.name = name
        self.age = age
        self.pets = pets


class Pet(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    name: str
    species: str


class Person(BaseModel):
    model_config = ConfigDict(from_attributes=True)

    name: str
    age: float = None
    pets: List[Pet]


bones = PetCls(name='Bones', species='dog')
orion = PetCls(name='Orion', species='cat')
anna = PersonCls(name='Anna', age=20, pets=[bones, orion])
anna_model = Person.model_validate(anna)
print(anna_model)
"""
name='Anna' age=20.0 pets=[Pet(name='Bones', species='dog'), Pet(name='Orion', species='cat')]
"""

त्रुटि प्रबंधन

जब भी पाइडेंटिक को अपने द्वारा सत्यापित किए जा रहे डेटा में कोई त्रुटि मिलेगी तो वह ValidationError बढ़ा देगा।

पाई गई त्रुटियों की संख्या की परवाह किए बिना ValidationError प्रकार का एक अपवाद उठाया जाएगा, और उस ValidationError सभी त्रुटियों और वे कैसे हुईं, इसके बारे में जानकारी होगी।

मानक और कस्टम त्रुटियों के विवरण के लिए त्रुटि प्रबंधन देखें।

एक प्रदर्शन के रूप में:

from typing import List

from pydantic import BaseModel, ValidationError


class Model(BaseModel):
    list_of_ints: List[int]
    a_float: float


data = dict(
    list_of_ints=['1', 2, 'bad'],
    a_float='not a float',
)

try:
    Model(**data)
except ValidationError as e:
    print(e)
    """
    2 validation errors for Model
    list_of_ints.2
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='bad', input_type=str]
    a_float
      Input should be a valid number, unable to parse string as a number [type=float_parsing, input_value='not a float', input_type=str]
    """

सहायक कार्य

पाइडेंटिक डेटा पार्सिंग के लिए मॉडल पर तीन classmethod सहायक फ़ंक्शन प्रदान करता है:

  • model_validate(): यह मॉडल की __init__ विधि के समान है, सिवाय इसके कि यह कीवर्ड तर्कों के बजाय एक निर्देश या ऑब्जेक्ट लेता है। यदि पारित वस्तु को मान्य नहीं किया जा सकता है, या यदि यह विचाराधीन मॉडल का शब्दकोश या उदाहरण नहीं है, तो एक ValidationError उठाया जाएगा।
  • model_validate_json(): यह एक str या बाइट्स लेता है और इसे json के रूप में पार्स करता है, फिर परिणाम को model_validate() पर भेजता है।
  • model_validate_strings(): यह स्ट्रिंग कुंजियों और मानों के साथ एक निर्देश लेता है (नेस्ट किया जा सकता है) और json मोड में डेटा को मान्य करता है ताकि उक्त स्ट्रिंग्स को सही प्रकारों में शामिल किया जा सके।

    from datetime import datetime from typing import Optional

    from pydantic import BaseModel, ValidationError

    class User(BaseModel): id: int name: str = 'John Doe' signup_ts: Optional[datetime] = None

    m = User.model_validate({'id': 123, 'name': 'James'}) print(m)

    > id=123 name='James' signup_ts=None

    try: User.model_validate(['not', 'a', 'dict']) except ValidationError as e: print(e) """ 1 validation error for User Input should be a valid dictionary or instance of User [type=model_type, input_value=['not', 'a', 'dict'], input_type=list] """

    m = User.model_validate_json('{"id": 123, "name": "James"}') print(m)

    > id=123 name='James' signup_ts=None

    try: m = User.model_validate_json('{"id": 123, "name": 123}') except ValidationError as e: print(e) """ 1 validation error for User name Input should be a valid string [type=string_type, input_value=123, input_type=int] """

    try: m = User.model_validate_json('invalid JSON') except ValidationError as e: print(e) """ 1 validation error for User Invalid JSON: expected value at line 1 column 1 [type=json_invalid, input_value='invalid JSON', input_type=str] """

    m = User.model_validate_strings({'id': '123', 'name': 'James'}) print(m)

    > id=123 name='James' signup_ts=None

    m = User.model_validate_strings( {'id': '123', 'name': 'James', 'signup_ts': '2024-04-01T12:00:00'} ) print(m)

    > id=123 name='James' signup_ts=datetime.datetime(2024, 4, 1, 12, 0)

    try: m = User.model_validate_strings( {'id': '123', 'name': 'James', 'signup_ts': '2024-04-01'}, strict=True ) except ValidationError as e: print(e) """ 1 validation error for User signup_ts Input should be a valid datetime, invalid datetime separator, expected T, t, _ or space [type=datetime_parsing, input_value='2024-04-01', input_type=str] """

यदि आप JSON के अलावा किसी अन्य प्रारूप में क्रमबद्ध डेटा को मान्य करना चाहते हैं, तो आपको डेटा को स्वयं एक निर्देश में लोड करना चाहिए और फिर इसे model_validate पर पास करना चाहिए।

!!! नोट शामिल प्रकार और मॉडल कॉन्फ़िगरेशन के आधार पर, model_validate और model_validate_json का सत्यापन व्यवहार भिन्न हो सकता है। यदि आपके पास गैर-JSON स्रोत से आने वाला डेटा है, लेकिन आप वही सत्यापन व्यवहार और त्रुटियां चाहते हैं जो आपको model_validate_json से मिलती है, तो अभी के लिए हमारी अनुशंसा है कि आप इनमें से किसी एक का उपयोग करें model_validate_json(json.dumps(data)) , या उपयोग करें model_validate_strings यदि डेटा स्ट्रिंग कुंजियों और मानों के साथ (संभावित रूप से नेस्टेड) निर्देश का रूप लेता है।

!!! नोट दस्तावेज़ों के JSON अनुभाग में JSON पार्सिंग के बारे में अधिक जानें।

!!! ध्यान दें यदि आप किसी मॉडल का उदाहरण model_validate में पास कर रहे हैं, तो आप मॉडल की कॉन्फ़िगरेशन में revalidate_instances सेट करने पर विचार करना चाहेंगे। यदि आप यह मान सेट नहीं करते हैं, तो मॉडल इंस्टेंस पर सत्यापन छोड़ दिया जाएगा। नीचे दिया गया उदाहरण देखें:

\=== "❌ revalidate_instances='never' " ```pydantic आयात बेसमॉडल से py

class Model(BaseModel):
    a: int


m = Model(a=0)
# note: the `model_config` setting validate_assignment=True` can prevent this kind of misbehavior
m.a = 'not an int'

# doesn't raise a validation error even though m is invalid
m2 = Model.model_validate(m)
```

\=== "✅ revalidate_instances='always' " ```pydantic आयात से py BaseModel, ConfigDict, ValidationError

class Model(BaseModel):
    a: int

    model_config = ConfigDict(revalidate_instances='always')


m = Model(a=0)
# note: the `model_config` setting validate_assignment=True` can prevent this kind of misbehavior
m.a = 'not an int'

try:
    m2 = Model.model_validate(m)
except ValidationError as e:
    print(e)
    """
    1 validation error for Model
    a
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='not an int', input_type=str]
    """
```

सत्यापन के बिना मॉडल बनाना

पाइडेंटिक model_construct() विधि भी प्रदान करता है, जो बिना सत्यापन के मॉडल बनाने की अनुमति देता है। यह कम से कम कुछ मामलों में उपयोगी हो सकता है:

  • जटिल डेटा के साथ काम करते समय जो पहले से ही वैध माना जाता है (प्रदर्शन कारणों से)
  • जब एक या अधिक सत्यापनकर्ता कार्य गैर-निष्क्रिय हों, या
  • जब एक या अधिक सत्यापनकर्ता कार्यों के दुष्प्रभाव होते हैं जिन्हें आप ट्रिगर नहीं करना चाहते हैं।

!!! नोट Pydantic V2 में, BaseModel.__init__ और BaseModel.model_construct के बीच प्रदर्शन अंतर काफी कम हो गया है। सरल मॉडलों के लिए, BaseModel.__init__ कॉल करना और भी तेज़ हो सकता है। यदि आप प्रदर्शन कारणों से model_construct() का उपयोग कर रहे हैं, तो आप यह मानने से पहले अपने उपयोग के मामले को प्रोफाइल करना चाहेंगे कि model_construct() तेज़ है।

!!! चेतावनी model_construct() कोई सत्यापन नहीं करता है, जिसका अर्थ है कि यह ऐसे मॉडल बना सकता है जो अमान्य हैं। आपको कभी भी model_construct() विधि का उपयोग केवल उस डेटा के साथ करना चाहिए जो पहले ही मान्य हो चुका है, या जिस पर आप निश्चित रूप से भरोसा करते हैं।

from pydantic import BaseModel


class User(BaseModel):
    id: int
    age: int
    name: str = 'John Doe'


original_user = User(id=123, age=32)

user_data = original_user.model_dump()
print(user_data)
#> {'id': 123, 'age': 32, 'name': 'John Doe'}
fields_set = original_user.model_fields_set
print(fields_set)
#> {'age', 'id'}

# ...
# pass user_data and fields_set to RPC or save to the database etc.
# ...

# you can then create a new instance of User without
# re-running validation which would be unnecessary at this point:
new_user = User.model_construct(_fields_set=fields_set, **user_data)
print(repr(new_user))
#> User(id=123, age=32, name='John Doe')
print(new_user.model_fields_set)
#> {'age', 'id'}

# construct can be dangerous, only use it with validated data!:
bad_user = User.model_construct(id='dog')
print(repr(bad_user))
#> User(id='dog', name='John Doe')

model_construct() के लिए _fields_set कीवर्ड तर्क वैकल्पिक है, लेकिन आपको इस बारे में अधिक सटीक होने की अनुमति देता है कि कौन से फ़ील्ड मूल रूप से सेट किए गए थे और कौन से नहीं। यदि इसे छोड़ दिया जाए तो model_fields_set केवल प्रदान किए गए डेटा की कुंजी होगी।

उदाहरण के लिए, उपरोक्त उदाहरण में, यदि _fields_set प्रदान नहीं किया गया था, तो new_user.model_fields_set {'id', 'age', 'name'} होगा।

ध्यान दें कि RootModel के उपवर्गों के लिए, कीवर्ड तर्क का उपयोग करने के बजाय, रूट मान को स्थितिगत रूप से model_construct() पर पास किया जा सकता है।

यहां model_construct() के व्यवहार पर कुछ अतिरिक्त नोट्स दिए गए हैं:

  • जब हम कहते हैं "कोई सत्यापन नहीं किया जाता है" - इसमें डिक्ट्स को मॉडल उदाहरणों में परिवर्तित करना शामिल है। तो अगर आपके पास कोई फ़ील्ड है एक Model प्रकार के साथ, आपको model_construct() में पास करने से पहले आंतरिक निर्देश को स्वयं एक मॉडल में परिवर्तित करना होगा।
    • विशेष रूप से, model_construct() विधि डिक्ट्स से पुनरावर्ती रूप से मॉडल बनाने का समर्थन नहीं करती है।
  • यदि आप डिफ़ॉल्ट वाले फ़ील्ड के लिए कीवर्ड तर्क पारित नहीं करते हैं, तो डिफ़ॉल्ट मान अभी भी उपयोग किए जाएंगे।
  • निजी विशेषताओं वाले मॉडलों के लिए, __pydantic_private__ निर्देश को उसी तरह प्रारंभ किया जाएगा जैसा कि __init__ कॉल करते समय किया जाएगा।
  • model_construct() का उपयोग करके एक उदाहरण का निर्माण करते समय, मॉडल या उसके किसी भी मूल वर्ग से कोई __init__ विधि नहीं बुलाई जाएगी, भले ही एक कस्टम __init__ विधि परिभाषित की गई हो।

!!! नोट " model_construct के साथ extra व्यवहार पर" * मॉडलों के लिए model_config['extra'] == 'allow' , फ़ील्ड से संबंधित डेटा को __pydantic_extra__ dict में सही ढंग से संग्रहीत नहीं किया जाएगा और मॉडल के __dict__ में सहेजा जाएगा। * मॉडलों के लिए model_config['extra'] == 'ignore' , फ़ील्ड के अनुरूप नहीं होने वाले डेटा को अनदेखा कर दिया जाएगा - अर्थात, उदाहरण पर __pydantic_extra__ या __dict__ में संग्रहीत नहीं किया जाएगा। * __init__ पर कॉल के विपरीत, model_construct के साथ कॉल model_config['extra'] == 'forbid' फ़ील्ड के अनुरूप डेटा की उपस्थिति में कोई त्रुटि उत्पन्न नहीं होती है। बल्कि, उक्त इनपुट डेटा को आसानी से नजरअंदाज कर दिया जाता है।

सामान्य मॉडल

पाइडेंटिक सामान्य मॉडल संरचना का पुन: उपयोग करना आसान बनाने के लिए सामान्य मॉडल के निर्माण का समर्थन करता है।

एक सामान्य मॉडल घोषित करने के लिए, आप निम्नलिखित कदम उठाते हैं:

  1. अपने मॉडल को पैरामीटराइज़ करने के लिए उपयोग करने के लिए एक या अधिक typing.TypeVar उदाहरण घोषित करें।
  2. एक पाइडेंटिक मॉडल घोषित करें जो pydantic.BaseModel और typing.Generic से विरासत में मिला है, जहां आप typing.Generic पैरामीटर के रूप में TypeVar उदाहरणों को पास करते हैं।
  3. TypeVar उदाहरणों को एनोटेशन के रूप में उपयोग करें जहां आप उन्हें अन्य प्रकार या पाइडेंटिक मॉडल के साथ बदलना चाहेंगे।

आसानी से पुन: उपयोग किए जाने वाले HTTP प्रतिक्रिया पेलोड रैपर बनाने के लिए सामान्य BaseModel उपवर्ग का उपयोग करने का एक उदाहरण यहां दिया गया है:

from typing import Generic, List, Optional, TypeVar

from pydantic import BaseModel, ValidationError

DataT = TypeVar('DataT')


class DataModel(BaseModel):
    numbers: List[int]
    people: List[str]


class Response(BaseModel, Generic[DataT]):
    data: Optional[DataT] = None


print(Response[int](data=1))
#> data=1
print(Response[str](data='value'))
#> data='value'
print(Response[str](data='value').model_dump())
#> {'data': 'value'}

data = DataModel(numbers=[1, 2, 3], people=[])
print(Response[DataModel](data=data).model_dump())
#> {'data': {'numbers': [1, 2, 3], 'people': []}}
try:
    Response[int](data='value')
except ValidationError as e:
    print(e)
    """
    1 validation error for Response[int]
    data
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='value', input_type=str]
    """

यदि आप अपने जेनेरिक मॉडल परिभाषा में model_config सेट करते हैं या @field_validator या अन्य Pydantic डेकोरेटर का उपयोग करते हैं, तो उन्हें उसी तरह पैरामीट्रिज्ड उपवर्गों पर लागू किया जाएगा जैसे BaseModel उपवर्ग से इनहेरिट करते समय। आपके सामान्य वर्ग पर परिभाषित कोई भी विधि भी विरासत में मिलेगी।

पाइडेंटिक के जेनेरिक भी टाइप चेकर्स के साथ ठीक से एकीकृत होते हैं, इसलिए आपको सभी प्रकार की जांच मिलती है जिसकी आप अपेक्षा करते हैं यदि आप प्रत्येक पैरामीट्रिजेशन के लिए एक अलग प्रकार की घोषणा करते हैं।

!!! ध्यान दें आंतरिक रूप से, पाइडेंटिक रनटाइम पर BaseModel के उपवर्ग बनाता है जब जेनेरिक मॉडल पैरामीट्रिज्ड होते हैं। ये कक्षाएं कैश्ड हैं, इसलिए जेनेरिक मॉडल के उपयोग से न्यूनतम ओवरहेड होना चाहिए।

एक सामान्य मॉडल से विरासत में मिलने और इस तथ्य को संरक्षित करने के लिए कि यह सामान्य है, उपवर्ग को typing.Generic से भी विरासत में मिलना चाहिए। सामान्य:

from typing import Generic, TypeVar

from pydantic import BaseModel

TypeX = TypeVar('TypeX')


class BaseClass(BaseModel, Generic[TypeX]):
    X: TypeX


class ChildClass(BaseClass[TypeX], Generic[TypeX]):
    # Inherit from Generic[TypeX]
    pass


# Replace TypeX by int
print(ChildClass[int](X=1))
#> X=1

आप BaseModel का एक सामान्य उपवर्ग भी बना सकते हैं जो सुपरक्लास में प्रकार के मापदंडों को आंशिक रूप से या पूरी तरह से बदल देता है:

from typing import Generic, TypeVar

from pydantic import BaseModel

TypeX = TypeVar('TypeX')
TypeY = TypeVar('TypeY')
TypeZ = TypeVar('TypeZ')


class BaseClass(BaseModel, Generic[TypeX, TypeY]):
    x: TypeX
    y: TypeY


class ChildClass(BaseClass[int, TypeY], Generic[TypeY, TypeZ]):
    z: TypeZ


# Replace TypeY by str
print(ChildClass[str, int](x='1', y='y', z='3'))
#> x=1 y='y' z=3

यदि ठोस उपवर्गों का नाम महत्वपूर्ण है, तो आप डिफ़ॉल्ट नाम पीढ़ी को ओवरराइड भी कर सकते हैं:

from typing import Any, Generic, Tuple, Type, TypeVar

from pydantic import BaseModel

DataT = TypeVar('DataT')


class Response(BaseModel, Generic[DataT]):
    data: DataT

    @classmethod
    def model_parametrized_name(cls, params: Tuple[Type[Any], ...]) -> str:
        return f'{params[0].__name__.title()}Response'


print(repr(Response[int](data=1)))
#> IntResponse(data=1)
print(repr(Response[str](data='a')))
#> StrResponse(data='a')

आप अन्य मॉडलों में प्रकार के रूप में पैरामीट्रिज्ड जेनेरिक मॉडल का उपयोग कर सकते हैं:

from typing import Generic, TypeVar

from pydantic import BaseModel

T = TypeVar('T')


class ResponseModel(BaseModel, Generic[T]):
    content: T


class Product(BaseModel):
    name: str
    price: float


class Order(BaseModel):
    id: int
    product: ResponseModel[Product]


product = Product(name='Apple', price=0.5)
response = ResponseModel[Product](content=product)
order = Order(id=1, product=response)
print(repr(order))
"""
Order(id=1, product=ResponseModel[Product](content=Product(name='Apple', price=0.5)))
"""

!!! युक्ति किसी अन्य मॉडल में एक प्रकार के रूप में पैरामीट्रिज्ड जेनेरिक मॉडल का उपयोग करते समय (जैसे product: ResponseModel[Product] ), जब आप मॉडल उदाहरण आरंभ करते हैं तो उक्त सामान्य मॉडल को पैरामीट्रिज करना सुनिश्चित करें (जैसे response = ResponseModel[Product](content=product) ). यदि आप ऐसा नहीं करते हैं, तो एक ValidationError उठाया जाएगा, क्योंकि Pydantic उसे दिए गए डेटा के आधार पर जेनेरिक मॉडल के प्रकार का अनुमान नहीं लगाता है।

नेस्टेड मॉडल में समान TypeVar उपयोग करने से आप अपने मॉडल में विभिन्न बिंदुओं पर टाइपिंग संबंधों को लागू कर सकते हैं:

from typing import Generic, TypeVar

from pydantic import BaseModel, ValidationError

T = TypeVar('T')


class InnerT(BaseModel, Generic[T]):
    inner: T


class OuterT(BaseModel, Generic[T]):
    outer: T
    nested: InnerT[T]


nested = InnerT[int](inner=1)
print(OuterT[int](outer=1, nested=nested))
#> outer=1 nested=InnerT[int](inner=1)
try:
    nested = InnerT[str](inner='a')
    print(OuterT[int](outer='a', nested=nested))
except ValidationError as e:
    print(e)
    """
    2 validation errors for OuterT[int]
    outer
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
    nested
      Input should be a valid dictionary or instance of InnerT[int] [type=model_type, input_value=InnerT[str](inner='a'), input_type=InnerT[str]]
    """

बाउंड टाइप पैरामीटर्स का उपयोग करते समय, और टाइप पैरामीटर्स को अनिर्दिष्ट छोड़ते समय, पाइडेंटिक जेनेरिक मॉडल के साथ उसी तरह व्यवहार करता है जैसे वह List और Dict जैसे अंतर्निहित जेनेरिक प्रकारों के साथ व्यवहार करता है:

  • यदि आप जेनेरिक मॉडल को तुरंत चालू करने से पहले पैरामीटर निर्दिष्ट नहीं करते हैं, तो उन्हें TypeVar की सीमा के रूप में मान्य किया जाता है।
  • यदि शामिल TypeVar की कोई सीमा नहीं है, तो उन्हें Any रूप में माना जाता है।

इसके अलावा, List और Dict की तरह, TypeVar उपयोग करके निर्दिष्ट किसी भी पैरामीटर को बाद में ठोस प्रकारों से प्रतिस्थापित किया जा सकता है:

from typing import Generic, TypeVar

from pydantic import BaseModel, ValidationError

AT = TypeVar('AT')
BT = TypeVar('BT')


class Model(BaseModel, Generic[AT, BT]):
    a: AT
    b: BT


print(Model(a='a', b='a'))
#> a='a' b='a'

IntT = TypeVar('IntT', bound=int)
typevar_model = Model[int, IntT]
print(typevar_model(a=1, b=1))
#> a=1 b=1
try:
    typevar_model(a='a', b='a')
except ValidationError as exc:
    print(exc)
    """
    2 validation errors for Model[int, TypeVar]
    a
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
    b
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
    """

concrete_model = typevar_model[int]
print(concrete_model(a=1, b=1))
#> a=1 b=1

!!! चेतावनी हालांकि इससे कोई त्रुटि नहीं हो सकती है, हम आईइंस्टेंस जांच में पैरामीट्रिज्ड जेनेरिक का उपयोग करने के खिलाफ दृढ़ता से सलाह देते हैं।

For example, you should not do `isinstance(my_model, MyGenericModel[int])`. However, it is fine to do `isinstance(my_model, MyGenericModel)`. (Note that, for standard generics, it would raise an error to do a subclass check with a parameterized generic.)

If you need to perform isinstance checks against parametrized generics, you can do this by subclassing the parametrized generic class. This looks like `class MyIntModel(MyGenericModel[int]): ...` and `isinstance(my_model, MyIntModel)`.

यदि एक पाइडेंटिक मॉडल का उपयोग TypeVar बाउंड में किया जाता है और सामान्य प्रकार को कभी भी पैरामीट्रिज्ड नहीं किया जाता है तो पाइडेंटिक सत्यापन के लिए बाउंड का उपयोग करेगा लेकिन क्रमांकन के संदर्भ में मान को Any के रूप में मानेगा:

from typing import Generic, Optional, TypeVar

from pydantic import BaseModel


class ErrorDetails(BaseModel):
    foo: str


ErrorDataT = TypeVar('ErrorDataT', bound=ErrorDetails)


class Error(BaseModel, Generic[ErrorDataT]):
    message: str
    details: Optional[ErrorDataT]


class MyErrorDetails(ErrorDetails):
    bar: str


# serialized as Any
error = Error(
    message='We just had an error',
    details=MyErrorDetails(foo='var', bar='var2'),
)
assert error.model_dump() == {
    'message': 'We just had an error',
    'details': {
        'foo': 'var',
        'bar': 'var2',
    },
}

# serialized using the concrete parametrization
# note that `'bar': 'var2'` is missing
error = Error[ErrorDetails](
    message='We just had an error',
    details=ErrorDetails(foo='var'),
)
assert error.model_dump() == {
    'message': 'We just had an error',
    'details': {
        'foo': 'var',
    },
}

यहां उपरोक्त व्यवहार का एक और उदाहरण दिया गया है, जिसमें बाउंड स्पेसिफिकेशन और सामान्य प्रकार के पैरामीट्रिजेशन के संबंध में सभी क्रमपरिवर्तनों की गणना की गई है:

from typing import Generic

from typing_extensions import TypeVar

from pydantic import BaseModel

TBound = TypeVar('TBound', bound=BaseModel)
TNoBound = TypeVar('TNoBound')


class IntValue(BaseModel):
    value: int


class ItemBound(BaseModel, Generic[TBound]):
    item: TBound


class ItemNoBound(BaseModel, Generic[TNoBound]):
    item: TNoBound


item_bound_inferred = ItemBound(item=IntValue(value=3))
item_bound_explicit = ItemBound[IntValue](item=IntValue(value=3))
item_no_bound_inferred = ItemNoBound(item=IntValue(value=3))
item_no_bound_explicit = ItemNoBound[IntValue](item=IntValue(value=3))

# calling `print(x.model_dump())` on any of the above instances results in the following:
#> {'item': {'value': 3}}

यदि आप default=... (पायथन >= 3.13 में या typing-extensions के माध्यम से उपलब्ध) या बाधाओं ( TypeVar('T', str, int) उपयोग करते हैं; ध्यान दें कि आप शायद ही कभी TypeVar के इस रूप का उपयोग करना चाहते हैं) तो यदि प्रकार चर पैरामीट्रिज्ड नहीं है तो डिफ़ॉल्ट मान या बाधाओं का उपयोग सत्यापन और क्रमबद्धता दोनों के लिए किया जाएगा। आप pydantic.SerializeAsAny का उपयोग करके इस व्यवहार को ओवरराइड कर सकते हैं:

from typing import Generic, Optional

from typing_extensions import TypeVar

from pydantic import BaseModel, SerializeAsAny


class ErrorDetails(BaseModel):
    foo: str


ErrorDataT = TypeVar('ErrorDataT', default=ErrorDetails)


class Error(BaseModel, Generic[ErrorDataT]):
    message: str
    details: Optional[ErrorDataT]


class MyErrorDetails(ErrorDetails):
    bar: str


# serialized using the default's serializer
error = Error(
    message='We just had an error',
    details=MyErrorDetails(foo='var', bar='var2'),
)
assert error.model_dump() == {
    'message': 'We just had an error',
    'details': {
        'foo': 'var',
    },
}


class SerializeAsAnyError(BaseModel, Generic[ErrorDataT]):
    message: str
    details: Optional[SerializeAsAny[ErrorDataT]]


# serialized as Any
error = SerializeAsAnyError(
    message='We just had an error',
    details=MyErrorDetails(foo='var', bar='baz'),
)
assert error.model_dump() == {
    'message': 'We just had an error',
    'details': {
        'foo': 'var',
        'bar': 'baz',
    },
}

!!! ध्यान दें, यदि आप किसी जेनेरिक को पैरामीट्रिज़ नहीं करते हैं तो आपको थोड़ी परेशानी हो सकती है, जबकि जेनेरिक की सीमा के विरुद्ध सत्यापन करने से डेटा हानि हो सकती है। नीचे उदाहरण देखें:

from typing import Generic

from typing_extensions import TypeVar

from pydantic import BaseModel

TItem = TypeVar('TItem', bound='ItemBase')


class ItemBase(BaseModel): ...


class IntItem(ItemBase):
    value: int


class ItemHolder(BaseModel, Generic[TItem]):
    item: TItem


loaded_data = {'item': {'value': 1}}


print(ItemHolder(**loaded_data).model_dump())  # (1)!
#> {'item': {}}

print(ItemHolder[IntItem](**loaded_data).model_dump())  # (2)!
#> {'item': {'value': 1}}
  1. जब जेनेरिक को पैरामीट्रिज्ड नहीं किया जाता है, तो इनपुट डेटा को जेनेरिक बाउंड के विरुद्ध मान्य किया जाता है। यह देखते हुए कि ItemBase कोई फ़ील्ड नहीं है, item फ़ील्ड जानकारी खो जाती है।
  2. इस मामले में, रनटाइम प्रकार की जानकारी सामान्य पैरामीट्रिज़ेशन के माध्यम से स्पष्ट रूप से प्रदान की जाती है, इसलिए इनपुट डेटा को IntItem वर्ग के विरुद्ध मान्य किया जाता है और क्रमांकन आउटपुट अपेक्षित से मेल खाता है।

गतिशील मॉडल निर्माण

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

ऐसे कुछ अवसर होते हैं जहां फ़ील्ड निर्दिष्ट करने के लिए रनटाइम जानकारी का उपयोग करके एक मॉडल बनाना वांछनीय होता है। इसके लिए पाइडेंटिक तुरंत मॉडल बनाने की अनुमति देने के लिए create_model फ़ंक्शन प्रदान करता है:

from pydantic import BaseModel, create_model

DynamicFoobarModel = create_model(
    'DynamicFoobarModel', foo=(str, ...), bar=(int, 123)
)


class StaticFoobarModel(BaseModel):
    foo: str
    bar: int = 123

यहां StaticFoobarModel और DynamicFoobarModel समान हैं।

फ़ील्ड्स को निम्नलिखित टपल रूपों में से एक द्वारा परिभाषित किया गया है:

  • (<type>, <default value>)
  • (<type>, Field(...))
  • typing.Annotated[<type>, Field(...)]

टुपल (डिफ़ॉल्ट मान) में दूसरे तर्क के रूप में Field(...) कॉल का उपयोग करने से अधिक उन्नत फ़ील्ड कॉन्फ़िगरेशन की अनुमति मिलती है। इस प्रकार, निम्नलिखित समान हैं:

from pydantic import BaseModel, Field, create_model

DynamicModel = create_model(
    'DynamicModel',
    foo=(str, Field(..., description='foo description', alias='FOO')),
)


class StaticModel(BaseModel):
    foo: str = Field(..., description='foo description', alias='FOO')

नए मॉडल को अनुकूलित करने के लिए विशेष कीवर्ड तर्क __config__ और __base__ उपयोग किया जा सकता है। इसमें अतिरिक्त फ़ील्ड के साथ बेस मॉडल का विस्तार करना शामिल है।

from pydantic import BaseModel, create_model


class FooModel(BaseModel):
    foo: str
    bar: int = 123


BarModel = create_model(
    'BarModel',
    apple=(str, 'russet'),
    banana=(str, 'yellow'),
    __base__=FooModel,
)
print(BarModel)
#> <class '__main__.BarModel'>
print(BarModel.model_fields.keys())
#> dict_keys(['foo', 'bar', 'apple', 'banana'])

आप __validators__ तर्क पर एक निर्देश पारित करके सत्यापनकर्ता भी जोड़ सकते हैं।

from pydantic import ValidationError, create_model, field_validator


def username_alphanumeric(cls, v):
    assert v.isalnum(), 'must be alphanumeric'
    return v


validators = {
    'username_validator': field_validator('username')(username_alphanumeric)
}

UserModel = create_model(
    'UserModel', username=(str, ...), __validators__=validators
)

user = UserModel(username='scolvin')
print(user)
#> username='scolvin'

try:
    UserModel(username='scolvi%n')
except ValidationError as e:
    print(e)
    """
    1 validation error for UserModel
    username
      Assertion failed, must be alphanumeric [type=assertion_error, input_value='scolvi%n', input_type=str]
    """

!!! नोट गतिशील रूप से बनाए गए मॉडल का चयन करने के लिए:

- the model must be defined globally
- it must provide `__module__`

RootModel और कस्टम रूट प्रकार

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

पाइडेंटिक मॉडल को उपवर्गीकरण द्वारा "कस्टम रूट प्रकार" के साथ परिभाषित किया जा सकता है pydantic.RootModel

रूट प्रकार पाइडेंटिक द्वारा समर्थित किसी भी प्रकार का हो सकता है, और जेनेरिक पैरामीटर द्वारा RootModel द्वारा निर्दिष्ट किया जाता है। रूट मान को पहले और एकमात्र तर्क के माध्यम से मॉडल __init__ या model_validate को पास किया जा सकता है।

यह कैसे काम करता है इसका एक उदाहरण यहां दिया गया है:

from typing import Dict, List

from pydantic import RootModel

Pets = RootModel[List[str]]
PetsByName = RootModel[Dict[str, str]]


print(Pets(['dog', 'cat']))
#> root=['dog', 'cat']
print(Pets(['dog', 'cat']).model_dump_json())
#> ["dog","cat"]
print(Pets.model_validate(['dog', 'cat']))
#> root=['dog', 'cat']
print(Pets.model_json_schema())
"""
{'items': {'type': 'string'}, 'title': 'RootModel[List[str]]', 'type': 'array'}
"""

print(PetsByName({'Otis': 'dog', 'Milo': 'cat'}))
#> root={'Otis': 'dog', 'Milo': 'cat'}
print(PetsByName({'Otis': 'dog', 'Milo': 'cat'}).model_dump_json())
#> {"Otis":"dog","Milo":"cat"}
print(PetsByName.model_validate({'Otis': 'dog', 'Milo': 'cat'}))
#> root={'Otis': 'dog', 'Milo': 'cat'}

यदि आप सीधे root फ़ील्ड में आइटम तक पहुंचना चाहते हैं या आइटम पर पुनरावृति करना चाहते हैं, तो आप कस्टम __iter__ और __getitem__ फ़ंक्शंस लागू कर सकते हैं, जैसा कि निम्नलिखित उदाहरण में दिखाया गया है।

from typing import List

from pydantic import RootModel


class Pets(RootModel):
    root: List[str]

    def __iter__(self):
        return iter(self.root)

    def __getitem__(self, item):
        return self.root[item]


pets = Pets.model_validate(['dog', 'cat'])
print(pets[0])
#> dog
print([pet for pet in pets])
#> ['dog', 'cat']

आप सीधे पैरामीट्रिज्ड रूट मॉडल के उपवर्ग भी बना सकते हैं:

from typing import List

from pydantic import RootModel


class Pets(RootModel[List[str]]):
    def describe(self) -> str:
        return f'Pets: {", ".join(self.root)}'


my_pets = Pets.model_validate(['dog', 'cat'])

print(my_pets.describe())
#> Pets: dog, cat

नकली अपरिवर्तनीयता

मॉडल को model_config['frozen'] = True के माध्यम से अपरिवर्तनीय होने के लिए कॉन्फ़िगर किया जा सकता है। जब इसे सेट किया जाता है, तो इंस्टेंस विशेषताओं के मानों को बदलने का प्रयास करने से त्रुटियाँ उत्पन्न होंगी। अधिक विवरण के लिए एपीआई संदर्भ देखें।

!!! नोट यह व्यवहार Pydantic V1 में कॉन्फिग सेटिंग allow_mutation = False माध्यम से प्राप्त किया गया था। यह कॉन्फ़िगरेशन फ़्लैग Pydantic V2 में अप्रचलित है, और इसे frozen से बदल दिया गया है।

!!! चेतावनी पायथन में, अपरिवर्तनीयता लागू नहीं की जाती है। डेवलपर्स के पास उन वस्तुओं को संशोधित करने की क्षमता होती है जिन्हें पारंपरिक रूप से "अपरिवर्तनीय" माना जाता है यदि वे ऐसा करना चुनते हैं।

from pydantic import BaseModel, ConfigDict, ValidationError


class FooBarModel(BaseModel):
    model_config = ConfigDict(frozen=True)

    a: str
    b: dict


foobar = FooBarModel(a='hello', b={'apple': 'pear'})

try:
    foobar.a = 'different'
except ValidationError as e:
    print(e)
    """
    1 validation error for FooBarModel
    a
      Instance is frozen [type=frozen_instance, input_value='different', input_type=str]
    """

print(foobar.a)
#> hello
print(foobar.b)
#> {'apple': 'pear'}
foobar.b['apple'] = 'grape'
print(foobar.b)
#> {'apple': 'grape'}

a बदलने का प्रयास करने से त्रुटि उत्पन्न हुई, और a अपरिवर्तित रहता है। हालाँकि, तानाशाही b परिवर्तनशील है, और foobar की अपरिवर्तनीयता b परिवर्तित होने से नहीं रोकती है।

सार आधार वर्ग

पायडेंटिक मॉडल का उपयोग पायथन के एब्सट्रैक्ट बेस क्लासेस (एबीसी) के साथ किया जा सकता है।

import abc

from pydantic import BaseModel


class FooBarModel(BaseModel, abc.ABC):
    a: str
    b: int

    @abc.abstractmethod
    def my_abstract_method(self):
        pass

फ़ील्ड ऑर्डरिंग

फ़ील्ड क्रम निम्नलिखित तरीकों से मॉडल को प्रभावित करता है:

  • फ़ील्ड क्रम मॉडल स्कीमा में संरक्षित है
  • सत्यापन त्रुटियों में फ़ील्ड क्रम संरक्षित है
  • फ़ील्ड क्रम .model_dump() और .model_dump_json() आदि द्वारा संरक्षित किया जाता है।

    from pydantic import BaseModel, ValidationError

    class Model(BaseModel): a: int b: int = 2 c: int = 1 d: int = 0 e: float

    print(Model.model_fields.keys())

    > dict_keys(['a', 'b', 'c', 'd', 'e'])

    m = Model(e=2, a=1) print(m.model_dump())

    >

    try: Model(a='x', b='x', c='x', d='x', e='x') except ValidationError as err: error_locations = [e['loc'] for e in err.errors()]

    print(error_locations)

    > [('a',), ('b',), ('c',), ('d',), ('e',)]

आवश्यक फील्ड्स

किसी फ़ील्ड को आवश्यकतानुसार घोषित करने के लिए, आप इसे एक एनोटेशन, या Field विनिर्देश के साथ संयोजन में एक एनोटेशन का उपयोग करके घोषित कर सकते हैं। आप इस बात पर जोर देने के लिए Ellipsis / ... का भी उपयोग कर सकते हैं कि एक फ़ील्ड की आवश्यकता है, खासकर Field कंस्ट्रक्टर का उपयोग करते समय।

Field फ़ंक्शन का उपयोग मुख्य रूप से किसी विशेषता के लिए alias या description जैसी सेटिंग्स को कॉन्फ़िगर करने के लिए किया जाता है। कंस्ट्रक्टर Ellipsis / ... को एकमात्र स्थितीय तर्क के रूप में समर्थन करता है। इसका उपयोग यह इंगित करने के तरीके के रूप में किया जाता है कि उक्त फ़ील्ड अनिवार्य है, हालांकि यह प्रकार का संकेत है जो इस आवश्यकता को लागू करता है।

from pydantic import BaseModel, Field


class Model(BaseModel):
    a: int
    b: int = ...
    c: int = Field(..., alias='C')

यहां a , b और c सभी आवश्यक हैं। हालाँकि, b: int = ... का यह उपयोग mypy के साथ ठीक से काम नहीं करता है, और v1.0 के कारण अधिकांश मामलों में इससे बचना चाहिए।

!!! नोट पाइडेंटिक V1 में, Optional या Any साथ एनोटेट किए गए फ़ील्ड को None का एक अंतर्निहित डिफ़ॉल्ट दिया जाएगा, भले ही कोई डिफ़ॉल्ट स्पष्ट रूप से निर्दिष्ट न किया गया हो। यह व्यवहार पाइडेंटिक V2 में बदल गया है, और अब कोई भी प्रकार का एनोटेशन नहीं है जिसके परिणामस्वरूप किसी फ़ील्ड में अंतर्निहित डिफ़ॉल्ट मान होगा।

See [the migration guide](../migration.md#required-optional-and-nullable-fields) for more details on changes
to required and nullable fields.

गैर-हैश करने योग्य डिफ़ॉल्ट मान वाले फ़ील्ड

पायथन में बग का एक सामान्य स्रोत किसी फ़ंक्शन या विधि तर्क के लिए एक परिवर्तनशील ऑब्जेक्ट को डिफ़ॉल्ट मान के रूप में उपयोग करना है, क्योंकि प्रत्येक कॉल में एक ही उदाहरण का पुन: उपयोग किया जाता है।

dataclasses मॉड्यूल वास्तव में इस मामले में एक त्रुटि उत्पन्न करता है, जो दर्शाता है कि आपको dataclasses.field के लिए default_factory तर्क का उपयोग करना चाहिए।

पाइडेंटिक गैर-हैशेबल डिफ़ॉल्ट मानों के लिए default_factory के उपयोग का भी समर्थन करता है, लेकिन इसकी आवश्यकता नहीं है। इस घटना में कि डिफ़ॉल्ट मान धोने योग्य नहीं है, मॉडल के प्रत्येक उदाहरण को बनाते समय पाइडेंटिक डिफ़ॉल्ट मान को डीपकॉपी करेगा:

from typing import Dict, List

from pydantic import BaseModel


class Model(BaseModel):
    item_counts: List[Dict[str, int]] = [{}]


m1 = Model()
m1.item_counts[0]['a'] = 1
print(m1.item_counts)
#> [{'a': 1}]

m2 = Model()
print(m2.item_counts)
#> [{}]

गतिशील डिफ़ॉल्ट मान वाले फ़ील्ड

किसी फ़ील्ड को डिफ़ॉल्ट मान के साथ घोषित करते समय, आप शायद इसे गतिशील बनाना चाहेंगे (अर्थात प्रत्येक मॉडल के लिए अलग)। ऐसा करने के लिए, आप default_factory उपयोग करना चाह सकते हैं।

यहाँ एक उदाहरण है:

from datetime import datetime, timezone
from uuid import UUID, uuid4

from pydantic import BaseModel, Field


def datetime_now() -> datetime:
    return datetime.now(timezone.utc)


class Model(BaseModel):
    uid: UUID = Field(default_factory=uuid4)
    updated: datetime = Field(default_factory=datetime_now)


m1 = Model()
m2 = Model()
assert m1.uid != m2.uid

आप Field फ़ंक्शन के दस्तावेज़ीकरण में अधिक जानकारी पा सकते हैं।

स्वचालित रूप से बहिष्कृत विशेषताएँ

कक्षा संस्करण

typing.ClassVar के साथ एनोटेट की गई विशेषताओं को Pydantic द्वारा क्लास वेरिएबल के रूप में उचित रूप से व्यवहार किया जाता है, और मॉडल उदाहरणों पर फ़ील्ड नहीं बनेंगे:

from typing import ClassVar

from pydantic import BaseModel


class Model(BaseModel):
    x: int = 2
    y: ClassVar[int] = 1


m = Model()
print(m)
#> x=2
print(Model.y)
#> 1

निजी मॉडल विशेषताएँ

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

जिन विशेषताओं के नाम में अग्रणी अंडरस्कोर है, उन्हें पाइडेंटिक द्वारा फ़ील्ड के रूप में नहीं माना जाता है, और मॉडल स्कीमा में शामिल नहीं किया जाता है। इसके बजाय, इन्हें एक "निजी विशेषता" में परिवर्तित कर दिया जाता है जिसे __init__ , model_validate इत्यादि पर कॉल के दौरान मान्य नहीं किया जाता है या सेट भी नहीं किया जाता है।

!!! ध्यान दें Pydantic v2.1.0 के अनुसार, यदि आप किसी निजी विशेषता के साथ Field फ़ंक्शन का उपयोग करने का प्रयास करते हैं तो आपको एक NameError प्राप्त होगा। क्योंकि निजी विशेषताओं को फ़ील्ड के रूप में नहीं माना जाता है, फ़ील्ड() फ़ंक्शन लागू नहीं किया जा सकता है।

यहां उपयोग का एक उदाहरण दिया गया है:

from datetime import datetime
from random import randint

from pydantic import BaseModel, PrivateAttr


class TimeAwareModel(BaseModel):
    _processed_at: datetime = PrivateAttr(default_factory=datetime.now)
    _secret_value: str

    def __init__(self, **data):
        super().__init__(**data)
        # this could also be done with default_factory
        self._secret_value = randint(1, 5)


m = TimeAwareModel()
print(m._processed_at)
#> 2032-01-02 03:04:05.000006
print(m._secret_value)
#> 3

मॉडल फ़ील्ड के साथ टकराव को रोकने के लिए निजी विशेषता नाम अंडरस्कोर से शुरू होने चाहिए। हालाँकि, डंडर नाम (जैसे __attr__ ) समर्थित नहीं हैं।

डेटा रूपांतरण

पाइडेंटिक इनपुट डेटा को मॉडल फ़ील्ड प्रकारों के अनुरूप बनाने के लिए बाध्य कर सकता है, और कुछ मामलों में इसके परिणामस्वरूप जानकारी का नुकसान हो सकता है। उदाहरण के लिए:

from pydantic import BaseModel


class Model(BaseModel):
    a: int
    b: float
    c: str


print(Model(a=3.000, b='2.72', c=b'binary data').model_dump())
#> {'a': 3, 'b': 2.72, 'c': 'binary data'}

यह पाइडेंटिक का एक जानबूझकर लिया गया निर्णय है, और अक्सर सबसे उपयोगी दृष्टिकोण है। विषय पर लंबी चर्चा के लिए यहां देखें।

फिर भी, सख्त प्रकार की जाँच का भी समर्थन किया जाता है।

मॉडल हस्ताक्षर

सभी पाइडेंटिक मॉडलों का हस्ताक्षर उनके क्षेत्रों के आधार पर तैयार किया जाएगा:

import inspect

from pydantic import BaseModel, Field


class FooModel(BaseModel):
    id: int
    name: str = None
    description: str = 'Foo'
    apple: int = Field(alias='pear')


print(inspect.signature(FooModel))
#> (*, id: int, name: str = None, description: str = 'Foo', pear: int) -> None

एक सटीक हस्ताक्षर आत्मनिरीक्षण उद्देश्यों और FastAPI या hypothesis जैसे पुस्तकालयों के लिए उपयोगी है।

जेनरेट किया गया हस्ताक्षर कस्टम __init__ फ़ंक्शंस का भी सम्मान करेगा:

import inspect

from pydantic import BaseModel


class MyModel(BaseModel):
    id: int
    info: str = 'Foo'

    def __init__(self, id: int = 1, *, bar: str, **data) -> None:
        """My custom init!"""
        super().__init__(id=id, bar=bar, **data)


print(inspect.signature(MyModel))
#> (id: int = 1, *, bar: str, info: str = 'Foo') -> None

हस्ताक्षर में शामिल होने के लिए, फ़ील्ड का उपनाम या नाम एक वैध पायथन पहचानकर्ता होना चाहिए। हस्ताक्षर बनाते समय पाइडेंटिक किसी फ़ील्ड के उपनाम को उसके नाम से अधिक प्राथमिकता देगा, लेकिन यदि उपनाम वैध पायथन पहचानकर्ता नहीं है, तो फ़ील्ड नाम का उपयोग कर सकता है।

यदि किसी फ़ील्ड का उपनाम और नाम दोनों मान्य पहचानकर्ता नहीं हैं (जो create_model के विदेशी उपयोग के माध्यम से संभव हो सकता है), तो एक **data तर्क जोड़ा जाएगा। इसके अलावा, **data तर्क हमेशा हस्ताक्षर में मौजूद रहेगा यदि model_config['extra'] == 'allow' .

संरचनात्मक पैटर्न मिलान

पाइडेंटिक मॉडलों के लिए संरचनात्मक पैटर्न मिलान का समर्थन करता है, जैसा कि पायथन 3.10 में पीईपी 636 द्वारा पेश किया गया था।

from pydantic import BaseModel


class Pet(BaseModel):
    name: str
    species: str


a = Pet(name='Bones', species='dog')

match a:
    # match `species` to 'dog', declare and initialize `dog_name`
    case Pet(species='dog', name=dog_name):
        print(f'{dog_name} is a dog')
#> Bones is a dog
    # default case
    case _:
        print('No dog matched')

!!! नोट एक मैच-केस स्टेटमेंट ऐसा लग सकता है मानो यह एक नया मॉडल बनाता है, लेकिन मूर्ख मत बनो; यह एक विशेषता प्राप्त करने और उसकी तुलना करने या उसे घोषित करने और आरंभ करने के लिए सिर्फ वाक्यात्मक चीनी है।

विशेषता प्रतियाँ

कई मामलों में, सत्यापन करने और, जहां आवश्यक हो, जबरदस्ती करने के लिए कंस्ट्रक्टर को दिए गए तर्कों की प्रतिलिपि बनाई जाएगी।

इस उदाहरण में, ध्यान दें कि सूची की आईडी कक्षा के निर्माण के बाद बदल जाती है क्योंकि इसे सत्यापन के दौरान कॉपी किया गया है:

from typing import List

from pydantic import BaseModel


class C1:
    arr = []

    def __init__(self, in_arr):
        self.arr = in_arr


class C2(BaseModel):
    arr: List[int]


arr_orig = [1, 9, 10, 3]


c1 = C1(arr_orig)
c2 = C2(arr=arr_orig)
print('id(c1.arr) == id(c2.arr):', id(c1.arr) == id(c2.arr))
#> id(c1.arr) == id(c2.arr): False

!!! नोट ऐसी कुछ स्थितियाँ हैं जहाँ पाइडेंटिक विशेषताओं की प्रतिलिपि नहीं बनाता है, जैसे कि मॉडल पास करते समय - हम मॉडल का उपयोग वैसे ही करते हैं। आप सेटिंग द्वारा इस व्यवहार को ओवरराइड कर सकते हैं model_config['revalidate_instances'] = 'always' .

अतिरिक्त फ़ील्ड

डिफ़ॉल्ट रूप से, जब आप अपरिचित फ़ील्ड के लिए डेटा प्रदान करते हैं तो पाइडेंटिक मॉडल त्रुटि नहीं करेंगे, उन्हें बस अनदेखा कर दिया जाएगा:

from pydantic import BaseModel


class Model(BaseModel):
    x: int


m = Model(x=1, y='a')
assert m.model_dump() == {'x': 1}

यदि आप चाहते हैं कि इससे कोई त्रुटि उत्पन्न हो, तो आप इसे model_config के माध्यम से प्राप्त कर सकते हैं:

from pydantic import BaseModel, ConfigDict, ValidationError


class Model(BaseModel):
    x: int

    model_config = ConfigDict(extra='forbid')


try:
    Model(x=1, y='a')
except ValidationError as exc:
    print(exc)
    """
    1 validation error for Model
    y
      Extra inputs are not permitted [type=extra_forbidden, input_value='a', input_type=str]
    """

इसके बजाय प्रदान किए गए किसी भी अतिरिक्त डेटा को संरक्षित करने के लिए, आप extra='allow' सेट कर सकते हैं। फिर अतिरिक्त फ़ील्ड BaseModel.__pydantic_extra__ में संग्रहीत की जाएंगी:

from pydantic import BaseModel, ConfigDict


class Model(BaseModel):
    x: int

    model_config = ConfigDict(extra='allow')


m = Model(x=1, y='a')
assert m.__pydantic_extra__ == {'y': 'a'}

डिफ़ॉल्ट रूप से, इन अतिरिक्त आइटमों पर कोई सत्यापन लागू नहीं किया जाएगा, लेकिन आप __pydantic_extra__ के प्रकार एनोटेशन को ओवरराइड करके मानों के लिए एक प्रकार सेट कर सकते हैं:

from typing import Dict

from pydantic import BaseModel, ConfigDict, Field, ValidationError


class Model(BaseModel):
    __pydantic_extra__: Dict[str, int] = Field(init=False)  # (1)!

    x: int

    model_config = ConfigDict(extra='allow')


try:
    Model(x=1, y='a')
except ValidationError as exc:
    print(exc)
    """
    1 validation error for Model
    y
      Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='a', input_type=str]
    """

m = Model(x=1, y='2')
assert m.x == 1
assert m.y == 2
assert m.model_dump() == {'x': 1, 'y': 2}
assert m.__pydantic_extra__ == {'y': 2}
  1. = Field(init=False) रनटाइम पर कोई प्रभाव नहीं पड़ता है, लेकिन टाइप-चेकर्स द्वारा __pydantic_extra__ फ़ील्ड को मॉडल की __init__ विधि के तर्क के रूप में मानने से रोकता है।

वही कॉन्फ़िगरेशन TypedDict और dataclass पर लागू होते हैं, सिवाय इसके कि कॉन्फ़िगरेशन को क्लास के __pydantic_config__ विशेषता को वैध ConfigDict पर सेट करके नियंत्रित किया जाता है।


本文总阅读量