??? एपीआई "एपीआई दस्तावेज़ीकरण" 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
डिफ़ॉल्ट रूप से, मॉडल परिवर्तनशील होते हैं और फ़ील्ड मानों को विशेषता असाइनमेंट के माध्यम से बदला जा सकता है।
मॉडल के तरीके और गुण¶
उपरोक्त उदाहरण केवल हिमशैल का टिप दिखाता है कि मॉडल क्या कर सकते हैं। मॉडल में निम्नलिखित विधियाँ और विशेषताएँ होती हैं:
model_computed_fields
: इस मॉडल उदाहरण के परिकलित फ़ील्ड का एक शब्दकोश।model_construct()
: सत्यापन चलाए बिना मॉडल बनाने के लिए एक क्लास विधि। सत्यापन के बिना मॉडल बनाना देखें।model_copy()
: मॉडल की एक प्रति (डिफ़ॉल्ट रूप से, उथली प्रति) लौटाता है। क्रमांकन देखें.model_dump()
: मॉडल के फ़ील्ड और मानों का एक शब्दकोश लौटाता है। क्रमांकन देखें.model_dump_json()
:model_dump()
का JSON स्ट्रिंग प्रतिनिधित्व लौटाता है। क्रमांकन देखें.model_extra
: सत्यापन के दौरान अतिरिक्त फ़ील्ड सेट करें।model_fields_set
: फ़ील्ड का सेट जो मॉडल इंस्टेंस के प्रारंभ होने पर सेट किया गया था।model_json_schema()
: JSON स्कीमा के रूप में मॉडल का प्रतिनिधित्व करने वाला एक jsonable शब्दकोश देता है। JSON स्कीमा देखें.model_parametrized_name()
: सामान्य कक्षाओं के पैरामीट्रिजेशन के लिए वर्ग नाम की गणना करें।model_post_init()
: मॉडल आरंभ होने के बाद अतिरिक्त आरंभीकरण करें।model_rebuild()
: मॉडल स्कीमा का पुनर्निर्माण करें, जो पुनरावर्ती जेनेरिक मॉडल के निर्माण का भी समर्थन करता है। मॉडल स्कीमा का पुनर्निर्माण देखें।model_validate()
: किसी भी ऑब्जेक्ट को मॉडल में लोड करने के लिए एक उपयोगिता। हेल्पर फ़ंक्शन देखें.model_validate_json()
: Pydantic मॉडल के विरुद्ध दिए गए JSON डेटा को मान्य करने के लिए एक उपयोगिता। हेल्पर फ़ंक्शन देखें.
!!! नोट विधियों और विशेषताओं की पूरी सूची सहित वर्ग परिभाषा के लिए 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'
फ़ील्ड के अनुरूप डेटा की उपस्थिति में कोई त्रुटि उत्पन्न नहीं होती है। बल्कि, उक्त इनपुट डेटा को आसानी से नजरअंदाज कर दिया जाता है।
सामान्य मॉडल¶
पाइडेंटिक सामान्य मॉडल संरचना का पुन: उपयोग करना आसान बनाने के लिए सामान्य मॉडल के निर्माण का समर्थन करता है।
एक सामान्य मॉडल घोषित करने के लिए, आप निम्नलिखित कदम उठाते हैं:
- अपने मॉडल को पैरामीटराइज़ करने के लिए उपयोग करने के लिए एक या अधिक
typing.TypeVar
उदाहरण घोषित करें। - एक पाइडेंटिक मॉडल घोषित करें जो
pydantic.BaseModel
औरtyping.Generic
से विरासत में मिला है, जहां आपtyping.Generic
पैरामीटर के रूप मेंTypeVar
उदाहरणों को पास करते हैं। 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}}
- जब जेनेरिक को पैरामीट्रिज्ड नहीं किया जाता है, तो इनपुट डेटा को जेनेरिक बाउंड के विरुद्ध मान्य किया जाता है। यह देखते हुए कि
ItemBase
कोई फ़ील्ड नहीं है,item
फ़ील्ड जानकारी खो जाती है। - इस मामले में, रनटाइम प्रकार की जानकारी सामान्य पैरामीट्रिज़ेशन के माध्यम से स्पष्ट रूप से प्रदान की जाती है, इसलिए इनपुट डेटा को
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}
= Field(init=False)
रनटाइम पर कोई प्रभाव नहीं पड़ता है, लेकिन टाइप-चेकर्स द्वारा__pydantic_extra__
फ़ील्ड को मॉडल की__init__
विधि के तर्क के रूप में मानने से रोकता है।
वही कॉन्फ़िगरेशन TypedDict
और dataclass
पर लागू होते हैं, सिवाय इसके कि कॉन्फ़िगरेशन को क्लास के __pydantic_config__
विशेषता को वैध ConfigDict
पर सेट करके नियंत्रित किया जाता है।
本文总阅读量次