FastAPI Pydantic Models
What are Pydantic models in FastAPI?
Pydantic models in FastAPI are Python classes that define the structure and types of data you expect in your application. FastAPI uses Pydantic models to validate request bodies, query parameters, and responses automatically, ensuring that the data conforms to the expected types. Pydantic models use Python type annotations to specify data types, making data validation intuitive and easy to use.
How do you define a basic Pydantic model in FastAPI?
To define a basic Pydantic model in FastAPI, you create a class that inherits from Pydantic's BaseModel. Each attribute in the model is a field, and its type is defined using Python type annotations. This model can then be used in your FastAPI route for request body validation.
Example of a basic Pydantic model:
from fastapi import FastAPI
from pydantic import BaseModel
app = FastAPI()
class Item(BaseModel):
name: str
price: float
@app.post("/items/")
def create_item(item: Item):
return item
In this example, the Item model has two fields: name (a string) and price (a float). The route /items/ accepts POST requests with a JSON body that matches the Item model. FastAPI automatically validates the request data.
How do you use Pydantic models for query parameters in FastAPI?
In FastAPI, you can use Pydantic models to validate complex query parameters. This is useful when you need to validate a group of related parameters, such as filtering or sorting criteria, and ensure that they follow the correct format.
Example of using Pydantic models for query parameters:
from typing import Optional
from pydantic import BaseModel
class QueryParams(BaseModel):
q: Optional[str]
limit: int = 10
offset: int = 0
@app.get("/items/")
def read_items(params: QueryParams = Depends()):
return {"q": params.q, "limit": params.limit, "offset": params.offset}
In this example, the QueryParams model defines three query parameters: q (an optional string), limit (an integer with a default value of 10), and offset (an integer with a default value of 0). FastAPI automatically validates the query parameters based on this model.
How do you handle optional fields in Pydantic models in FastAPI?
Pydantic models in FastAPI support optional fields using the Optional type from the typing module. You can define a field as optional by annotating it with Optional and providing a default value (typically None).
Example of handling optional fields:
from typing import Optional
from pydantic import BaseModel
class Item(BaseModel):
name: str
description: Optional[str] = None
price: float
@app.post("/items/")
def create_item(item: Item):
return item
In this example, the description field is optional, meaning it can be either a string or None. If the client does not provide a value for description, it defaults to None.
How do you use nested Pydantic models in FastAPI?
Pydantic models in FastAPI can be nested, meaning one model can contain another model as a field. This is useful for handling complex JSON objects that contain hierarchical data.
Example of using nested Pydantic models:
from pydantic import BaseModel
class Address(BaseModel):
street: str
city: str
class User(BaseModel):
username: str
address: Address
@app.post("/users/")
def create_user(user: User):
return user
In this example, the User model contains an Address model as a nested field. FastAPI will validate both the username and the nested address fields when handling the request.
How do you use list fields in Pydantic models in FastAPI?
Pydantic models in FastAPI can handle list fields, where the model expects a list of elements of a specific type. You can define a list field using the List type from Python's typing module.
Example of using list fields:
from typing import List
from pydantic import BaseModel
class Item(BaseModel):
name: str
tags: List[str]
@app.post("/items/")
def create_item(item: Item):
return item
In this example, the tags field is a list of strings. FastAPI validates that the tags field in the request body contains a list, and each item in the list is a string.
How do you handle default values in Pydantic models in FastAPI?
Pydantic models in FastAPI allow you to specify default values for fields. If a field is not provided in the request, the default value will be used.
Example of handling default values:
class Item(BaseModel):
name: str
price: float = 0.0
@app.post("/items/")
def create_item(item: Item):
return item
In this example, the price field has a default value of 0.0. If the client does not provide a value for price, the default value will be used in the response.
How do you perform custom validation in Pydantic models in FastAPI?
Pydantic allows you to define custom validation logic using class methods. You can use the @validator decorator to create custom validation rules for individual fields or the entire model.
Example of custom validation in Pydantic models:
from pydantic import BaseModel, validator
class Item(BaseModel):
name: str
price: float
@validator("price")
def price_must_be_positive(cls, v):
if v <= 0:
raise ValueError("Price must be greater than zero")
return v
@app.post("/items/")
def create_item(item: Item):
return item
In this example, the price_must_be_positive validator ensures that the price field is greater than zero. If the validation fails, a ValueError is raised.
How do you exclude fields from Pydantic models in FastAPI responses?
Pydantic allows you to exclude certain fields from the response using the response_model argument in FastAPI. This is useful if you want to return a subset of the fields in the model.
Example of excluding fields from responses:
class Item(BaseModel):
name: str
price: float
secret_code: str
@app.post("/items/", response_model=Item)
def create_item(item: Item):
return item.dict(exclude={"secret_code"})
In this example, the secret_code field is excluded from the response by using the exclude argument when returning the item model.
How do you use the response_model in FastAPI routes?
In FastAPI, you can specify a response_model in the route definition to control the shape of the data returned in the response. FastAPI will validate the response and ensure that it matches the specified Pydantic model.
Example of using response_model:
class Item(BaseModel):
name: str
price: float
@app.get("/items/{item_id}", response_model=Item)
def read_item(item_id: int):
return {"name": "Sample Item", "price": 10.99, "extra_field": "This will be excluded"}
In this example, the response model is set to Item, meaning only the name and price fields will be included in the response. Any extra fields, such as extra_field, will be excluded.