एनोटेटेड सत्यापनकर्ता¶
??? एपीआई "एपीआई दस्तावेज़ीकरण" [pydantic.functional_validators.WrapValidator
][pydantic.functional_validator.WrapValidator]
[pydantic.functional_validators.PlainValidator
][pydantic.functional_validator.PlainValidator]
[pydantic.functional_validators.BeforeValidator
][pydantic.functional_validator.BeforeValidator]
[pydantic.functional_validators.AfterValidator
][pydantic.functional_validator.AfterValidator]
पाइडेंटिक Annotated
के उपयोग के माध्यम से सत्यापनकर्ताओं को लागू करने का एक तरीका प्रदान करता है। जब भी आप सत्यापन को मॉडल या फ़ील्ड के बजाय किसी प्रकार से बांधना चाहते हैं तो आपको इसका उपयोग करना चाहिए।
from typing import Any, List
from typing_extensions import Annotated
from pydantic import BaseModel, ValidationError
from pydantic.functional_validators import AfterValidator
def check_squares(v: int) -> int:
assert v**0.5 % 1 == 0, f'{v} is not a square number'
return v
def double(v: Any) -> Any:
return v * 2
MyNumber = Annotated[int, AfterValidator(double), AfterValidator(check_squares)]
class DemoModel(BaseModel):
number: List[MyNumber]
print(DemoModel(number=[2, 8]))
#> number=[4, 16]
try:
DemoModel(number=[2, 4])
except ValidationError as e:
print(e)
"""
1 validation error for DemoModel
number.1
Assertion failed, 8 is not a square number
assert ((8 ** 0.5) % 1) == 0 [type=assertion_error, input_value=4, input_type=int]
"""
इस उदाहरण में हमने कुछ प्रकार के उपनामों ( MyNumber = Annotated[...]
) का उपयोग किया है। हालांकि यह कोड की सुपाठ्यता में मदद कर सकता है, लेकिन इसकी आवश्यकता नहीं है, आप Annotated
उपयोग सीधे मॉडल फ़ील्ड प्रकार संकेत में कर सकते हैं। ये प्रकार के उपनाम भी वास्तविक प्रकार नहीं हैं लेकिन आप वास्तविक प्रकार बनाने के लिए TypeAliasType
के साथ एक समान दृष्टिकोण का उपयोग कर सकते हैं। कस्टम प्रकारों की अधिक विस्तृत व्याख्या के लिए कस्टम प्रकार देखें।
यह भी ध्यान देने योग्य है कि आप Annotated
अन्य प्रकारों के अंदर नेस्ट कर सकते हैं। इस उदाहरण में हमने किसी सूची की आंतरिक वस्तुओं पर सत्यापन लागू करने के लिए इसका उपयोग किया। उसी दृष्टिकोण का उपयोग तानाशाही कुंजी आदि के लिए किया जा सकता है।
पहले, बाद, रैप और सादा सत्यापनकर्ता¶
पाइडेंटिक कई प्रकार के सत्यापनकर्ता कार्य प्रदान करता है:
- सत्यापनकर्ता पाइडेंटिक के आंतरिक पार्सिंग के
After
चलते हैं। वे आम तौर पर अधिक सुरक्षित होते हैं और इसलिए उन्हें लागू करना आसान होता है। - पाइडेंटिक के आंतरिक पार्सिंग और सत्यापन से
Before
सत्यापनकर्ता चलते हैं (उदाहरण के लिए एकstr
को एकint
पर मजबूर करना)। येAfter
वैलिडेटर की तुलना में अधिक लचीले हैं क्योंकि वे कच्चे इनपुट को संशोधित कर सकते हैं, लेकिन उन्हें कच्चे इनपुट से भी निपटना पड़ता है, जो सिद्धांत रूप में कोई भी मनमानी वस्तु हो सकती है। Plain
सत्यापनकर्ता एकmode='before'
सत्यापनकर्ता की तरह होते हैं लेकिन वे सत्यापन को तुरंत समाप्त कर देते हैं, कोई और सत्यापनकर्ता नहीं बुलाया जाता है और Pydantic अपना कोई भी आंतरिक सत्यापन नहीं करता है।Wrap
सत्यापनकर्ता सभी में सबसे अधिक लचीले होते हैं। आप पाइडेंटिक और अन्य सत्यापनकर्ताओं के अपना काम करने से पहले या बाद में कोड चला सकते हैं या आप सफल मान या त्रुटि दोनों के साथ सत्यापन को तुरंत समाप्त कर सकते हैं।
आप एकाधिक पहले, बाद, या mode='wrap'
सत्यापनकर्ताओं का उपयोग कर सकते हैं, लेकिन केवल एक PlainValidator
उपयोग कर सकते हैं क्योंकि एक सादा सत्यापनकर्ता किसी भी आंतरिक सत्यापनकर्ता को कॉल नहीं करेगा।
यहां mode='wrap'
सत्यापनकर्ता का एक उदाहरण दिया गया है:
import json
from typing import Any, List
from typing_extensions import Annotated
from pydantic import (
BaseModel,
ValidationError,
ValidationInfo,
ValidatorFunctionWrapHandler,
)
from pydantic.functional_validators import WrapValidator
def maybe_strip_whitespace(
v: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
) -> int:
if info.mode == 'json':
assert isinstance(v, str), 'In JSON mode the input must be a string!'
# you can call the handler multiple times
try:
return handler(v)
except ValidationError:
return handler(v.strip())
assert info.mode == 'python'
assert isinstance(v, int), 'In Python mode the input must be an int!'
# do no further validation
return v
MyNumber = Annotated[int, WrapValidator(maybe_strip_whitespace)]
class DemoModel(BaseModel):
number: List[MyNumber]
print(DemoModel(number=[2, 8]))
#> number=[2, 8]
print(DemoModel.model_validate_json(json.dumps({'number': [' 2 ', '8']})))
#> number=[2, 8]
try:
DemoModel(number=['2'])
except ValidationError as e:
print(e)
"""
1 validation error for DemoModel
number.0
Assertion failed, In Python mode the input must be an int!
assert False
+ where False = isinstance('2', int) [type=assertion_error, input_value='2', input_type=str]
"""
वही "मोड" @field_validator
पर लागू होते हैं, जिसकी चर्चा अगले भाग में की गई है।
Annotated
के भीतर सत्यापनकर्ताओं का आदेश देना¶
Annotated
मामलों के भीतर सत्यापन मेटाडेटा का क्रम। सत्यापन दाएँ से बाएँ और पीछे जाता है। अर्थात्, यह दाएं से बाएं सभी "पहले" सत्यापनकर्ताओं को चलाता है (या "रैप" सत्यापनकर्ताओं को कॉल करता है), फिर बाएं से दाएं सभी "बाद" सत्यापनकर्ताओं को कॉल करता है।
from typing import Any, Callable, List, cast
from typing_extensions import Annotated, TypedDict
from pydantic import (
AfterValidator,
BaseModel,
BeforeValidator,
PlainValidator,
ValidationInfo,
ValidatorFunctionWrapHandler,
WrapValidator,
)
from pydantic.functional_validators import field_validator
class Context(TypedDict):
logs: List[str]
def make_validator(label: str) -> Callable[[Any, ValidationInfo], Any]:
def validator(v: Any, info: ValidationInfo) -> Any:
context = cast(Context, info.context)
context['logs'].append(label)
return v
return validator
def make_wrap_validator(
label: str,
) -> Callable[[Any, ValidatorFunctionWrapHandler, ValidationInfo], Any]:
def validator(
v: Any, handler: ValidatorFunctionWrapHandler, info: ValidationInfo
) -> Any:
context = cast(Context, info.context)
context['logs'].append(f'{label}: pre')
result = handler(v)
context['logs'].append(f'{label}: post')
return result
return validator
class A(BaseModel):
x: Annotated[
str,
BeforeValidator(make_validator('before-1')),
AfterValidator(make_validator('after-1')),
WrapValidator(make_wrap_validator('wrap-1')),
BeforeValidator(make_validator('before-2')),
AfterValidator(make_validator('after-2')),
WrapValidator(make_wrap_validator('wrap-2')),
BeforeValidator(make_validator('before-3')),
AfterValidator(make_validator('after-3')),
WrapValidator(make_wrap_validator('wrap-3')),
BeforeValidator(make_validator('before-4')),
AfterValidator(make_validator('after-4')),
WrapValidator(make_wrap_validator('wrap-4')),
]
y: Annotated[
str,
BeforeValidator(make_validator('before-1')),
AfterValidator(make_validator('after-1')),
WrapValidator(make_wrap_validator('wrap-1')),
BeforeValidator(make_validator('before-2')),
AfterValidator(make_validator('after-2')),
WrapValidator(make_wrap_validator('wrap-2')),
PlainValidator(make_validator('plain')),
BeforeValidator(make_validator('before-3')),
AfterValidator(make_validator('after-3')),
WrapValidator(make_wrap_validator('wrap-3')),
BeforeValidator(make_validator('before-4')),
AfterValidator(make_validator('after-4')),
WrapValidator(make_wrap_validator('wrap-4')),
]
val_x_before = field_validator('x', mode='before')(
make_validator('val_x before')
)
val_x_after = field_validator('x', mode='after')(
make_validator('val_x after')
)
val_y_wrap = field_validator('y', mode='wrap')(
make_wrap_validator('val_y wrap')
)
context = Context(logs=[])
A.model_validate({'x': 'abc', 'y': 'def'}, context=context)
print(context['logs'])
"""
[
'val_x before',
'wrap-4: pre',
'before-4',
'wrap-3: pre',
'before-3',
'wrap-2: pre',
'before-2',
'wrap-1: pre',
'before-1',
'after-1',
'wrap-1: post',
'after-2',
'wrap-2: post',
'after-3',
'wrap-3: post',
'after-4',
'wrap-4: post',
'val_x after',
'val_y wrap: pre',
'wrap-4: pre',
'before-4',
'wrap-3: pre',
'before-3',
'plain',
'after-3',
'wrap-3: post',
'after-4',
'wrap-4: post',
'val_y wrap: post',
]
"""
डिफ़ॉल्ट मानों का सत्यापन¶
जब डिफ़ॉल्ट मान का उपयोग किया जाता है तो सत्यापनकर्ता नहीं चलेंगे। यह @field_validator
सत्यापनकर्ताओं और Annotated
सत्यापनकर्ताओं दोनों पर लागू होता है। आप उन्हें Field(validate_default=True)
के साथ चलने के लिए बाध्य कर सकते हैं। validate_default
True
पर सेट करना Pydantic v1 में validator
में always=True
उपयोग करने के सबसे निकटतम व्यवहार है। हालाँकि, आमतौर पर आप इसका उपयोग करना बेहतर समझते हैं @model_validator(mode='before')
जहां आंतरिक सत्यापनकर्ता को कॉल करने से पहले फ़ंक्शन को कॉल किया जाता है।
from typing_extensions import Annotated
from pydantic import BaseModel, Field, field_validator
class Model(BaseModel):
x: str = 'abc'
y: Annotated[str, Field(validate_default=True)] = 'xyz'
@field_validator('x', 'y')
@classmethod
def double(cls, v: str) -> str:
return v * 2
print(Model())
#> x='abc' y='xyzxyz'
print(Model(x='foo'))
#> x='foofoo' y='xyzxyz'
print(Model(x='abc'))
#> x='abcabc' y='xyzxyz'
print(Model(x='foo', y='bar'))
#> x='foofoo' y='barbar'
फ़ील्ड सत्यापनकर्ता¶
??? एपीआई "एपीआई दस्तावेज़ीकरण" [pydantic.functional_validators.field_validator
][pydantic.functional_validator.field_validator]
यदि आप किसी मॉडल के विशिष्ट फ़ील्ड में एक सत्यापनकर्ता संलग्न करना चाहते हैं तो आप @field_validator
डेकोरेटर का उपयोग कर सकते हैं।
from pydantic import (
BaseModel,
ValidationError,
ValidationInfo,
field_validator,
)
class UserModel(BaseModel):
name: str
id: int
@field_validator('name')
@classmethod
def name_must_contain_space(cls, v: str) -> str:
if ' ' not in v:
raise ValueError('must contain a space')
return v.title()
# you can select multiple fields, or use '*' to select all fields
@field_validator('id', 'name')
@classmethod
def check_alphanumeric(cls, v: str, info: ValidationInfo) -> str:
if isinstance(v, str):
# info.field_name is the name of the field being validated
is_alphanumeric = v.replace(' ', '').isalnum()
assert is_alphanumeric, f'{info.field_name} must be alphanumeric'
return v
print(UserModel(name='John Doe', id=1))
#> name='John Doe' id=1
try:
UserModel(name='samuel', id=1)
except ValidationError as e:
print(e)
"""
1 validation error for UserModel
name
Value error, must contain a space [type=value_error, input_value='samuel', input_type=str]
"""
try:
UserModel(name='John Doe', id='abc')
except ValidationError as e:
print(e)
"""
1 validation error for UserModel
id
Input should be a valid integer, unable to parse string as an integer [type=int_parsing, input_value='abc', input_type=str]
"""
try:
UserModel(name='John Doe!', id=1)
except ValidationError as e:
print(e)
"""
1 validation error for UserModel
name
Assertion failed, name must be alphanumeric
assert False [type=assertion_error, input_value='John Doe!', input_type=str]
"""
सत्यापनकर्ताओं पर ध्यान देने योग्य कुछ बातें:
@field_validator
s "वर्ग विधियाँ" हैं, इसलिए उन्हें प्राप्त होने वाला पहला तर्क मानUserModel
वर्ग है,UserModel
का उदाहरण नहीं। हम अनुशंसा करते हैं कि आप उचित प्रकार की जाँच प्राप्त करने के लिए@field_validator
डेकोरेटर के नीचे@classmethod
डेकोरेटर का उपयोग करें।- दूसरा तर्क सत्यापित करने के लिए फ़ील्ड मान है; इसे आपकी इच्छानुसार नाम दिया जा सकता है
- तीसरा तर्क, यदि मौजूद है, तो
pydantic.ValidationInfo
का एक उदाहरण है - सत्यापनकर्ताओं को या तो पार्स किए गए मान को वापस करना चाहिए या
ValueError
याAssertionError
बढ़ाना चाहिए (assert
स्टेटमेंट का उपयोग किया जा सकता है)। - एक एकल सत्यापनकर्ता को कई फ़ील्ड नामों को पास करके कई फ़ील्ड पर लागू किया जा सकता है।
- विशेष मान
'*'
पास करके सभी फ़ील्ड पर एक एकल सत्यापनकर्ता को भी बुलाया जा सकता है।
!!! चेतावनी यदि आप assert
स्टेटमेंट का उपयोग करते हैं, तो ध्यान रखें कि -O
ऑप्टिमाइज़ेशन फ़्लैग के साथ पायथन को चलाने से assert
स्टेटमेंट अक्षम हो जाएगा, और सत्यापनकर्ता काम करना बंद कर देंगे ।
!!! ध्यान दें FieldValidationInfo
2.4 में अप्रचलित है, इसके बजाय ValidationInfo
उपयोग करें।
यदि आप @field_validator
के अंदर किसी अन्य फ़ील्ड से मानों तक पहुंचना चाहते हैं, तो यह ValidationInfo.data
का उपयोग करके संभव हो सकता है, जो कि फ़ील्ड नाम से फ़ील्ड मान का एक निर्देश है। सत्यापन फ़ील्ड को परिभाषित किए गए क्रम में किया जाता है, इसलिए ValidationInfo.data
उपयोग करते समय आपको सावधान रहना होगा कि आप उस फ़ील्ड तक न पहुंचें जो अभी तक मान्य/पॉप्युलेट नहीं किया गया है - उदाहरण के लिए, उपरोक्त कोड में, आप एक्सेस नहीं कर पाएंगे info.data['id']
name_must_contain_space
के भीतर से। हालाँकि, ज्यादातर मामलों में जहां आप एकाधिक फ़ील्ड मानों का उपयोग करके सत्यापन करना चाहते हैं, @model_validator
उपयोग करना बेहतर है जिसकी चर्चा नीचे अनुभाग में की गई है।
मॉडल सत्यापनकर्ता¶
??? एपीआई "एपीआई दस्तावेज़ीकरण" [pydantic.functional_validators.model_validator
][pydantic.functional_validator.model_validator]
@model_validator
का उपयोग करके संपूर्ण मॉडल के डेटा पर सत्यापन भी किया जा सकता है।
from typing import Any
from typing_extensions import Self
from pydantic import BaseModel, ValidationError, model_validator
class UserModel(BaseModel):
username: str
password1: str
password2: str
@model_validator(mode='before')
@classmethod
def check_card_number_omitted(cls, data: Any) -> Any:
if isinstance(data, dict):
assert (
'card_number' not in data
), 'card_number should not be included'
return data
@model_validator(mode='after')
def check_passwords_match(self) -> Self:
pw1 = self.password1
pw2 = self.password2
if pw1 is not None and pw2 is not None and pw1 != pw2:
raise ValueError('passwords do not match')
return self
print(UserModel(username='scolvin', password1='zxcvbn', password2='zxcvbn'))
#> username='scolvin' password1='zxcvbn' password2='zxcvbn'
try:
UserModel(username='scolvin', password1='zxcvbn', password2='zxcvbn2')
except ValidationError as e:
print(e)
"""
1 validation error for UserModel
Value error, passwords do not match [type=value_error, input_value={'username': 'scolvin', '... 'password2': 'zxcvbn2'}, input_type=dict]
"""
try:
UserModel(
username='scolvin',
password1='zxcvbn',
password2='zxcvbn',
card_number='1234',
)
except ValidationError as e:
print(e)
"""
1 validation error for UserModel
Assertion failed, card_number should not be included
assert 'card_number' not in {'card_number': '1234', 'password1': 'zxcvbn', 'password2': 'zxcvbn', 'username': 'scolvin'} [type=assertion_error, input_value={'username': 'scolvin', '..., 'card_number': '1234'}, input_type=dict]
"""
!!! ध्यान दें "रिटर्न टाइप चेकिंग पर" @model_validator
से सजाए गए तरीकों को विधि के अंत में सेल्फ इंस्टेंस वापस करना चाहिए। टाइप चेकिंग उद्देश्यों के लिए, आप सजाए गए तरीके के रिटर्न प्रकार के रूप में typing
या typing_extensions
बैकपोर्ट से Self
उपयोग कर सकते हैं। उपरोक्त उदाहरण के संदर्भ में, आप इसका भी उपयोग कर सकते हैं def check_passwords_match(self: 'UserModel') -> 'UserModel'
यह इंगित करने के लिए कि विधि मॉडल का एक उदाहरण लौटाती है।
!!! नोट "विरासत पर" बेस क्लास में परिभाषित एक @model_validator
उपवर्ग उदाहरण के सत्यापन के दौरान बुलाया जाएगा।
Overriding a `@model_validator` in a subclass will override the base class' `@model_validator`, and thus only the subclass' version of said `@model_validator` will be called.
मॉडल सत्यापनकर्ता mode='before'
, mode='after'
या mode='wrap'
हो सकते हैं।
मॉडल सत्यापनकर्ताओं को कच्चे इनपुट को पारित करने से पहले जो अक्सर एक dict[str, Any]
है लेकिन मॉडल का एक उदाहरण भी हो सकता है (उदाहरण के लिए यदि UserModel.model_validate(UserModel.construct(...))
कहा जाता है) या कुछ और क्योंकि आप मनमानी वस्तुओं को model_validate
में पास कर सकते हैं। इस mode='before'
के कारण सत्यापनकर्ता बेहद लचीले और शक्तिशाली होते हैं लेकिन इन्हें लागू करना बोझिल और त्रुटि प्रवण हो सकता है। मॉडल सत्यापनकर्ताओं से पहले क्लास विधियां होनी चाहिए। पहला तर्क cls
होना चाहिए (और हम यह भी अनुशंसा करते हैं कि आप उचित प्रकार की जाँच के लिए @model_validator
के नीचे @classmethod
उपयोग करें), दूसरा तर्क इनपुट होगा (आपको इसे आम तौर पर Any
के रूप में टाइप करना चाहिए और प्रकार को सीमित करने के लिए isinstance
उपयोग करना चाहिए) और तीसरा तर्क (यदि मौजूद है) एक pydantic.ValidationInfo
होगा।
mode='after'
सत्यापनकर्ता उदाहरण विधियां हैं और हमेशा पहले तर्क के रूप में मॉडल का एक उदाहरण प्राप्त करते हैं। अपने सत्यापनकर्ता के अंत में उदाहरण वापस करना सुनिश्चित करें। आपको हस्ताक्षर के रूप में (cls, ModelType)
उपयोग नहीं करना चाहिए, इसके बजाय केवल (self)
उपयोग करें और टाइप चेकर्स को आपके लिए self
के प्रकार का अनुमान लगाने दें। चूंकि ये पूरी तरह से सुरक्षित हैं इसलिए इन्हें mode='before'
सत्यापनकर्ताओं की तुलना में लागू करना अक्सर आसान होता है। यदि कोई फ़ील्ड सत्यापित करने में विफल रहता है, तो उस फ़ील्ड के लिए mode='after'
सत्यापनकर्ताओं को नहीं बुलाया जाएगा।
सत्यापनकर्ताओं में त्रुटियों को संभालना¶
जैसा कि पिछले अनुभागों में उल्लेख किया गया है, सत्यापन विफल होने का संकेत देने के लिए आप एक सत्यापनकर्ता के भीतर या तो एक ValueError
या AssertionError
( assert ...
स्टेटमेंट सहित) बढ़ा सकते हैं। आप एक PydanticCustomError
भी बढ़ा सकते हैं जो थोड़ा अधिक क्रियात्मक है लेकिन आपको अतिरिक्त लचीलापन देता है। किसी भी अन्य त्रुटि ( TypeError
सहित) को बबल किया गया है और ValidationError
में लपेटा नहीं गया है।
from pydantic_core import PydanticCustomError
from pydantic import BaseModel, ValidationError, field_validator
class Model(BaseModel):
x: int
@field_validator('x')
@classmethod
def validate_x(cls, v: int) -> int:
if v % 42 == 0:
raise PydanticCustomError(
'the_answer_error',
'{number} is the answer!',
{'number': v},
)
return v
try:
Model(x=42 * 2)
except ValidationError as e:
print(e)
"""
1 validation error for Model
x
84 is the answer! [type=the_answer_error, input_value=84, input_type=int]
"""
विशेष प्रकार¶
पाइडेंटिक कुछ विशेष प्रकार प्रदान करता है जिनका उपयोग सत्यापन को अनुकूलित करने के लिए किया जा सकता है।
-
[
InstanceOf
][pydantic.functional_validator.InstanceOf] एक प्रकार है जिसका उपयोग यह सत्यापित करने के लिए किया जा सकता है कि कोई मान किसी दिए गए वर्ग का एक उदाहरण है।from typing import List
from pydantic import BaseModel, InstanceOf, ValidationError
class Fruit: def repr(self): return self.class.name
class Banana(Fruit): ...
class Apple(Fruit): ...
class Basket(BaseModel): fruits: List[InstanceOf[Fruit]]
print(Basket(fruits=[Banana(), Apple()]))
> fruits=[Banana, Apple]¶
try: Basket(fruits=[Banana(), 'Apple']) except ValidationError as e: print(e) """ 1 validation error for Basket fruits.1 Input should be an instance of Fruit [type=is_instance_of, input_value='Apple', input_type=str] """
-
[
SkipValidation
][pydantic.functional_validator.SkipValidation] एक प्रकार है जिसका उपयोग किसी फ़ील्ड पर सत्यापन को छोड़ने के लिए किया जा सकता है।from typing import List
from pydantic import BaseModel, SkipValidation
class Model(BaseModel): names: List[SkipValidation[str]]
m = Model(names=['foo', 'bar']) print(m)
> names=['foo', 'bar']¶
m = Model(names=['foo', 123]) # (1)! print(m)
> names=['foo', 123]¶
-
ध्यान दें कि दूसरे आइटम का सत्यापन छोड़ दिया गया है। यदि इसका प्रकार गलत है तो यह क्रमबद्धता के दौरान एक चेतावनी जारी करेगा।
फ़ील्ड जांच¶
वर्ग निर्माण के दौरान, सत्यापनकर्ताओं की जाँच यह पुष्टि करने के लिए की जाती है कि उनके द्वारा निर्दिष्ट फ़ील्ड वास्तव में मॉडल पर मौजूद हैं।
यह अवांछनीय हो सकता है यदि, उदाहरण के लिए, आप फ़ील्ड को मान्य करने के लिए एक सत्यापनकर्ता को परिभाषित करना चाहते हैं जो केवल उस मॉडल के उपवर्गों पर मौजूद होगा जहां सत्यापनकर्ता को परिभाषित किया गया है।
यदि आप कक्षा निर्माण के दौरान इन चेकों को अक्षम करना चाहते हैं, तो आप सत्यापनकर्ता को कीवर्ड तर्क के रूप में check_fields=False
पास कर सकते हैं।
डेटाक्लास सत्यापनकर्ता¶
सत्यापनकर्ता पाइडेंटिक डेटाक्लास के साथ भी काम करते हैं।
from pydantic import field_validator
from pydantic.dataclasses import dataclass
@dataclass
class DemoDataclass:
product_id: str # should be a five-digit string, may have leading zeros
@field_validator('product_id', mode='before')
@classmethod
def convert_int_serial(cls, v):
if isinstance(v, int):
v = str(v).zfill(5)
return v
print(DemoDataclass(product_id='01234'))
#> DemoDataclass(product_id='01234')
print(DemoDataclass(product_id=2468))
#> DemoDataclass(product_id='02468')
मान्यता प्रसंग¶
आप एक संदर्भ ऑब्जेक्ट को सत्यापन विधियों में पास कर सकते हैं जिसे info
तर्क से सजाए गए सत्यापनकर्ता कार्यों तक पहुंचा जा सकता है:
from pydantic import BaseModel, ValidationInfo, field_validator
class Model(BaseModel):
text: str
@field_validator('text')
@classmethod
def remove_stopwords(cls, v: str, info: ValidationInfo):
context = info.context
if context:
stopwords = context.get('stopwords', set())
v = ' '.join(w for w in v.split() if w.lower() not in stopwords)
return v
data = {'text': 'This is an example document'}
print(Model.model_validate(data)) # no context
#> text='This is an example document'
print(Model.model_validate(data, context={'stopwords': ['this', 'is', 'an']}))
#> text='example document'
print(Model.model_validate(data, context={'stopwords': ['document']}))
#> text='This is an example'
यह तब उपयोगी होता है जब आपको रनटाइम के दौरान सत्यापन व्यवहार को गतिशील रूप से अपडेट करने की आवश्यकता होती है। उदाहरण के लिए, यदि आप चाहते हैं कि किसी फ़ील्ड में अनुमत मानों का गतिशील रूप से नियंत्रणीय सेट हो, तो यह अनुमत मानों को संदर्भ के आधार पर पारित करके और जो अनुमत है उसे अपडेट करने के लिए एक अलग तंत्र रखकर किया जा सकता है:
from typing import Any, Dict, List
from pydantic import (
BaseModel,
ValidationError,
ValidationInfo,
field_validator,
)
_allowed_choices = ['a', 'b', 'c']
def set_allowed_choices(allowed_choices: List[str]) -> None:
global _allowed_choices
_allowed_choices = allowed_choices
def get_context() -> Dict[str, Any]:
return {'allowed_choices': _allowed_choices}
class Model(BaseModel):
choice: str
@field_validator('choice')
@classmethod
def validate_choice(cls, v: str, info: ValidationInfo):
allowed_choices = info.context.get('allowed_choices')
if allowed_choices and v not in allowed_choices:
raise ValueError(f'choice must be one of {allowed_choices}')
return v
print(Model.model_validate({'choice': 'a'}, context=get_context()))
#> choice='a'
try:
print(Model.model_validate({'choice': 'd'}, context=get_context()))
except ValidationError as exc:
print(exc)
"""
1 validation error for Model
choice
Value error, choice must be one of ['a', 'b', 'c'] [type=value_error, input_value='d', input_type=str]
"""
set_allowed_choices(['b', 'c'])
try:
print(Model.model_validate({'choice': 'a'}, context=get_context()))
except ValidationError as exc:
print(exc)
"""
1 validation error for Model
choice
Value error, choice must be one of ['b', 'c'] [type=value_error, input_value='a', input_type=str]
"""
इसी तरह, आप क्रमबद्धता के लिए एक संदर्भ का उपयोग कर सकते हैं।
BaseModel
आरंभीकरण के साथ सत्यापन संदर्भ का उपयोग करना¶
हालाँकि मानक BaseModel
इनिशियलाइज़र में संदर्भ निर्दिष्ट करने का कोई तरीका नहीं है, आप contextvars.ContextVar
और एक कस्टम __init__
विधि के उपयोग के माध्यम से इस पर काम कर सकते हैं:
from contextlib import contextmanager
from contextvars import ContextVar
from typing import Any, Dict, Iterator
from pydantic import BaseModel, ValidationInfo, field_validator
_init_context_var = ContextVar('_init_context_var', default=None)
@contextmanager
def init_context(value: Dict[str, Any]) -> Iterator[None]:
token = _init_context_var.set(value)
try:
yield
finally:
_init_context_var.reset(token)
class Model(BaseModel):
my_number: int
def __init__(self, /, **data: Any) -> None:
self.__pydantic_validator__.validate_python(
data,
self_instance=self,
context=_init_context_var.get(),
)
@field_validator('my_number')
@classmethod
def multiply_with_context(cls, value: int, info: ValidationInfo) -> int:
if info.context:
multiplier = info.context.get('multiplier', 1)
value = value * multiplier
return value
print(Model(my_number=2))
#> my_number=2
with init_context({'multiplier': 3}):
print(Model(my_number=2))
#> my_number=6
print(Model(my_number=2))
#> my_number=2
सत्यापनकर्ताओं का पुन: उपयोग करना¶
कभी-कभी, आप एकाधिक फ़ील्ड/मॉडल पर एक ही सत्यापनकर्ता का उपयोग करना चाहेंगे (उदाहरण के लिए कुछ इनपुट डेटा को सामान्य करने के लिए)। "बेवकूफ" दृष्टिकोण एक अलग फ़ंक्शन लिखना होगा, फिर इसे कई डेकोरेटर्स से कॉल करना होगा। जाहिर है, इसमें बहुत अधिक दोहराव और बॉयलर प्लेट कोड शामिल है। निम्नलिखित दृष्टिकोण दर्शाता है कि आप एक सत्यापनकर्ता का पुन: उपयोग कैसे कर सकते हैं ताकि अतिरेक कम से कम हो और मॉडल फिर से लगभग घोषणात्मक बन जाएं।
from pydantic import BaseModel, field_validator
def normalize(name: str) -> str:
return ' '.join((word.capitalize()) for word in name.split(' '))
class Producer(BaseModel):
name: str
_normalize_name = field_validator('name')(normalize)
class Consumer(BaseModel):
name: str
_normalize_name = field_validator('name')(normalize)
jane_doe = Producer(name='JaNe DOE')
print(repr(jane_doe))
#> Producer(name='Jane Doe')
john_doe = Consumer(name='joHN dOe')
print(repr(john_doe))
#> Consumer(name='John Doe')
本文总阅读量次