Mode Ketat
??? api "Dokumentasi API" [pydantic.types.Strict
][pydantic.types.Ketat]
Secara default, Pydantic akan mencoba memaksakan nilai ke tipe yang diinginkan jika memungkinkan. Misalnya, Anda dapat meneruskan string "123"
sebagai masukan ke bidang int
, dan string tersebut akan dikonversi menjadi 123
. Perilaku pemaksaan ini berguna dalam banyak skenario — pikirkan: UUID, parameter URL, header HTTP, variabel lingkungan, masukan pengguna, dll.
Namun, ada juga situasi di mana hal ini tidak diinginkan, dan Anda ingin Pydantic melakukan kesalahan alih-alih memaksa data.
Untuk lebih mendukung kasus penggunaan ini, Pydantic menyediakan "mode ketat" yang dapat diaktifkan berdasarkan per model, per bidang, atau bahkan per panggilan validasi. Ketika mode ketat diaktifkan, Pydantic akan menjadi lebih lunak saat memaksa data, dan malah akan error jika tipe datanya tidak benar.
Berikut adalah contoh singkat yang menunjukkan perbedaan antara perilaku validasi dalam mode ketat dan mode default/"lax":
from pydantic import BaseModel, ValidationError
class MyModel(BaseModel):
x: int
print(MyModel.model_validate({'x': '123'})) # lax mode
#> x=123
try:
MyModel.model_validate({'x': '123'}, strict=True) # strict mode
except ValidationError as exc:
print(exc)
"""
1 validation error for MyModel
x
Input should be a valid integer [type=int_type, input_value='123', input_type=str]
"""
Ada berbagai cara untuk mendapatkan validasi mode ketat saat menggunakan Pydantic, yang akan dibahas lebih detail di bawah ini:
- Meneruskan
strict=True
ke metode validasi , sepertiBaseModel.model_validate
,TypeAdapter.validate_python
, dan serupa untuk JSON - Menggunakan
Field(strict=True)
dengan fieldBaseModel
,dataclass
, atauTypedDict
- Menggunakan
pydantic.types.Strict
sebagai anotasi tipe pada suatu bidang- Pydantic menyediakan beberapa alias tipe yang sudah dianotasi dengan
Strict
, sepertipydantic.types.StrictInt
- Pydantic menyediakan beberapa alias tipe yang sudah dianotasi dengan
- Menggunakan
ConfigDict(strict=True)
Ketik paksaan dalam mode ketat¶
Untuk sebagian besar tipe, saat memvalidasi data dari python dalam mode ketat, hanya instance dari tipe persisnya yang diterima. Misalnya, saat memvalidasi bidang int
, hanya contoh int
yang diterima; melewatkan instance float
atau str
akan menghasilkan ValidationError
.
Perhatikan bahwa kami lebih longgar saat memvalidasi data dari JSON dalam mode ketat. Misalnya, saat memvalidasi bidang UUID
, instance str
akan diterima saat memvalidasi dari JSON, namun tidak dari python:
import json
from uuid import UUID
from pydantic import BaseModel, ValidationError
class MyModel(BaseModel):
guid: UUID
data = {'guid': '12345678-1234-1234-1234-123456789012'}
print(MyModel.model_validate(data)) # OK: lax
#> guid=UUID('12345678-1234-1234-1234-123456789012')
print(
MyModel.model_validate_json(json.dumps(data), strict=True)
) # OK: strict, but from json
#> guid=UUID('12345678-1234-1234-1234-123456789012')
try:
MyModel.model_validate(data, strict=True) # Not OK: strict, from python
except ValidationError as exc:
print(exc.errors(include_url=False))
"""
[
{
'type': 'is_instance_of',
'loc': ('guid',),
'msg': 'Input should be an instance of UUID',
'input': '12345678-1234-1234-1234-123456789012',
'ctx': {'class': 'UUID'},
}
]
"""
Untuk lebih jelasnya mengenai jenis apa saja yang diperbolehkan sebagai input pada mode ketat, Anda dapat meninjau Tabel Konversi .
Mode ketat dalam pemanggilan metode¶
Semua contoh yang disertakan sejauh ini mendapatkan validasi mode ketat melalui penggunaan strict=True
sebagai argumen kata kunci pada metode validasi. Meskipun kami telah menunjukkan ini untuk BaseModel.model_validate
, ini juga berfungsi dengan tipe arbitrer melalui penggunaan TypeAdapter
:
from pydantic import TypeAdapter, ValidationError
print(TypeAdapter(bool).validate_python('yes')) # OK: lax
#> True
try:
TypeAdapter(bool).validate_python('yes', strict=True) # Not OK: strict
except ValidationError as exc:
print(exc)
"""
1 validation error for bool
Input should be a valid boolean [type=bool_type, input_value='yes', input_type=str]
"""
Perhatikan ini juga berfungsi bahkan ketika menggunakan tipe yang lebih "kompleks" di TypeAdapter
:
from dataclasses import dataclass
from pydantic import TypeAdapter, ValidationError
@dataclass
class MyDataclass:
x: int
try:
TypeAdapter(MyDataclass).validate_python({'x': '123'}, strict=True)
except ValidationError as exc:
print(exc)
"""
1 validation error for MyDataclass
Input should be an instance of MyDataclass [type=dataclass_exact_type, input_value={'x': '123'}, input_type=dict]
"""
Ini juga berfungsi dengan metode TypeAdapter.validate_json
dan BaseModel.model_validate_json
:
import json
from typing import List
from uuid import UUID
from pydantic import BaseModel, TypeAdapter, ValidationError
try:
TypeAdapter(List[int]).validate_json('["1", 2, "3"]', strict=True)
except ValidationError as exc:
print(exc)
"""
2 validation errors for list[int]
0
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
2
Input should be a valid integer [type=int_type, input_value='3', input_type=str]
"""
class Model(BaseModel):
x: int
y: UUID
data = {'x': '1', 'y': '12345678-1234-1234-1234-123456789012'}
try:
Model.model_validate(data, strict=True)
except ValidationError as exc:
# Neither x nor y are valid in strict mode from python:
print(exc)
"""
2 validation errors for Model
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
y
Input should be an instance of UUID [type=is_instance_of, input_value='12345678-1234-1234-1234-123456789012', input_type=str]
"""
json_data = json.dumps(data)
try:
Model.model_validate_json(json_data, strict=True)
except ValidationError as exc:
# From JSON, x is still not valid in strict mode, but y is:
print(exc)
"""
1 validation error for Model
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
Mode ketat dengan Field
¶
Untuk masing-masing bidang pada model, Anda dapat mengatur strict=True
pada bidang tersebut . Hal ini akan menyebabkan validasi mode ketat digunakan untuk bidang tersebut, meskipun metode validasi dipanggil tanpa strict=True
.
Hanya kolom yang strict=True
disetel yang akan terpengaruh:
from pydantic import BaseModel, Field, ValidationError
class User(BaseModel):
name: str
age: int
n_pets: int
user = User(name='John', age='42', n_pets='1')
print(user)
#> name='John' age=42 n_pets=1
class AnotherUser(BaseModel):
name: str
age: int = Field(strict=True)
n_pets: int
try:
anotheruser = AnotherUser(name='John', age='42', n_pets='1')
except ValidationError as e:
print(e)
"""
1 validation error for AnotherUser
age
Input should be a valid integer [type=int_type, input_value='42', input_type=str]
"""
Perhatikan bahwa membuat bidang menjadi ketat juga akan memengaruhi validasi yang dilakukan saat membuat instance kelas model:
from pydantic import BaseModel, Field, ValidationError
class Model(BaseModel):
x: int = Field(strict=True)
y: int = Field(strict=False)
try:
Model(x='1', y='2')
except ValidationError as exc:
print(exc)
"""
1 validation error for Model
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
Menggunakan Field
sebagai anotasi¶
Perhatikan bahwa Field(strict=True)
(atau dengan argumen kata kunci lainnya) dapat digunakan sebagai anotasi jika diperlukan, misalnya saat bekerja dengan TypedDict
:
from typing_extensions import Annotated, TypedDict
from pydantic import Field, TypeAdapter, ValidationError
class MyDict(TypedDict):
x: Annotated[int, Field(strict=True)]
try:
TypeAdapter(MyDict).validate_python({'x': '1'})
except ValidationError as exc:
print(exc)
"""
1 validation error for typed-dict
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
Mode ketat dengan Annotated[..., Strict()]
¶
??? api "Dokumentasi API" [pydantic.types.Strict
][pydantic.types.Ketat]
Pydantic juga menyediakan kelas Strict
, yang dimaksudkan untuk digunakan sebagai metadata dengan kelas typing.Annotated
; anotasi ini menunjukkan bahwa bidang yang diberi anotasi harus divalidasi dalam mode ketat:
from typing_extensions import Annotated
from pydantic import BaseModel, Strict, ValidationError
class User(BaseModel):
name: str
age: int
is_active: Annotated[bool, Strict()]
User(name='David', age=33, is_active=True)
try:
User(name='David', age=33, is_active='True')
except ValidationError as exc:
print(exc)
"""
1 validation error for User
is_active
Input should be a valid boolean [type=bool_type, input_value='True', input_type=str]
"""
Faktanya, ini adalah metode yang digunakan untuk mengimplementasikan beberapa tipe strict-out-of-the-box yang disediakan oleh Pydantic, seperti StrictInt
.
Mode ketat dengan ConfigDict
¶
BaseModel
¶
Jika Anda ingin mengaktifkan mode ketat untuk semua bidang pada tipe input kompleks, Anda dapat menggunakan ConfigDict(strict=True)
di model_config
:
from pydantic import BaseModel, ConfigDict, ValidationError
class User(BaseModel):
model_config = ConfigDict(strict=True)
name: str
age: int
is_active: bool
try:
User(name='David', age='33', is_active='yes')
except ValidationError as exc:
print(exc)
"""
2 validation errors for User
age
Input should be a valid integer [type=int_type, input_value='33', input_type=str]
is_active
Input should be a valid boolean [type=bool_type, input_value='yes', input_type=str]
"""
!!! catatan Saat menggunakan strict=True
melalui model_config
model, Anda masih dapat mengganti ketatnya masing-masing bidang dengan menyetel strict=False
pada masing-masing bidang:
```py
from pydantic import BaseModel, ConfigDict, Field
class User(BaseModel):
model_config = ConfigDict(strict=True)
name: str
age: int = Field(strict=False)
```
Perhatikan bahwa mode ketat tidak diterapkan secara rekursif ke bidang model bertumpuk:
from pydantic import BaseModel, ConfigDict, ValidationError
class Inner(BaseModel):
y: int
class Outer(BaseModel):
model_config = ConfigDict(strict=True)
x: int
inner: Inner
print(Outer(x=1, inner=Inner(y='2')))
#> x=1 inner=Inner(y=2)
try:
Outer(x='1', inner=Inner(y='2'))
except ValidationError as exc:
print(exc)
"""
1 validation error for Outer
x
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
(Ini juga berlaku untuk dataclasses dan TypedDict
.)
Jika hal ini tidak diinginkan, Anda harus memastikan bahwa mode ketat diaktifkan untuk semua jenis yang terlibat. Misalnya, hal ini dapat dilakukan untuk kelas model dengan menggunakan kelas dasar bersama model_config = ConfigDict(strict=True)
:
from pydantic import BaseModel, ConfigDict, ValidationError
class MyBaseModel(BaseModel):
model_config = ConfigDict(strict=True)
class Inner(MyBaseModel):
y: int
class Outer(MyBaseModel):
x: int
inner: Inner
try:
Outer.model_validate({'x': 1, 'inner': {'y': '2'}})
except ValidationError as exc:
print(exc)
"""
1 validation error for Outer
inner.y
Input should be a valid integer [type=int_type, input_value='2', input_type=str]
"""
Kelas data dan TypedDict
¶
Kelas data Pydantic berperilaku mirip dengan contoh yang ditunjukkan di atas dengan BaseModel
, hanya saja alih-alih model_config
Anda harus menggunakan argumen kata kunci config
ke @pydantic.dataclasses.dataclass
penghias.
Jika memungkinkan, Anda dapat mencapai mode ketat bersarang untuk kelas data vanilla atau subkelas TypedDict
dengan memberi anotasi pada bidang dengan anotasi pydantic.types.Strict
.
Namun, jika hal ini tidak memungkinkan (misalnya, ketika bekerja dengan tipe pihak ketiga), Anda dapat mengatur konfigurasi yang harus digunakan Pydantic untuk tipe tersebut dengan mengatur atribut __pydantic_config__
pada tipe:
from typing_extensions import TypedDict
from pydantic import ConfigDict, TypeAdapter, ValidationError
class Inner(TypedDict):
y: int
Inner.__pydantic_config__ = ConfigDict(strict=True)
class Outer(TypedDict):
x: int
inner: Inner
adapter = TypeAdapter(Outer)
print(adapter.validate_python({'x': '1', 'inner': {'y': 2}}))
#> {'x': 1, 'inner': {'y': 2}}
try:
adapter.validate_python({'x': '1', 'inner': {'y': '2'}})
except ValidationError as exc:
print(exc)
"""
1 validation error for typed-dict
inner.y
Input should be a valid integer [type=int_type, input_value='2', input_type=str]
"""
TypeAdapter
¶
Anda juga bisa mendapatkan mode ketat melalui penggunaan argumen kata kunci config ke kelas TypeAdapter
:
from pydantic import ConfigDict, TypeAdapter, ValidationError
adapter = TypeAdapter(bool, config=ConfigDict(strict=True))
try:
adapter.validate_python('yes')
except ValidationError as exc:
print(exc)
"""
1 validation error for bool
Input should be a valid boolean [type=bool_type, input_value='yes', input_type=str]
"""
@validate_call
¶
Mode ketat juga dapat digunakan dengan dekorator @validate_call
dengan meneruskan argumen kata kunci config
:
from pydantic import ConfigDict, ValidationError, validate_call
@validate_call(config=ConfigDict(strict=True))
def foo(x: int) -> int:
return x
try:
foo('1')
except ValidationError as exc:
print(exc)
"""
1 validation error for foo
0
Input should be a valid integer [type=int_type, input_value='1', input_type=str]
"""
本文总阅读量次