Last active
November 25, 2022 23:20
-
-
Save matheusfillipe/ca52bd8f536bfd77c0ff02ca9b708049 to your computer and use it in GitHub Desktop.
A python crash course demo for how to parse, validate, convert fields data, convert field names and serialize json/dicts using pydantic.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
from datetime import datetime, timedelta | |
from pydantic import BaseModel, Field, validator, ValidationError | |
# Random json data or something | |
person_json = { | |
"name": "John Doe", | |
"age": 30, | |
"address": { | |
"street": "Main Street", | |
"city": "New York", | |
"state": "NY", | |
"zip": "10001", | |
}, | |
"field_idc_about": "This is a field", | |
"field_idc_about2": "This is another field", | |
"phone": "123-456-7890", | |
} | |
# Pydantic model for address | |
class Address(BaseModel): | |
street: str | |
city: str | |
state: str | |
zip: str | |
# Pydantic model for person | |
class Person(BaseModel): | |
name: str | |
age: int | |
address: Address | |
phone: str | |
person = Person(**person_json) | |
print(f"{person=}") | |
print(f"{person.name=}") | |
print(f"{person.address=}") | |
print(f"{person.address.city=}") | |
print() | |
# Notice the fieds_idct_about* are not in the model | |
# Here is how you can let them be and anything else, allow extra arbitrary fields | |
class OpenPerson(Person): | |
class Config: | |
extra = "allow" # can be: allow, ignore, forbid --> meaning will let extra fields in | |
extra_fields_person = OpenPerson(**person_json) | |
print(f"{extra_fields_person=}") | |
print(f"{extra_fields_person.field_idc_about=}") # This can be unpredictable and problematic though | |
print() | |
# Example to rename fields | |
class NamePerson(BaseModel): | |
othername: str | |
otheraddress: Address | |
class Config: | |
fields = { | |
"othername": "name", # Field in object: Field in json | |
"otheraddress": "address", # Field in object: Field in json | |
} | |
renamed_field_person = NamePerson(**person_json) | |
print(f"{renamed_field_person=}") | |
print(f"{renamed_field_person.othername=}") | |
print() | |
# You can also rename using Fiel(..., alias="name") | |
class AliasPerson(BaseModel): | |
othername: str = Field(alias="name") | |
otheraddress: Address = Field(alias="address") | |
aliasperson = AliasPerson(**person_json) | |
print(f"{aliasperson=}") | |
print(f"{aliasperson.otheraddress=}") | |
# You can also use validators | |
class ValidatorPerson(BaseModel): | |
name: str | |
age: int | |
address: Address | |
phone: str | |
@validator("age") | |
def age_must_be_positive(cls, v): | |
if v < 0: | |
raise ValueError("Age must be positive") | |
return v | |
validator_person = ValidatorPerson(**person_json) | |
print(f"{validator_person=}") | |
print(f"{validator_person.age=}") | |
# You can convert objects back to dicts | |
dict_person = person.dict() | |
print(f"{dict_person=}") | |
# And then back to objects | |
try: | |
dict_person['age'] = -10 | |
person2 = ValidatorPerson(**dict_person) | |
except ValidationError as e: | |
print(e) # But the validation error is raised for negative ages | |
print() | |
# You can also convert fields using validators | |
class BirthDatePerson(BaseModel): | |
name: str | |
birthdate: datetime | |
address: Address | |
phone: str | |
@validator("birthdate", pre=True) # pre means before the field is validated with datetime type | |
def convert_birthdate(cls, v): | |
return datetime.now() - timedelta(days=v * 365) | |
class Config: | |
fields = { | |
"birthdate": "age", | |
} | |
birthdate_person = BirthDatePerson(**person_json) | |
print(f"{birthdate_person=}") | |
print(f"{birthdate_person.birthdate=}") | |
print() | |
# You can copy objects modifying fields you want | |
birthdate_person2 = birthdate_person.copy(update={"name": "Jane Doe", "birthdate": datetime.now()}) | |
print(f"{birthdate_person2=}") | |
print() | |
# You can also apply conversions and serialise to json strings | |
class ExportPerson(BaseModel): | |
name: str | |
birthdate: datetime | |
address: Address | |
phone: str | |
@validator("birthdate", pre=True) | |
def convert_birthdate(cls, v): | |
return datetime.now() - timedelta(days=v * 365) | |
class Config: | |
fields = { | |
"birthdate": "age", | |
} | |
json_encoders = { | |
datetime: lambda dt: dt.isoformat(), | |
} | |
export_person = ExportPerson(**person_json) | |
person_json = export_person.json() | |
print(f"{type(person_json)=}") | |
print(f"{person_json=}") | |
# And thousands of other things: https://pydantic-docs.helpmanual.io/ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment