Pydantic V2 Field Validator Equivalent to Values Argument: Accessing Other Fields
In Pydantic V2, the values argument from V1's @validator is replaced by the info.data attribute of the ValidationInfo object passed to @field_validator methods.
When migrating FastAPI applications from Pydantic V1 to V2, developers must update their validation logic to accommodate the removal of the values parameter. The fastapi/fastapi repository implements this transition through the ValidationInfo pattern, providing equivalent functionality for cross-field validation while maintaining type safety and performance.
Understanding the Migration from values to info.data
In Pydantic V1, the @validator decorator exposed a values dictionary containing already-validated field values:
@validator("age")
def check_age(cls, v, values):
if v < values.get("birth_year", 0):
raise ValueError("age must be greater than birth_year")
Pydantic V2 eliminates the values parameter entirely. The new @field_validator decorator instead supplies a ValidationInfo object (conventionally named info) as the second parameter. This object contains an attribute info.data, which is a dictionary mapping field names to their validated values.
The ValidationInfo Object Structure
The ValidationInfo object exposes info.data, a dictionary containing values that have been validated up to that point. When using mode="after", this dictionary contains the complete model state after field assignment. FastAPI's compatibility layer forwards this information through fastapi._compat.v2.with_info_plain_validator_function, ensuring consistent behavior across Pydantic versions.
Implementing Cross-Field Validation in Pydantic V2
To validate one field against another using the Pydantic V2 equivalent of the values argument, import ValidationInfo and access info.data within your validator:
from pydantic import BaseModel, ValidationInfo, field_validator
class Item(BaseModel):
price: float
discount: float
@field_validator("discount", mode="after")
@classmethod
def discount_must_be_less_than_price(
cls, v: float, info: ValidationInfo
) -> float:
# `info.data` holds the already-validated fields, i.e. {"price": …, "discount": …}
if v > info.data["price"]:
raise ValueError("discount cannot exceed price")
return v
In this example, info.data["price"] provides the same functionality as the deprecated values["price"] from Pydantic V1.
Using FastAPI's Compatibility Wrapper
FastAPI maintains internal compatibility through utilities defined in fastapi/_compat/v2.py. The with_info_plain_validator_function decorator ensures ValidationInfo propagates correctly through FastAPI's validation pipeline:
from fastapi import FastAPI
from fastapi._compat.v2 import with_info_plain_validator_function
from pydantic import BaseModel, ValidationInfo, field_validator
class User(BaseModel):
username: str
password: str
@field_validator("password", mode="before")
@classmethod
@with_info_plain_validator_function
def hash_password(cls, v: str, info: ValidationInfo) -> str:
# `info.data` contains {"username": …, "password": …}
return hash_function(v) # replace with real hashing
This pattern appears throughout FastAPI's codebase, including in fastapi/openapi/models.py, demonstrating how the framework handles Pydantic V2 validation internally.
Using model_validator for Complex Scenarios
For validations requiring simultaneous access to multiple fields, Pydantic V2 introduces @model_validator. While @field_validator operates on individual fields, @model_validator receives the complete model state:
from pydantic import BaseModel, ValidationInfo, model_validator
class Config(BaseModel):
host: str
port: int
@model_validator(mode="after")
@classmethod
def check_host_and_port(cls, info: ValidationInfo) -> "Config":
data = info.data
if data["host"] == "localhost" and data["port"] != 8000:
raise ValueError("localhost must use port 8000")
return cls(**data)
Before vs After Validation Modes
mode="before": Runs validation on raw input before Pydantic performs type coercion. Theinfo.datadictionary contains pre-validation values.mode="after": Runs validation after field assignment and type coercion. Theinfo.datadictionary contains transformed Python objects.
How FastAPI Handles the Compatibility Layer
The transition from values to info.data is managed internally by FastAPI through specific compatibility utilities. The file fastapi/_compat/v2.py defines with_info_plain_validator_function, which wraps validator functions to inject ValidationInfo objects correctly.
Test implementations in tests/test_filter_pydantic_sub_model_pv2.py demonstrate practical applications of field_validator with info.data, providing reference implementations for complex validation scenarios. These tests verify that FastAPI models correctly pass field context through the Pydantic V2 validation pipeline.
Summary
- Pydantic V2 replaces the
valuesargument withinfo.datafrom theValidationInfoobject in@field_validatormethods. - Import
ValidationInfofrompydanticand accept it as the second parameter in validator functions to access other fields. - FastAPI provides
with_info_plain_validator_functioninfastapi/_compat/v2.pyfor framework-specific validation wrapping. - Use
@model_validatorwhen validation logic spans multiple fields simultaneously. - Reference implementations exist in
tests/test_filter_pydantic_sub_model_pv2.pyandfastapi/openapi/models.py.
Frequently Asked Questions
What replaced the values argument in Pydantic V2?
The values dictionary from Pydantic V1's @validator has been replaced by info.data in Pydantic V2's @field_validator. The ValidationInfo object, passed as the second argument to validator functions, contains the data attribute which provides access to other validated fields during the validation process.
How do I import ValidationInfo in Pydantic V2?
Import ValidationInfo directly from the pydantic module: from pydantic import ValidationInfo. Pass it as a parameter to your @field_validator decorated method alongside the field value being validated. The object is automatically populated by Pydantic's validation engine.
What is the difference between mode="before" and mode="after" in field_validator?
mode="before" runs validation on raw input data before Pydantic performs type coercion, allowing you to transform or validate the original input values. mode="after" runs validation after the field has been converted to its declared Python type. When accessing info.data, "after" mode provides already-transformed values, whereas "before" mode may contain raw, uncoerced input.
Does FastAPI require special handling for Pydantic V2 validators?
FastAPI automatically handles Pydantic V2 validators through its internal compatibility layer defined in fastapi/_compat/v2.py. The with_info_plain_validator_function decorator ensures ValidationInfo objects propagate correctly through FastAPI's dependency injection and validation systems, maintaining compatibility with both Pydantic V1 and V2.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →