Geannoteerde validaties¶
??? api "API-documentatie" pydantic.functional_validators.WrapValidator
pydantic.functional_validators.PlainValidator
pydantic.functional_validators.BeforeValidator
pydantic.functional_validators.AfterValidator
Pydantic biedt een manier om validators toe te passen via het gebruik van Annotated
. U moet dit gebruiken wanneer u validatie aan een type wilt koppelen in plaats van aan een model of veld.
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]
"""
In dit voorbeeld hebben we enkele typealiassen gebruikt ( MyNumber = Annotated[...]
). Hoewel dit kan helpen bij de leesbaarheid van de code, is dit niet vereist. U kunt Annotated
rechtstreeks gebruiken in een hint van het modelveldtype. Deze typealiassen zijn ook geen werkelijke typen, maar u kunt een vergelijkbare aanpak gebruiken met TypeAliasType
om werkelijke typen te maken. Zie Aangepaste typen voor een meer gedetailleerde uitleg van aangepaste typen.
Het is ook vermeldenswaard dat u Annotated
in andere typen kunt nesten. In dit voorbeeld hebben we dat gebruikt om validatie toe te passen op de binnenste items van een lijst. Dezelfde aanpak kan worden gebruikt voor dicteertoetsen, enz.
Voor-, Na-, Wrap- en Plain-validators¶
Pydantic biedt meerdere soorten validatorfuncties:
After
validators zijn uitgevoerd na de interne parsering van Pydantic. Ze zijn over het algemeen typeveiliger en dus gemakkelijker te implementeren.Before
validators worden uitgevoerd vóór de interne parsering en validatie van Pydantic (bijvoorbeeld dwang van astr
naar eenint
). Deze zijn flexibeler danAfter
validators omdat ze de onbewerkte invoer kunnen wijzigen, maar ze hebben ook te maken met de onbewerkte invoer, die in theorie elk willekeurig object kan zijn.Plain
validators zijn als eenmode='before'
validator, maar ze beëindigen de validatie onmiddellijk, er worden geen verdere validators aangeroepen en Pydantic voert geen enkele interne validatie uit.Wrap
zijn het meest flexibel van allemaal. U kunt code uitvoeren voordat of nadat Pydantic en andere validators hun ding doen, of u kunt de validatie onmiddellijk beëindigen, zowel met een succesvolle waarde als met een fout.
U kunt meerdere validators voor, na of mode='wrap'
gebruiken, maar slechts één PlainValidator
aangezien een gewone validator geen interne validators zal aanroepen.
Hier is een voorbeeld van een mode='wrap'
validator:
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]
"""
Dezelfde "modi" zijn van toepassing op @field_validator
, wat in de volgende sectie wordt besproken.
Bestellen van validators binnen Annotated
¶
Volgorde van validatiemetagegevens binnen Annotated
zaken. Validatie gaat van rechts naar links en terug. Dat wil zeggen, het gaat van rechts naar links waarbij alle "voor" validators worden uitgevoerd (of de "wrap" validators worden aangeroepen), en vervolgens van links naar rechts weer alle "na" validators worden opgeroepen.
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',
]
"""
Validatie van standaardwaarden¶
Validators worden niet uitgevoerd als de standaardwaarde wordt gebruikt. Dit geldt zowel voor @field_validator
-validators als voor Annotated
validators. Je kunt ze dwingen om uit te voeren met Field(validate_default=True)
. Het instellen van validate_default
op True
komt het dichtst in de buurt van het gebruik van always=True
in validator
in Pydantic v1. Over het algemeen bent u echter beter af als u een @model_validator(mode='before')
waarbij de functie wordt aangeroepen voordat de innerlijke validator wordt aangeroepen.
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'
Veldvalidators¶
??? api "API-documentatie" pydantic.functional_validators.field_validator
Als u een validator aan een specifiek veld van een model wilt koppelen, kunt u de @field_validator
decorateur gebruiken.
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]
"""
Een paar dingen om op te merken over validators:
@field_validator
s zijn "klassemethoden", dus de eerste argumentwaarde die ze ontvangen is de klasseUserModel
, en niet een exemplaar vanUserModel
. We raden u aan de@classmethod
-decorator onder de@field_validator
-decorator te gebruiken om de juiste typecontrole te krijgen.- het tweede argument is de veldwaarde die moet worden gevalideerd; het kan worden genoemd zoals u wilt
- het derde argument, indien aanwezig, is een exemplaar van
pydantic.ValidationInfo
- validators moeten de geparseerde waarde retourneren of een
ValueError
ofAssertionError
verhogen (er kunnenassert
-instructies worden gebruikt). - Eén enkele validator kan op meerdere velden worden toegepast door meerdere veldnamen door te geven.
- Er kan ook één enkele validator op alle velden worden aangeroepen door de speciale waarde
'*'
door te geven.
!!! waarschuwing Als u gebruik maakt van assert
-statements, houd er dan rekening mee dat het uitvoeren van Python met de optimalisatievlag -O
assert
-statements uitschakelt, en dat validators niet meer werken .
!!! opmerking FieldValidationInfo
is verouderd in 2.4. Gebruik in plaats daarvan ValidationInfo
.
Als u toegang wilt krijgen tot waarden uit een ander veld binnen een @field_validator
, kan dit mogelijk zijn met behulp van ValidationInfo.data
, wat een dictaat is van veldnaam tot veldwaarde. Validatie vindt plaats in de volgorde waarin de velden zijn gedefinieerd, dus u moet voorzichtig zijn wanneer u ValidationInfo.data
gebruikt om geen toegang te krijgen tot een veld dat nog niet is gevalideerd/ingevuld. In de bovenstaande code zou u bijvoorbeeld geen toegang hebben info.data['id']
vanuit name_must_contain_space
. In de meeste gevallen waarin u validatie wilt uitvoeren met behulp van meerdere veldwaarden, is het echter beter om @model_validator
te gebruiken, wat in het onderstaande gedeelte wordt besproken.
Modelvalidatoren¶
??? api "API-documentatie" pydantic.functional_validators.model_validator
Validatie kan ook worden uitgevoerd op de gegevens van het volledige model met behulp van @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]
"""
!!! opmerking "Bij retourneringstypecontrole" Methoden gedecoreerd met @model_validator
zouden de self-instantie aan het einde van de methode moeten retourneren. Voor typecontroledoeleinden kunt u Self
from typing
of de typing_extensions
backport gebruiken als het retourtype van de gedecoreerde methode. In de context van het bovenstaande voorbeeld kunt u ook gebruiken def check_passwords_match(self: 'UserModel') -> 'UserModel'
om aan te geven dat de methode een exemplaar van het model retourneert.
!!! opmerking "Bij overerving" Een @model_validator
gedefinieerd in een basisklasse zal worden aangeroepen tijdens de validatie van een subklasse-instantie.
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.
Modelvalidators kunnen mode='before'
, mode='after'
of mode='wrap'
zijn.
Voordat modelvalidators worden doorgegeven, wordt de onbewerkte invoer ingevoerd, die vaak een dict[str, Any]
is, maar ook een instantie van het model zelf kan zijn (bijvoorbeeld als UserModel.model_validate(UserModel.construct(...))
wordt genoemd) of iets anders, omdat u willekeurige objecten kunt doorgeven aan model_validate
. Hierdoor zijn mode='before'
validators uiterst flexibel en krachtig, maar kunnen ze omslachtig en foutgevoelig zijn om te implementeren. Voordat modelvalidators klassemethoden zouden moeten zijn. Het eerste argument moet cls
zijn (en we raden u ook aan @classmethod
onder @model_validator
te gebruiken voor de juiste typecontrole), het tweede argument zal de invoer zijn (u moet het over het algemeen als Any
typen en isinstance
gebruiken om het type te beperken) en het derde argument (indien aanwezig) zal een pydantic.ValidationInfo
zijn.
mode='after'
validators zijn instantiemethoden en krijgen altijd een instantie van het model als eerste argument. Zorg ervoor dat u de instantie aan het einde van uw validator retourneert. U moet niet (cls, ModelType)
als handtekening gebruiken, maar gewoon (self)
gebruiken en typecontroleurs het type self
voor u laten afleiden. Omdat deze volledig typeveilig zijn, zijn ze vaak eenvoudiger te implementeren dan mode='before'
-validators. Als een veld niet kan worden gevalideerd, worden mode='after'
validators voor dat veld niet aangeroepen.
Afhandelen van fouten in validators¶
Zoals vermeld in de vorige secties kunt u een ValueError
of AssertionError
genereren (inclusief de fouten die zijn gegenereerd door assert ...
-instructies) binnen een validator om aan te geven dat de validatie is mislukt. U kunt ook een PydanticCustomError
verhogen, die iets uitgebreider is maar u extra flexibiliteit geeft. Alle andere fouten (inclusief TypeError
) worden weergegeven en niet verpakt in een 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]
"""
Speciale typen¶
Pydantic biedt een paar speciale typen die kunnen worden gebruikt om de validatie aan te passen.
-
InstanceOf
is een type dat kan worden gebruikt om te valideren dat een waarde een exemplaar van een bepaalde klasse is.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
is een type dat kan worden gebruikt om de validatie van een veld over te slaan.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]¶
-
Houd er rekening mee dat de validatie van het tweede item wordt overgeslagen. Als het het verkeerde type heeft, geeft het een waarschuwing tijdens de serialisatie.
Veldcontroles¶
Tijdens het maken van klassen worden validators gecontroleerd om te bevestigen dat de velden die zij specificeren daadwerkelijk in het model voorkomen.
Dit kan onwenselijk zijn als u bijvoorbeeld een validator wilt definiëren om velden te valideren die alleen aanwezig zullen zijn in subklassen van het model waarin de validator is gedefinieerd.
Als u deze controles wilt uitschakelen tijdens het maken van een klasse, kunt u check_fields=False
als trefwoordargument doorgeven aan de validator.
Dataclass-validators¶
Validators werken ook met Pydantic-dataklassen.
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')
Validatiecontext¶
U kunt een contextobject doorgeven aan de validatiemethoden die toegankelijk zijn via het info
-argument voor gedecoreerde validatorfuncties:
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'
Dit is handig wanneer u het validatiegedrag tijdens runtime dynamisch moet bijwerken. Als u bijvoorbeeld wilt dat een veld een dynamisch bestuurbare set toegestane waarden heeft, kunt u dit doen door de toegestane waarden per context door te geven en een apart mechanisme te hebben voor het bijwerken van wat is toegestaan:
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]
"""
Op dezelfde manier kunt u een context gebruiken voor serialisatie .
Validatiecontext gebruiken met BaseModel
initialisatie¶
Hoewel er geen manier is om een context op te geven in de standaard BaseModel
initializer, kunt u dit omzeilen door het gebruik van contextvars.ContextVar
en een aangepaste __init__
methode:
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
Validatoren hergebruiken¶
Af en toe zult u dezelfde validator op meerdere velden/modellen willen gebruiken (bijvoorbeeld om bepaalde invoergegevens te normaliseren). De "naïeve" benadering zou zijn om een aparte functie te schrijven en deze vervolgens door meerdere decorateurs aan te roepen. Uiteraard brengt dit veel herhaling en boilerplate-code met zich mee. De volgende aanpak laat zien hoe je een validator kunt hergebruiken, zodat redundantie wordt geminimaliseerd en de modellen weer bijna declaratief worden.
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')
本文总阅读量次