notes on Pydantic
This commit is contained in:
parent
b0c1cab95a
commit
0790cd2218
1 changed files with 98 additions and 0 deletions
98
zk/Pydantic.md
Normal file
98
zk/Pydantic.md
Normal file
|
|
@ -0,0 +1,98 @@
|
|||
---
|
||||
tags: [python]
|
||||
---
|
||||
|
||||
Pydantic provides runtime type-checking and schema validation, similar to the
|
||||
Zod library for TypeScript.
|
||||
|
||||
It integrates seamlessly with native Python [type hinting](/zk/Type_hinting.md).
|
||||
|
||||
## Basic usage
|
||||
|
||||
We define our model which must always inherit from the Pydantic `BaseModel`:
|
||||
|
||||
```py
|
||||
class User(BaseModel):
|
||||
id: int
|
||||
name: str = 'John Doe'
|
||||
signup_ts: datetime | None
|
||||
```
|
||||
|
||||
Then we validate against data:
|
||||
|
||||
```py
|
||||
external_data = {
|
||||
'id': 123,
|
||||
'signup_ts': '2019-06-01 12:22',
|
||||
}
|
||||
|
||||
user = User(**external_data)
|
||||
```
|
||||
|
||||
> Note here we can _set_ values when we define the schema, as with
|
||||
> `name: str = 'John Doe'`.
|
||||
|
||||
## Extending schemas
|
||||
|
||||
In scenarios where you have common as well as variant values between different
|
||||
schemas you can extend simply by passing the shared schema to each variant in a
|
||||
composable manner.
|
||||
|
||||
```python
|
||||
class CommonProperties(BaseModel):
|
||||
category: str
|
||||
meta_id: str
|
||||
|
||||
|
||||
class VariantProperties(CommonProperties):
|
||||
not_shared_field: int
|
||||
|
||||
```
|
||||
|
||||
> Note that the `BaseModel` must "drill-down"; it must be inherited at each
|
||||
> stage.
|
||||
|
||||
## Aliasing
|
||||
|
||||
Sometimes the incoming data that you wish to validate will have field names
|
||||
different to those that you want to use internally within your program.
|
||||
|
||||
You can use aliases to handle these values. This way, Pydantic won't error when
|
||||
it receives them, whilst also representing the data in the format that you want
|
||||
to use.
|
||||
|
||||
```py
|
||||
class IncomingRecord:
|
||||
sub_genres: Optional[str] = Field(default=None, validation_alias="subgenres")
|
||||
```
|
||||
|
||||
This schema will accept both `sub_genres` and `subgenres` as the key for the
|
||||
field but once instantiated, it will represent the field as `sub_genres`.
|
||||
|
||||
## Methods
|
||||
|
||||
You can add methods to the Pydantic schemas. These will execute whenever the
|
||||
schema is instantiated. I used a method recently to transform the data of the
|
||||
base schema into a dictionary that could be consumed by a particular API, e.g:
|
||||
|
||||
```py
|
||||
class User(BaseModel):
|
||||
id: int
|
||||
name: str
|
||||
|
||||
@property
|
||||
def to_alt_format(self):
|
||||
alternative_id: self.id,
|
||||
alternative_name: self.name
|
||||
```
|
||||
|
||||
Then:
|
||||
|
||||
```py
|
||||
raw_user_data = {"id": "1234", name: "Thomas"}
|
||||
user = User(**raw_user_data)
|
||||
print(user.to_alt_format)
|
||||
|
||||
# {"alternative_id": "1234", "name": "Thomas"}
|
||||
|
||||
```
|
||||
Loading…
Add table
Reference in a new issue