[{"data":1,"prerenderedAt":1565},["ShallowReactive",2],{"nav":3,"page-\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002F":152,"surround-\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002F":1563},[4,72],{"title":5,"path":6,"stem":7,"children":8},"Advanced Pydantic Validation Serialization","\u002Fadvanced-pydantic-validation-serialization","advanced-pydantic-validation-serialization",[9,12,24,36,48,54,66],{"title":10,"path":6,"stem":11},"Advanced Pydantic Validation & Serialization","advanced-pydantic-validation-serialization\u002Findex",{"title":13,"path":14,"stem":15,"children":16},"Custom Validators & Field Constraints in FastAPI & Pydantic V2","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Findex",[17,18],{"title":13,"path":14,"stem":15},{"title":19,"path":20,"stem":21,"children":22},"Creating Reusable Custom Validators in Pydantic: Production Patterns","\u002Fadvanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic","advanced-pydantic-validation-serialization\u002Fcustom-validators-field-constraints\u002Fcreating-reusable-custom-validators-in-pydantic\u002Findex",[23],{"title":19,"path":20,"stem":21},{"title":25,"path":26,"stem":27,"children":28},"JSON Schema Customization","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Findex",[29,30],{"title":25,"path":26,"stem":27},{"title":31,"path":32,"stem":33,"children":34},"Customizing OpenAPI Schema Generation in FastAPI: Production Implementation Guide","\u002Fadvanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi","advanced-pydantic-validation-serialization\u002Fjson-schema-customization\u002Fcustomizing-openapi-schema-generation-in-fastapi\u002Findex",[35],{"title":31,"path":32,"stem":33},{"title":37,"path":38,"stem":39,"children":40},"Mastering Nested Model Serialization in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Findex",[41,42],{"title":37,"path":38,"stem":39},{"title":43,"path":44,"stem":45,"children":46},"Handling Deeply Nested JSON Models Efficiently in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently","advanced-pydantic-validation-serialization\u002Fnested-model-serialization\u002Fhandling-deeply-nested-json-models-efficiently\u002Findex",[47],{"title":43,"path":44,"stem":45},{"title":49,"path":50,"stem":51,"children":52},"Performance Optimization for Models in FastAPI","\u002Fadvanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models","advanced-pydantic-validation-serialization\u002Fperformance-optimization-for-models\u002Findex",[53],{"title":49,"path":50,"stem":51},{"title":55,"path":56,"stem":57,"children":58},"Pydantic V2 Migration Guide: FastAPI Production Patterns","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Findex",[59,60],{"title":55,"path":56,"stem":57},{"title":61,"path":62,"stem":63,"children":64},"Migrating from Pydantic v1 to v2 without breaking APIs","\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis","advanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex",[65],{"title":61,"path":62,"stem":63},{"title":67,"path":68,"stem":69,"children":70},"Type Hinting & IDE Integration in FastAPI: Advanced Pydantic Patterns","\u002Fadvanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration","advanced-pydantic-validation-serialization\u002Ftype-hinting-ide-integration\u002Findex",[71],{"title":67,"path":68,"stem":69},{"title":73,"path":74,"stem":75,"children":76},"Core Architecture Routing Patterns","\u002Fcore-architecture-routing-patterns","core-architecture-routing-patterns",[77,80,92,104,116,128,140],{"title":78,"path":74,"stem":79},"Core Architecture & Routing Patterns in FastAPI: A Production-Ready Blueprint","core-architecture-routing-patterns\u002Findex",{"title":81,"path":82,"stem":83,"children":84},"Application Factory Patterns in FastAPI: Production Architecture Guide","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Findex",[85,86],{"title":81,"path":82,"stem":83},{"title":87,"path":88,"stem":89,"children":90},"FastAPI App Factory Pattern for Testing and Deployment: Production Guide","\u002Fcore-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment","core-architecture-routing-patterns\u002Fapplication-factory-patterns\u002Ffastapi-app-factory-pattern-for-testing-and-deployment\u002Findex",[91],{"title":87,"path":88,"stem":89},{"title":93,"path":94,"stem":95,"children":96},"Configuration Management in FastAPI: Production-Ready Patterns & Security","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management","core-architecture-routing-patterns\u002Fconfiguration-management\u002Findex",[97,98],{"title":93,"path":94,"stem":95},{"title":99,"path":100,"stem":101,"children":102},"Managing Environment Variables with Pydantic Settings in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings","core-architecture-routing-patterns\u002Fconfiguration-management\u002Fmanaging-environment-variables-with-pydantic-settings\u002Findex",[103],{"title":99,"path":100,"stem":101},{"title":105,"path":106,"stem":107,"children":108},"Dependency Injection Strategies","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Findex",[109,110],{"title":105,"path":106,"stem":107},{"title":111,"path":112,"stem":113,"children":114},"Best Practices for FastAPI Dependency Injection","\u002Fcore-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection","core-architecture-routing-patterns\u002Fdependency-injection-strategies\u002Fbest-practices-for-fastapi-dependency-injection\u002Findex",[115],{"title":111,"path":112,"stem":113},{"title":117,"path":118,"stem":119,"children":120},"Error Handling & Global Exceptions in FastAPI","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Findex",[121,122],{"title":117,"path":118,"stem":119},{"title":123,"path":124,"stem":125,"children":126},"Global Exception Handlers for Consistent API Responses","\u002Fcore-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses","core-architecture-routing-patterns\u002Ferror-handling-global-exceptions\u002Fglobal-exception-handlers-for-consistent-api-responses\u002Findex",[127],{"title":123,"path":124,"stem":125},{"title":129,"path":130,"stem":131,"children":132},"Middleware Implementation","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Findex",[133,134],{"title":129,"path":130,"stem":131},{"title":135,"path":136,"stem":137,"children":138},"Implementing Custom Middleware for Request Tracing in FastAPI","\u002Fcore-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing","core-architecture-routing-patterns\u002Fmiddleware-implementation\u002Fimplementing-custom-middleware-for-request-tracing\u002Findex",[139],{"title":135,"path":136,"stem":137},{"title":141,"path":142,"stem":143,"children":144},"Modular Router Organization in FastAPI: Production-Grade Architecture","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Findex",[145,146],{"title":141,"path":142,"stem":143},{"title":147,"path":148,"stem":149,"children":150},"How to Structure Large FastAPI Projects for Scale","\u002Fcore-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale","core-architecture-routing-patterns\u002Fmodular-router-organization\u002Fhow-to-structure-large-fastapi-projects-for-scale\u002Findex",[151],{"title":147,"path":148,"stem":149},{"id":153,"title":61,"body":154,"description":1558,"extension":1559,"meta":1560,"navigation":353,"path":62,"seo":1561,"stem":63,"__hash__":1562},"content\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002Fmigrating-from-pydantic-v1-to-v2-without-breaking-apis\u002Findex.md",{"type":155,"value":156,"toc":1550},"minimark",[157,161,175,181,218,221,226,229,234,270,541,543,547,558,563,610,885,887,891,897,902,940,1128,1130,1134,1137,1142,1185,1353,1355,1359,1482,1484,1488,1493,1502,1507,1530,1535,1546],[158,159,61],"h1",{"id":160},"migrating-from-pydantic-v1-to-v2-without-breaking-apis",[162,163,164,165,169,170,174],"p",{},"Upgrading to Pydantic v2 introduces breaking changes in validation, serialization, and schema generation that can silently corrupt API contracts. This guide provides immediate implementation steps, configuration overrides, and debugging workflows to ensure zero-downtime transitions. For foundational architecture patterns, consult the ",[166,167,10],"a",{"href":168},"\u002Fadvanced-pydantic-validation-serialization\u002F"," pillar, and follow the phased rollout strategies detailed in the ",[166,171,173],{"href":172},"\u002Fadvanced-pydantic-validation-serialization\u002Fpydantic-v2-migration-guide\u002F","Pydantic V2 Migration Guide",".",[162,176,177],{},[178,179,180],"strong",{},"Core Migration Objectives:",[182,183,184,193,208,215],"ul",{},[185,186,187,188,192],"li",{},"Leverage the ",[189,190,191],"code",{},"pydantic.v1"," compatibility namespace for incremental refactoring",[185,194,195,196,199,200,203,204,207],{},"Replace ",[189,197,198],{},"@validator"," with ",[189,201,202],{},"@field_validator"," and ",[189,205,206],{},"@model_validator"," while preserving input\u002Foutput signatures",[185,209,210,211,214],{},"Configure ",[189,212,213],{},"model_config"," to enforce strict typing and legacy serialization formats",[185,216,217],{},"Automate OpenAPI schema diffing to catch contract drift before deployment",[219,220],"hr",{},[222,223,225],"h2",{"id":224},"phase-1-compatibility-layer-dependency-pinning","Phase 1: Compatibility Layer & Dependency Pinning",[162,227,228],{},"Establish a safe baseline by isolating v1 and v2 imports to prevent namespace collisions during the transition. Pin dependencies explicitly to avoid transitive resolution conflicts in CI\u002FCD pipelines.",[162,230,231],{},[178,232,233],{},"Production Constraints:",[182,235,236,253,260,267],{},[185,237,238,239,203,242,245,246,249,250],{},"Pin ",[189,240,241],{},"pydantic>=2.0,\u003C3.0",[189,243,244],{},"pydantic-core"," in ",[189,247,248],{},"requirements.txt"," or ",[189,251,252],{},"pyproject.toml",[185,254,255,256,259],{},"Use ",[189,257,258],{},"from pydantic.v1 import BaseModel"," exclusively for legacy FastAPI routes",[185,261,262,263,266],{},"Run ",[189,264,265],{},"pydantic-settings"," compatibility checks to prevent environment variable parsing regressions",[185,268,269],{},"Implement route-level feature flags to toggle v2 validation incrementally",[271,272,277],"pre",{"className":273,"code":274,"language":275,"meta":276,"style":276},"language-python shiki shiki-themes github-light","# requirements.txt\npydantic>=2.0,\u003C3.0\npydantic-core>=2.0,\u003C3.0\npydantic-settings>=2.0\n\n# app\u002Fmodels\u002Flegacy.py (v1 compatibility layer)\nfrom pydantic.v1 import BaseModel, Field, validator\n\nclass LegacyUser(BaseModel):\n id: int\n username: str\n\n# app\u002Fmodels\u002Fv2.py (new implementation)\nfrom pydantic import BaseModel, Field, field_validator\n\nclass ModernUser(BaseModel):\n id: int\n username: str\n\n @field_validator(\"username\")\n @classmethod\n def normalize_username(cls, v: str) -> str:\n return v.strip().lower()\n","python","",[189,278,279,288,312,333,348,355,361,376,381,400,412,421,426,432,445,450,464,473,480,485,500,509,532],{"__ignoreMap":276},[280,281,284],"span",{"class":282,"line":283},"line",1,[280,285,287],{"class":286},"sAwPA","# requirements.txt\n",[280,289,291,295,299,303,306,309],{"class":282,"line":290},2,[280,292,294],{"class":293},"sgsFI","pydantic",[280,296,298],{"class":297},"sD7c4",">=",[280,300,302],{"class":301},"sYu0t","2.0",[280,304,305],{"class":293},",",[280,307,308],{"class":297},"\u003C",[280,310,311],{"class":301},"3.0\n",[280,313,315,317,320,323,325,327,329,331],{"class":282,"line":314},3,[280,316,294],{"class":293},[280,318,319],{"class":297},"-",[280,321,322],{"class":293},"core",[280,324,298],{"class":297},[280,326,302],{"class":301},[280,328,305],{"class":293},[280,330,308],{"class":297},[280,332,311],{"class":301},[280,334,336,338,340,343,345],{"class":282,"line":335},4,[280,337,294],{"class":293},[280,339,319],{"class":297},[280,341,342],{"class":293},"settings",[280,344,298],{"class":297},[280,346,347],{"class":301},"2.0\n",[280,349,351],{"class":282,"line":350},5,[280,352,354],{"emptyLinePlaceholder":353},true,"\n",[280,356,358],{"class":282,"line":357},6,[280,359,360],{"class":286},"# app\u002Fmodels\u002Flegacy.py (v1 compatibility layer)\n",[280,362,364,367,370,373],{"class":282,"line":363},7,[280,365,366],{"class":297},"from",[280,368,369],{"class":293}," pydantic.v1 ",[280,371,372],{"class":297},"import",[280,374,375],{"class":293}," BaseModel, Field, validator\n",[280,377,379],{"class":282,"line":378},8,[280,380,354],{"emptyLinePlaceholder":353},[280,382,384,387,391,394,397],{"class":282,"line":383},9,[280,385,386],{"class":297},"class",[280,388,390],{"class":389},"s7eDp"," LegacyUser",[280,392,393],{"class":293},"(",[280,395,396],{"class":389},"BaseModel",[280,398,399],{"class":293},"):\n",[280,401,403,406,409],{"class":282,"line":402},10,[280,404,405],{"class":301}," id",[280,407,408],{"class":293},": ",[280,410,411],{"class":301},"int\n",[280,413,415,418],{"class":282,"line":414},11,[280,416,417],{"class":293}," username: ",[280,419,420],{"class":301},"str\n",[280,422,424],{"class":282,"line":423},12,[280,425,354],{"emptyLinePlaceholder":353},[280,427,429],{"class":282,"line":428},13,[280,430,431],{"class":286},"# app\u002Fmodels\u002Fv2.py (new implementation)\n",[280,433,435,437,440,442],{"class":282,"line":434},14,[280,436,366],{"class":297},[280,438,439],{"class":293}," pydantic ",[280,441,372],{"class":297},[280,443,444],{"class":293}," BaseModel, Field, field_validator\n",[280,446,448],{"class":282,"line":447},15,[280,449,354],{"emptyLinePlaceholder":353},[280,451,453,455,458,460,462],{"class":282,"line":452},16,[280,454,386],{"class":297},[280,456,457],{"class":389}," ModernUser",[280,459,393],{"class":293},[280,461,396],{"class":389},[280,463,399],{"class":293},[280,465,467,469,471],{"class":282,"line":466},17,[280,468,405],{"class":301},[280,470,408],{"class":293},[280,472,411],{"class":301},[280,474,476,478],{"class":282,"line":475},18,[280,477,417],{"class":293},[280,479,420],{"class":301},[280,481,483],{"class":282,"line":482},19,[280,484,354],{"emptyLinePlaceholder":353},[280,486,488,491,493,497],{"class":282,"line":487},20,[280,489,490],{"class":389}," @field_validator",[280,492,393],{"class":293},[280,494,496],{"class":495},"sYBdl","\"username\"",[280,498,499],{"class":293},")\n",[280,501,503,506],{"class":282,"line":502},21,[280,504,505],{"class":389}," @",[280,507,508],{"class":301},"classmethod\n",[280,510,512,515,518,521,524,527,529],{"class":282,"line":511},22,[280,513,514],{"class":297}," def",[280,516,517],{"class":389}," normalize_username",[280,519,520],{"class":293},"(cls, v: ",[280,522,523],{"class":301},"str",[280,525,526],{"class":293},") -> ",[280,528,523],{"class":301},[280,530,531],{"class":293},":\n",[280,533,535,538],{"class":282,"line":534},23,[280,536,537],{"class":297}," return",[280,539,540],{"class":293}," v.strip().lower()\n",[219,542],{},[222,544,546],{"id":545},"phase-2-refactoring-validators-field-constraints","Phase 2: Refactoring Validators & Field Constraints",[162,548,549,550,553,554,557],{},"Translate deprecated validation decorators to v2 syntax while maintaining identical error payloads and HTTP ",[189,551,552],{},"422 Unprocessable Entity"," responses. FastAPI relies on Pydantic's ",[189,555,556],{},"ValidationError"," structure to format these responses automatically.",[162,559,560],{},[178,561,562],{},"Key Translation Rules:",[182,564,565,580,589,603],{},[185,566,567,568,570,571,573,574,249,577],{},"Map ",[189,569,198],{}," to ",[189,572,202],{}," with explicit ",[189,575,576],{},"mode='before'",[189,578,579],{},"mode='after'",[185,581,582,583,570,586],{},"Update ",[189,584,585],{},"@root_validator",[189,587,588],{},"@model_validator(mode='before')",[185,590,591,592,595,596,599,600],{},"Replace the ",[189,593,594],{},"values"," dict with ",[189,597,598],{},"info.data"," via ",[189,601,602],{},"ValidationInfo",[185,604,605,606,609],{},"Preserve custom error formatting using ",[189,607,608],{},"PydanticCustomError"," for strict contract enforcement",[271,611,613],{"className":273,"code":612,"language":275,"meta":276,"style":276},"from pydantic import BaseModel, field_validator, ValidationError, ValidationInfo\n\nclass UserUpdate(BaseModel):\n email: str\n age: int\n\n @field_validator(\"email\")\n @classmethod\n def validate_email(cls, v: str) -> str:\n if \"@\" not in v:\n raise ValueError(\"Invalid email format\")\n return v.lower()\n\n @field_validator(\"age\", mode=\"before\")\n @classmethod\n def coerce_age(cls, v: str | int) -> int:\n return int(v)\n\n @classmethod\n def validate_model(cls, values: dict, info: ValidationInfo) -> dict:\n # Replaces @root_validator(pre=True)\n if values.get(\"email\") and values.get(\"age\") \u003C 18:\n raise ValueError(\"Minors cannot register\")\n return values\n",[189,614,615,626,630,643,650,657,661,672,678,695,712,727,734,738,762,768,792,801,805,811,831,836,864,877],{"__ignoreMap":276},[280,616,617,619,621,623],{"class":282,"line":283},[280,618,366],{"class":297},[280,620,439],{"class":293},[280,622,372],{"class":297},[280,624,625],{"class":293}," BaseModel, field_validator, ValidationError, ValidationInfo\n",[280,627,628],{"class":282,"line":290},[280,629,354],{"emptyLinePlaceholder":353},[280,631,632,634,637,639,641],{"class":282,"line":314},[280,633,386],{"class":297},[280,635,636],{"class":389}," UserUpdate",[280,638,393],{"class":293},[280,640,396],{"class":389},[280,642,399],{"class":293},[280,644,645,648],{"class":282,"line":335},[280,646,647],{"class":293}," email: ",[280,649,420],{"class":301},[280,651,652,655],{"class":282,"line":350},[280,653,654],{"class":293}," age: ",[280,656,411],{"class":301},[280,658,659],{"class":282,"line":357},[280,660,354],{"emptyLinePlaceholder":353},[280,662,663,665,667,670],{"class":282,"line":363},[280,664,490],{"class":389},[280,666,393],{"class":293},[280,668,669],{"class":495},"\"email\"",[280,671,499],{"class":293},[280,673,674,676],{"class":282,"line":378},[280,675,505],{"class":389},[280,677,508],{"class":301},[280,679,680,682,685,687,689,691,693],{"class":282,"line":383},[280,681,514],{"class":297},[280,683,684],{"class":389}," validate_email",[280,686,520],{"class":293},[280,688,523],{"class":301},[280,690,526],{"class":293},[280,692,523],{"class":301},[280,694,531],{"class":293},[280,696,697,700,703,706,709],{"class":282,"line":402},[280,698,699],{"class":297}," if",[280,701,702],{"class":495}," \"@\"",[280,704,705],{"class":297}," not",[280,707,708],{"class":297}," in",[280,710,711],{"class":293}," v:\n",[280,713,714,717,720,722,725],{"class":282,"line":414},[280,715,716],{"class":297}," raise",[280,718,719],{"class":301}," ValueError",[280,721,393],{"class":293},[280,723,724],{"class":495},"\"Invalid email format\"",[280,726,499],{"class":293},[280,728,729,731],{"class":282,"line":423},[280,730,537],{"class":297},[280,732,733],{"class":293}," v.lower()\n",[280,735,736],{"class":282,"line":428},[280,737,354],{"emptyLinePlaceholder":353},[280,739,740,742,744,747,750,754,757,760],{"class":282,"line":434},[280,741,490],{"class":389},[280,743,393],{"class":293},[280,745,746],{"class":495},"\"age\"",[280,748,749],{"class":293},", ",[280,751,753],{"class":752},"sqxcx","mode",[280,755,756],{"class":297},"=",[280,758,759],{"class":495},"\"before\"",[280,761,499],{"class":293},[280,763,764,766],{"class":282,"line":447},[280,765,505],{"class":389},[280,767,508],{"class":301},[280,769,770,772,775,777,779,782,785,787,790],{"class":282,"line":452},[280,771,514],{"class":297},[280,773,774],{"class":389}," coerce_age",[280,776,520],{"class":293},[280,778,523],{"class":301},[280,780,781],{"class":297}," |",[280,783,784],{"class":301}," int",[280,786,526],{"class":293},[280,788,789],{"class":301},"int",[280,791,531],{"class":293},[280,793,794,796,798],{"class":282,"line":466},[280,795,537],{"class":297},[280,797,784],{"class":301},[280,799,800],{"class":293},"(v)\n",[280,802,803],{"class":282,"line":475},[280,804,354],{"emptyLinePlaceholder":353},[280,806,807,809],{"class":282,"line":482},[280,808,505],{"class":389},[280,810,508],{"class":301},[280,812,813,815,818,821,824,827,829],{"class":282,"line":487},[280,814,514],{"class":297},[280,816,817],{"class":389}," validate_model",[280,819,820],{"class":293},"(cls, values: ",[280,822,823],{"class":301},"dict",[280,825,826],{"class":293},", info: ValidationInfo) -> ",[280,828,823],{"class":301},[280,830,531],{"class":293},[280,832,833],{"class":282,"line":502},[280,834,835],{"class":286}," # Replaces @root_validator(pre=True)\n",[280,837,838,840,843,845,848,851,853,855,857,859,862],{"class":282,"line":511},[280,839,699],{"class":297},[280,841,842],{"class":293}," values.get(",[280,844,669],{"class":495},[280,846,847],{"class":293},") ",[280,849,850],{"class":297},"and",[280,852,842],{"class":293},[280,854,746],{"class":495},[280,856,847],{"class":293},[280,858,308],{"class":297},[280,860,861],{"class":301}," 18",[280,863,531],{"class":293},[280,865,866,868,870,872,875],{"class":282,"line":534},[280,867,716],{"class":297},[280,869,719],{"class":301},[280,871,393],{"class":293},[280,873,874],{"class":495},"\"Minors cannot register\"",[280,876,499],{"class":293},[280,878,880,882],{"class":282,"line":879},24,[280,881,537],{"class":297},[280,883,884],{"class":293}," values\n",[219,886],{},[222,888,890],{"id":889},"phase-3-configuration-overrides-for-backward-compatibility","Phase 3: Configuration Overrides for Backward Compatibility",[162,892,893,894,896],{},"Apply ",[189,895,213],{}," directives to replicate v1 serialization behavior, preventing silent data truncation or type coercion. Pydantic v2 defaults to stricter parsing in several contexts, which can break legacy frontend clients expecting implicit type casting.",[162,898,899],{},[178,900,901],{},"Configuration Directives:",[182,903,904,918,924,930],{},[185,905,906,907,910,911,914,915,917],{},"Set ",[189,908,909],{},"strict=True"," to reject implicit type conversions (e.g., ",[189,912,913],{},"\"123\""," → ",[189,916,789],{},")",[185,919,210,920,923],{},[189,921,922],{},"extra='forbid'"," to match v1 default behavior and prevent payload bloat",[185,925,255,926,929],{},[189,927,928],{},"populate_by_name=True"," for alias resolution parity across nested models",[185,931,932,933,199,936,939],{},"Override legacy ",[189,934,935],{},"json_encoders",[189,937,938],{},"@field_serializer"," for deterministic datetime\u002FUUID formatting",[271,941,943],{"className":273,"code":942,"language":275,"meta":276,"style":276},"from pydantic import BaseModel, ConfigDict, field_serializer\nfrom datetime import datetime\n\nclass LegacyPayload(BaseModel):\n model_config = ConfigDict(\n strict=True,\n extra=\"forbid\",\n populate_by_name=True,\n json_schema_extra={\"example\": {\"created_at\": \"2023-01-01T00:00:00Z\"}}\n )\n created_at: datetime\n metadata: dict = {}\n\n @field_serializer(\"created_at\")\n def serialize_dt(self, dt: datetime) -> str:\n return dt.strftime(\"%Y-%m-%dT%H:%M:%SZ\")\n",[189,944,945,956,968,972,985,995,1008,1020,1031,1058,1063,1068,1081,1085,1096,1110],{"__ignoreMap":276},[280,946,947,949,951,953],{"class":282,"line":283},[280,948,366],{"class":297},[280,950,439],{"class":293},[280,952,372],{"class":297},[280,954,955],{"class":293}," BaseModel, ConfigDict, field_serializer\n",[280,957,958,960,963,965],{"class":282,"line":290},[280,959,366],{"class":297},[280,961,962],{"class":293}," datetime ",[280,964,372],{"class":297},[280,966,967],{"class":293}," datetime\n",[280,969,970],{"class":282,"line":314},[280,971,354],{"emptyLinePlaceholder":353},[280,973,974,976,979,981,983],{"class":282,"line":335},[280,975,386],{"class":297},[280,977,978],{"class":389}," LegacyPayload",[280,980,393],{"class":293},[280,982,396],{"class":389},[280,984,399],{"class":293},[280,986,987,990,992],{"class":282,"line":350},[280,988,989],{"class":293}," model_config ",[280,991,756],{"class":297},[280,993,994],{"class":293}," ConfigDict(\n",[280,996,997,1000,1002,1005],{"class":282,"line":357},[280,998,999],{"class":752}," strict",[280,1001,756],{"class":297},[280,1003,1004],{"class":301},"True",[280,1006,1007],{"class":293},",\n",[280,1009,1010,1013,1015,1018],{"class":282,"line":363},[280,1011,1012],{"class":752}," extra",[280,1014,756],{"class":297},[280,1016,1017],{"class":495},"\"forbid\"",[280,1019,1007],{"class":293},[280,1021,1022,1025,1027,1029],{"class":282,"line":378},[280,1023,1024],{"class":752}," populate_by_name",[280,1026,756],{"class":297},[280,1028,1004],{"class":301},[280,1030,1007],{"class":293},[280,1032,1033,1036,1038,1041,1044,1047,1050,1052,1055],{"class":282,"line":383},[280,1034,1035],{"class":752}," json_schema_extra",[280,1037,756],{"class":297},[280,1039,1040],{"class":293},"{",[280,1042,1043],{"class":495},"\"example\"",[280,1045,1046],{"class":293},": {",[280,1048,1049],{"class":495},"\"created_at\"",[280,1051,408],{"class":293},[280,1053,1054],{"class":495},"\"2023-01-01T00:00:00Z\"",[280,1056,1057],{"class":293},"}}\n",[280,1059,1060],{"class":282,"line":402},[280,1061,1062],{"class":293}," )\n",[280,1064,1065],{"class":282,"line":414},[280,1066,1067],{"class":293}," created_at: datetime\n",[280,1069,1070,1073,1075,1078],{"class":282,"line":423},[280,1071,1072],{"class":293}," metadata: ",[280,1074,823],{"class":301},[280,1076,1077],{"class":297}," =",[280,1079,1080],{"class":293}," {}\n",[280,1082,1083],{"class":282,"line":428},[280,1084,354],{"emptyLinePlaceholder":353},[280,1086,1087,1090,1092,1094],{"class":282,"line":434},[280,1088,1089],{"class":389}," @field_serializer",[280,1091,393],{"class":293},[280,1093,1049],{"class":495},[280,1095,499],{"class":293},[280,1097,1098,1100,1103,1106,1108],{"class":282,"line":447},[280,1099,514],{"class":297},[280,1101,1102],{"class":389}," serialize_dt",[280,1104,1105],{"class":293},"(self, dt: datetime) -> ",[280,1107,523],{"class":301},[280,1109,531],{"class":293},[280,1111,1112,1114,1117,1120,1123,1126],{"class":282,"line":452},[280,1113,537],{"class":297},[280,1115,1116],{"class":293}," dt.strftime(",[280,1118,1119],{"class":495},"\"%Y-%m-",[280,1121,1122],{"class":301},"%d",[280,1124,1125],{"class":495},"T%H:%M:%SZ\"",[280,1127,499],{"class":293},[219,1129],{},[222,1131,1133],{"id":1132},"phase-4-debugging-serialization-openapi-schema-drift","Phase 4: Debugging Serialization & OpenAPI Schema Drift",[162,1135,1136],{},"Identify and resolve discrepancies between v1 and v2 JSON Schema outputs that break frontend clients and third-party integrations. Schema drift is the most common cause of post-migration production incidents.",[162,1138,1139],{},[178,1140,1141],{},"Debugging Workflow:",[1143,1144,1145,1156,1166,1176],"ol",{},[185,1146,1147,1148,1151,1152,1155],{},"Compare ",[189,1149,1150],{},"model.schema()"," (v1) vs ",[189,1153,1154],{},"model.model_json_schema()"," (v2) outputs using a JSON diff tool",[185,1157,1158,1159,1162,1163],{},"Debug ",[189,1160,1161],{},"Union"," type resolution changes by explicitly ordering types or using ",[189,1164,1165],{},"typing_extensions.Annotated",[185,1167,1168,1169,1172,1173],{},"Validate nested model serialization with ",[189,1170,1171],{},"model_dump(mode=\"json\")"," instead of legacy ",[189,1174,1175],{},".dict()",[185,1177,1178,1179,249,1182],{},"Run contract tests against production traffic snapshots using tools like ",[189,1180,1181],{},"schemathesis",[189,1183,1184],{},"pytest-contract",[271,1186,1188],{"className":273,"code":1187,"language":275,"meta":276,"style":276},"# Schema diff verification script\nimport json\nfrom app.models.v2 import ModernUser\n\nv2_schema = ModernUser.model_json_schema()\nprint(json.dumps(v2_schema, indent=2))\n\n# Production-safe serialization test\ndef test_serialization_contract():\n user = ModernUser(id=1, username=\"TestUser\")\n payload = user.model_dump(mode=\"json\")\n assert isinstance(payload[\"id\"], int)\n assert isinstance(payload[\"username\"], str)\n",[189,1189,1190,1195,1202,1214,1218,1228,1247,1251,1256,1267,1297,1316,1337],{"__ignoreMap":276},[280,1191,1192],{"class":282,"line":283},[280,1193,1194],{"class":286},"# Schema diff verification script\n",[280,1196,1197,1199],{"class":282,"line":290},[280,1198,372],{"class":297},[280,1200,1201],{"class":293}," json\n",[280,1203,1204,1206,1209,1211],{"class":282,"line":314},[280,1205,366],{"class":297},[280,1207,1208],{"class":293}," app.models.v2 ",[280,1210,372],{"class":297},[280,1212,1213],{"class":293}," ModernUser\n",[280,1215,1216],{"class":282,"line":335},[280,1217,354],{"emptyLinePlaceholder":353},[280,1219,1220,1223,1225],{"class":282,"line":350},[280,1221,1222],{"class":293},"v2_schema ",[280,1224,756],{"class":297},[280,1226,1227],{"class":293}," ModernUser.model_json_schema()\n",[280,1229,1230,1233,1236,1239,1241,1244],{"class":282,"line":357},[280,1231,1232],{"class":301},"print",[280,1234,1235],{"class":293},"(json.dumps(v2_schema, ",[280,1237,1238],{"class":752},"indent",[280,1240,756],{"class":297},[280,1242,1243],{"class":301},"2",[280,1245,1246],{"class":293},"))\n",[280,1248,1249],{"class":282,"line":363},[280,1250,354],{"emptyLinePlaceholder":353},[280,1252,1253],{"class":282,"line":378},[280,1254,1255],{"class":286},"# Production-safe serialization test\n",[280,1257,1258,1261,1264],{"class":282,"line":383},[280,1259,1260],{"class":297},"def",[280,1262,1263],{"class":389}," test_serialization_contract",[280,1265,1266],{"class":293},"():\n",[280,1268,1269,1272,1274,1277,1280,1282,1285,1287,1290,1292,1295],{"class":282,"line":402},[280,1270,1271],{"class":293}," user ",[280,1273,756],{"class":297},[280,1275,1276],{"class":293}," ModernUser(",[280,1278,1279],{"class":752},"id",[280,1281,756],{"class":297},[280,1283,1284],{"class":301},"1",[280,1286,749],{"class":293},[280,1288,1289],{"class":752},"username",[280,1291,756],{"class":297},[280,1293,1294],{"class":495},"\"TestUser\"",[280,1296,499],{"class":293},[280,1298,1299,1302,1304,1307,1309,1311,1314],{"class":282,"line":414},[280,1300,1301],{"class":293}," payload ",[280,1303,756],{"class":297},[280,1305,1306],{"class":293}," user.model_dump(",[280,1308,753],{"class":752},[280,1310,756],{"class":297},[280,1312,1313],{"class":495},"\"json\"",[280,1315,499],{"class":293},[280,1317,1318,1321,1324,1327,1330,1333,1335],{"class":282,"line":423},[280,1319,1320],{"class":297}," assert",[280,1322,1323],{"class":301}," isinstance",[280,1325,1326],{"class":293},"(payload[",[280,1328,1329],{"class":495},"\"id\"",[280,1331,1332],{"class":293},"], ",[280,1334,789],{"class":301},[280,1336,499],{"class":293},[280,1338,1339,1341,1343,1345,1347,1349,1351],{"class":282,"line":428},[280,1340,1320],{"class":297},[280,1342,1323],{"class":301},[280,1344,1326],{"class":293},[280,1346,496],{"class":495},[280,1348,1332],{"class":293},[280,1350,523],{"class":301},[280,1352,499],{"class":293},[219,1354],{},[222,1356,1358],{"id":1357},"common-production-pitfalls","Common Production Pitfalls",[1360,1361,1362,1378],"table",{},[1363,1364,1365],"thead",{},[1366,1367,1368,1372,1375],"tr",{},[1369,1370,1371],"th",{},"Issue",[1369,1373,1374],{},"Root Cause",[1369,1376,1377],{},"Production Fix",[1379,1380,1381,1403,1426,1449],"tbody",{},[1366,1382,1383,1389,1395],{},[1384,1385,1386],"td",{},[178,1387,1388],{},"Silent type coercion",[1384,1390,1391,1392,1394],{},"v2 allows implicit conversions in certain contexts unless ",[189,1393,909],{}," is set",[1384,1396,1397,1398,245,1400,1402],{},"Explicitly configure ",[189,1399,909],{},[189,1401,213],{}," to prevent float-to-int truncation",[1366,1404,1405,1411,1418],{},[1384,1406,1407,1410],{},[189,1408,1409],{},"TypeError"," on legacy validators",[1384,1412,1413,1414,1417],{},"Directly porting v1 ",[189,1415,1416],{},"@validator(cls, v, values, field, config)"," signature",[1384,1419,1420,1421,1423,1424],{},"Migrate to ",[189,1422,202],{}," and access context via ",[189,1425,602],{},[1366,1427,1428,1433,1440],{},[1384,1429,1430],{},[178,1431,1432],{},"Incomplete JSON responses",[1384,1434,1435,1436,1439],{},"Calling ",[189,1437,1438],{},"dict(model)"," on v2 models triggers deprecation warnings and skips nested serialization",[1384,1441,1442,1443,1446,1447],{},"Replace all ",[189,1444,1445],{},"dict()"," calls with ",[189,1448,1171],{},[1366,1450,1451,1464,1473],{},[1384,1452,1453],{},[178,1454,1455,1456,1459,1460,1463],{},"OpenAPI ",[189,1457,1458],{},"anyOf"," vs ",[189,1461,1462],{},"allOf"," drift",[1384,1465,1466,1467,203,1469,1472],{},"v2 changes how ",[189,1468,1161],{},[189,1470,1471],{},"Optional"," types are represented in JSON Schema",[1384,1474,255,1475,573,1478,1481],{},[189,1476,1477],{},"typing.Annotated",[189,1479,1480],{},"Field()"," constraints to stabilize schema output",[219,1483],{},[222,1485,1487],{"id":1486},"frequently-asked-questions","Frequently Asked Questions",[162,1489,1490],{},[178,1491,1492],{},"Can I run Pydantic v1 and v2 models simultaneously in FastAPI?",[162,1494,1495,1496,1498,1499,1501],{},"Yes. Import from ",[189,1497,191],{}," for legacy routes and ",[189,1500,294],{}," for new ones. FastAPI handles both namespaces seamlessly, but ensure OpenAPI schema generation doesn't mix them. Isolate v1 routes behind a dedicated router prefix if possible.",[162,1503,1504],{},[178,1505,1506],{},"How do I fix 422 Unprocessable Entity errors after migration?",[162,1508,1509,1510,1512,1513,1515,1516,1519,1520,1522,1523,1525,1526,1529],{},"Verify ",[189,1511,909],{}," enforcement, check ",[189,1514,202],{}," execution modes, and ensure ",[189,1517,1518],{},"model_dump()"," replaces ",[189,1521,1445],{},". Enable ",[189,1524,294],{},"'s ",[189,1527,1528],{},"error_wrappers"," to log exact validation failures at the route level before they reach the client.",[162,1531,1532],{},[178,1533,1534],{},"Does Pydantic v2 change how FastAPI generates OpenAPI docs?",[162,1536,1537,1538,1541,1542,1545],{},"Yes. v2 uses ",[189,1539,1540],{},"model_json_schema()"," which produces stricter JSON Schema drafts (aligned with OpenAPI 3.1). Adjust ",[189,1543,1544],{},"json_schema_extra"," to maintain frontend client compatibility, and validate generated specs against your API contract before deployment.",[1547,1548,1549],"style",{},"html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html pre.shiki code .sgsFI, html code.shiki .sgsFI{--shiki-default:#24292E}html pre.shiki code .sD7c4, html code.shiki .sD7c4{--shiki-default:#D73A49}html pre.shiki code .sYu0t, html code.shiki .sYu0t{--shiki-default:#005CC5}html pre.shiki code .s7eDp, html code.shiki .s7eDp{--shiki-default:#6F42C1}html pre.shiki code .sYBdl, html code.shiki .sYBdl{--shiki-default:#032F62}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .sqxcx, html code.shiki .sqxcx{--shiki-default:#E36209}",{"title":276,"searchDepth":290,"depth":290,"links":1551},[1552,1553,1554,1555,1556,1557],{"id":224,"depth":290,"text":225},{"id":545,"depth":290,"text":546},{"id":889,"depth":290,"text":890},{"id":1132,"depth":290,"text":1133},{"id":1357,"depth":290,"text":1358},{"id":1486,"depth":290,"text":1487},"Upgrading to Pydantic v2 introduces breaking changes in validation, serialization, and schema generation that can silently corrupt API contracts. This guide…","md",{},{"title":61,"description":1558},"UOfEWPDOHmthDVItgLVe5YtJKENwMCw-GocqG0zDo3A",[1564,1564],null,1778082655107]