Your First BaseModel
Creating models, defining fields, and instantiating validated objects.
I've been using plain dictionaries to pass data around. What's wrong with that?
Nothing — until something goes wrong. A dictionary will happily let you store {"age": "banana"} and you won't find out until your code crashes three functions later. Pydantic's BaseModel catches that the moment the data arrives:
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
email: str
user = User(name="Alice", age=30, email="alice@example.com")
print(user.name) # "Alice"
print(user.age) # 30
You declare the fields and their types. Pydantic checks everything when you create the instance. If age isn't an integer (or something that can be converted to one), it raises a ValidationError immediately.
What happens if I pass the wrong type? Like a string for age?
Pydantic is smart about it. It tries to coerce the value first. If you pass "30" for age, it converts it to 30 — that's a reasonable conversion. But if you pass "banana", there's no sensible conversion to int, so it raises an error:
# This works — "30" gets coerced to 30
user = User(name="Bob", age="30", email="bob@example.com")
print(user.age) # 30
print(type(user.age)) # <class 'int'>
# This fails — "banana" can't become an int
try:
user = User(name="Bob", age="banana", email="bob@example.com")
except Exception as e:
print(e) # validation error for age
So Pydantic models are just like regular classes but with automatic type checking?
Exactly. You can access fields with dot notation, pass models to functions, and use them anywhere you'd use a regular object. But you also get validation, serialization, and type safety for free:
class Product(BaseModel):
name: str
price: float
in_stock: bool
item = Product(name="Widget", price=9.99, in_stock=True)
print(f"{item.name}: ${item.price}") # "Widget: $9.99"
Every field is validated on creation. You define the shape of your data once, and Pydantic enforces it everywhere.
Can I create a model from a dictionary? Like if I'm getting JSON from an API?
Yes — use the double-star ** unpacking syntax. If you have a dictionary with the right keys, it works directly:
data = {"name": "Widget", "price": 9.99, "in_stock": True}
item = Product(**data)
print(item.name) # "Widget"
Or use model_validate() which does the same thing:
item = Product.model_validate(data)
This is the pattern you'll use constantly — data comes in as a dictionary (from JSON, a database row, a form submission), you validate it through a model, and from that point on you have a clean, typed object.
Practice your skills
Sign up to write and run code in this lesson.
Your First BaseModel
Creating models, defining fields, and instantiating validated objects.
I've been using plain dictionaries to pass data around. What's wrong with that?
Nothing — until something goes wrong. A dictionary will happily let you store {"age": "banana"} and you won't find out until your code crashes three functions later. Pydantic's BaseModel catches that the moment the data arrives:
from pydantic import BaseModel
class User(BaseModel):
name: str
age: int
email: str
user = User(name="Alice", age=30, email="alice@example.com")
print(user.name) # "Alice"
print(user.age) # 30
You declare the fields and their types. Pydantic checks everything when you create the instance. If age isn't an integer (or something that can be converted to one), it raises a ValidationError immediately.
What happens if I pass the wrong type? Like a string for age?
Pydantic is smart about it. It tries to coerce the value first. If you pass "30" for age, it converts it to 30 — that's a reasonable conversion. But if you pass "banana", there's no sensible conversion to int, so it raises an error:
# This works — "30" gets coerced to 30
user = User(name="Bob", age="30", email="bob@example.com")
print(user.age) # 30
print(type(user.age)) # <class 'int'>
# This fails — "banana" can't become an int
try:
user = User(name="Bob", age="banana", email="bob@example.com")
except Exception as e:
print(e) # validation error for age
So Pydantic models are just like regular classes but with automatic type checking?
Exactly. You can access fields with dot notation, pass models to functions, and use them anywhere you'd use a regular object. But you also get validation, serialization, and type safety for free:
class Product(BaseModel):
name: str
price: float
in_stock: bool
item = Product(name="Widget", price=9.99, in_stock=True)
print(f"{item.name}: ${item.price}") # "Widget: $9.99"
Every field is validated on creation. You define the shape of your data once, and Pydantic enforces it everywhere.
Can I create a model from a dictionary? Like if I'm getting JSON from an API?
Yes — use the double-star ** unpacking syntax. If you have a dictionary with the right keys, it works directly:
data = {"name": "Widget", "price": 9.99, "in_stock": True}
item = Product(**data)
print(item.name) # "Widget"
Or use model_validate() which does the same thing:
item = Product.model_validate(data)
This is the pattern you'll use constantly — data comes in as a dictionary (from JSON, a database row, a form submission), you validate it through a model, and from that point on you have a clean, typed object.
Practice your skills
Sign up to write and run code in this lesson.