Validator Beranotasi¶
??? api "Dokumentasi API" [pydantic.functional_validators.WrapValidator
][pydantic.fungsional_validators.WrapValidator]
[pydantic.functional_validators.PlainValidator
][pydantic.fungsional_validator.PlainValidator]
[pydantic.functional_validators.BeforeValidator
][pydantic.fungsional_validators.BeforeValidator]
[pydantic.functional_validators.AfterValidator
][pydantic.fungsional_validator.AfterValidator]
Pydantic menyediakan cara untuk menerapkan validator melalui penggunaan Annotated
. Anda harus menggunakan ini kapan pun Anda ingin mengikat validasi ke suatu tipe, bukan model atau bidang.
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]
"""
Dalam contoh ini kami menggunakan beberapa tipe alias ( MyNumber = Annotated[...]
). Meskipun hal ini dapat membantu keterbacaan kode, hal ini tidak diperlukan, Anda dapat menggunakan Annotated
secara langsung dalam petunjuk jenis bidang model. Alias tipe ini juga bukan tipe sebenarnya tetapi Anda dapat menggunakan pendekatan serupa dengan TypeAliasType
untuk membuat tipe sebenarnya. Lihat Tipe Kustom untuk penjelasan lebih detail mengenai tipe kustom.
Perlu juga dicatat bahwa Anda dapat membuat sarang Annotated
di dalam tipe lain. Dalam contoh ini kami menggunakannya untuk menerapkan validasi ke item dalam daftar. Pendekatan yang sama dapat digunakan untuk kunci dict, dll.
Validator Sebelum, Setelah, Bungkus, dan Biasa¶
Pydantic menyediakan beberapa jenis fungsi validator:
After
validator dijalankan setelah parsing internal Pydantic. Mereka umumnya lebih aman dan lebih mudah diterapkan.Before
validator dijalankan sebelum penguraian dan validasi internal Pydantic (misalnya pemaksaanstr
keint
). Ini lebih fleksibel daripada validatorAfter
karena mereka dapat memodifikasi masukan mentah, namun mereka juga harus menangani masukan mentah, yang secara teori dapat berupa objek apa pun.- Validator
Plain
seperti validatormode='before'
tetapi mereka segera menghentikan validasi, tidak ada validator lebih lanjut yang dipanggil dan Pydantic tidak melakukan validasi internal apa pun. - Validator
Wrap
adalah yang paling fleksibel dari semuanya. Anda dapat menjalankan kode sebelum atau setelah Pydantic dan validator lain melakukan tugasnya atau Anda dapat segera menghentikan validasi, baik dengan nilai berhasil atau kesalahan.
Anda dapat menggunakan beberapa validator sebelum, sesudah, atau mode='wrap'
, namun hanya satu PlainValidator
karena validator biasa tidak akan memanggil validator dalam apa pun.
Berikut ini contoh validator 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]
"""
"Mode" yang sama berlaku untuk @field_validator
, yang akan dibahas di bagian selanjutnya.
Pengurutan validator dalam Annotated
¶
Urutan metadata validasi dalam hal-hal Annotated
. Validasi berjalan dari kanan ke kiri dan belakang. Yaitu, dari kanan ke kiri menjalankan semua validator "sebelum" (atau memanggil validator "bungkus"), lalu dari kiri ke kanan kembali memanggil semua validator "setelah".
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',
]
"""
Validasi nilai default¶
Validator tidak akan berjalan ketika nilai default digunakan. Hal ini berlaku untuk validator @field_validator
dan validator Annotated
. Anda dapat memaksanya untuk dijalankan dengan Field(validate_default=True)
. Menyetel validate_default
ke True
memiliki perilaku yang paling mirip dengan penggunaan always=True
di validator
di Pydantic v1. Namun, Anda biasanya lebih baik menggunakan a @model_validator(mode='before')
di mana fungsinya dipanggil sebelum validator dalam dipanggil.
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'
Validator lapangan¶
??? api "Dokumentasi API" [pydantic.functional_validators.field_validator
][pydantic.fungsional_validator.field_validator]
Jika Anda ingin melampirkan validator ke bidang model tertentu, Anda dapat menggunakan dekorator @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]
"""
Beberapa hal yang perlu diperhatikan pada validator:
@field_validator
adalah "metode kelas", jadi nilai argumen pertama yang mereka terima adalah kelasUserModel
, bukan turunan dariUserModel
. Kami menyarankan Anda menggunakan dekorator@classmethod
di bawah dekorator@field_validator
untuk mendapatkan pemeriksaan tipe yang tepat.- argumen kedua adalah nilai bidang yang akan divalidasi; bisa diberi nama sesukamu
- argumen ketiga, jika ada, adalah turunan dari
pydantic.ValidationInfo
- validator harus mengembalikan nilai yang diurai atau menaikkan
ValueError
atauAssertionError
(pernyataanassert
dapat digunakan). - Validator tunggal dapat diterapkan ke beberapa bidang dengan meneruskan beberapa nama bidang ke dalamnya.
- Validator tunggal juga dapat dipanggil di semua bidang dengan meneruskan nilai khusus
'*'
.
!!! peringatan Jika Anda menggunakan pernyataan assert
, perlu diingat bahwa menjalankan Python dengan tanda optimasi -O
akan menonaktifkan pernyataan assert
, dan validator akan berhenti bekerja .
!!! catatan FieldValidationInfo
tidak digunakan lagi di 2.4, gunakan ValidationInfo
sebagai gantinya.
Jika Anda ingin mengakses nilai dari bidang lain di dalam @field_validator
, hal ini dapat dilakukan menggunakan ValidationInfo.data
, yang merupakan dict nama bidang ke nilai bidang. Validasi dilakukan pada kolom urutan yang ditentukan, jadi Anda harus berhati-hati saat menggunakan ValidationInfo.data
agar tidak mengakses kolom yang belum divalidasi/diisi — pada kode di atas, misalnya, Anda tidak akan dapat mengakses info.data['id']
dari dalam name_must_contain_space
. Namun, dalam kebanyakan kasus ketika Anda ingin melakukan validasi menggunakan beberapa nilai bidang, lebih baik menggunakan @model_validator
yang dibahas pada bagian di bawah ini.
Validator model¶
??? api "Dokumentasi API" [pydantic.functional_validators.model_validator
][pydantic.fungsional_validator.model_validator]
Validasi juga dapat dilakukan pada seluruh data model menggunakan @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]
"""
!!! catatan "Saat pengecekan tipe kembali" Metode yang dihiasi dengan @model_validator
harus mengembalikan instance mandiri di akhir metode. Untuk tujuan pemeriksaan tipe, Anda dapat menggunakan Self
dari typing
atau backport typing_extensions
sebagai tipe kembalian dari metode yang didekorasi. Dalam konteks contoh di atas, Anda juga bisa menggunakan def check_passwords_match(self: 'UserModel') -> 'UserModel'
untuk menunjukkan bahwa metode mengembalikan sebuah instance dari model.
!!! catatan "Pada Warisan" @model_validator
yang didefinisikan dalam kelas dasar akan dipanggil selama validasi instance subkelas.
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.
Validator model dapat berupa mode='before'
, mode='after'
atau mode='wrap'
.
Sebelum validator model diberikan masukan mentah yang seringkali berupa dict[str, Any]
namun bisa juga berupa turunan dari model itu sendiri (misalnya jika UserModel.model_validate(UserModel.construct(...))
dipanggil) atau apa pun karena Anda dapat meneruskan objek arbitrer ke model_validate
. Karena itu validator mode='before'
ini sangat fleksibel dan kuat, namun penerapannya rumit dan rawan kesalahan. Sebelum validator model harus menjadi metode kelas. Argumen pertama harus cls
(dan kami juga menyarankan Anda menggunakan @classmethod
di bawah @model_validator
untuk pemeriksaan tipe yang tepat), argumen kedua akan menjadi input (biasanya Anda harus mengetikkannya sebagai Any
dan menggunakan isinstance
untuk mempersempit tipe) dan yang ketiga argumen (jika ada) akan menjadi pydantic.ValidationInfo
.
validator mode='after'
adalah metode instan dan selalu menerima instance model sebagai argumen pertama. Pastikan untuk mengembalikan instance di akhir validator Anda. Anda tidak boleh menggunakan (cls, ModelType)
sebagai tanda tangan, cukup gunakan (self)
dan biarkan pemeriksa tipe menyimpulkan tipe self
untuk Anda. Karena ini sepenuhnya aman untuk diketik, seringkali lebih mudah diterapkan daripada validator mode='before'
. Jika ada bidang yang gagal divalidasi, validator mode='after'
untuk bidang tersebut tidak akan dipanggil.
Menangani kesalahan pada validator¶
Seperti disebutkan di bagian sebelumnya, Anda dapat memunculkan ValueError
atau AssertionError
(termasuk pernyataan yang dihasilkan oleh assert ...
) dalam validator untuk menunjukkan validasi gagal. Anda juga dapat meningkatkan PydanticCustomError
yang sedikit lebih bertele-tele namun memberi Anda fleksibilitas ekstra. Kesalahan lainnya (termasuk TypeError
) akan dimunculkan dan tidak dimasukkan ke dalam 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]
"""
Tipe Khusus¶
Pydantic menyediakan beberapa tipe khusus yang dapat digunakan untuk menyesuaikan validasi.
-
[
InstanceOf
][pydantic.function_validators.InstanceOf] adalah tipe yang dapat digunakan untuk memvalidasi bahwa suatu nilai adalah turunan dari kelas tertentu.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.function_validators.SkipValidation] adalah tipe yang dapat digunakan untuk melewati validasi pada suatu bidang.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]¶
-
Perhatikan bahwa validasi item kedua dilewati. Jika tipenya salah maka akan mengeluarkan peringatan selama serialisasi.
Pemeriksaan lapangan¶
Selama pembuatan kelas, validator diperiksa untuk mengonfirmasi bahwa bidang yang mereka tentukan benar-benar ada pada model.
Hal ini mungkin tidak diinginkan jika, misalnya, Anda ingin menentukan validator untuk memvalidasi bidang yang hanya akan ada pada subkelas model tempat validator ditentukan.
Jika Anda ingin menonaktifkan pemeriksaan ini selama pembuatan kelas, Anda dapat meneruskan check_fields=False
sebagai argumen kata kunci ke validator.
Validator kelas data¶
Validator juga bekerja dengan kelas data Pydantic.
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')
Konteks Validasi¶
Anda dapat meneruskan objek konteks ke metode validasi yang dapat diakses dari argumen info
ke fungsi validator yang dihias:
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'
Ini berguna ketika Anda perlu memperbarui perilaku validasi secara dinamis selama runtime. Misalnya, jika Anda ingin sebuah bidang memiliki kumpulan nilai yang diizinkan yang dapat dikontrol secara dinamis, hal ini dapat dilakukan dengan meneruskan nilai yang diizinkan berdasarkan konteks, dan memiliki mekanisme terpisah untuk memperbarui nilai yang diizinkan:
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]
"""
Demikian pula, Anda dapat menggunakan konteks untuk serialisasi .
Menggunakan konteks validasi dengan inisialisasi BaseModel
¶
Meskipun tidak ada cara untuk menentukan konteks dalam penginisialisasi BaseModel
standar, Anda dapat menyiasatinya melalui penggunaan contextvars.ContextVar
dan metode __init__
khusus:
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
Menggunakan kembali Validator¶
Kadang-kadang, Anda ingin menggunakan validator yang sama pada beberapa bidang/model (misalnya untuk menormalkan beberapa data masukan). Pendekatan "naif" adalah dengan menulis fungsi terpisah, lalu memanggilnya dari beberapa dekorator. Jelas, ini memerlukan banyak pengulangan dan kode pelat ketel. Pendekatan berikut menunjukkan bagaimana Anda dapat menggunakan kembali validator sehingga redundansi diminimalkan dan model menjadi hampir deklaratif.
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')
本文总阅读量次