Skip to content

Instantly share code, notes, and snippets.

@matheusfillipe
Last active November 25, 2022 23:20
Show Gist options
  • Save matheusfillipe/ca52bd8f536bfd77c0ff02ca9b708049 to your computer and use it in GitHub Desktop.
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.
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