Pydantic Models workflow skill. Use this skill when the user needs Create Pydantic models following the multi-model pattern for clean API contracts and the operator should design explicit request, update, response, and internal model boundaries before merging or handing off.
Scanned 9/6/2026
Install to Claude Code
npx -y skills add diegosouzapw/awesome-omni-skills --skill pydantic-models-py --agent claude-codeInstalls into .claude/skills of the current project.
Are you the author of Pydantic Models Py?
Add the live security badge to your README — it updates automatically with every re-scan.
[](https://www.skillsdirectory.com/skills/diegosouzapw-pydantic-models-py-awesome-omni-skills)More formats (shields.io, HTML) on the badges page.
---
name: "pydantic-models-py"
description: "Pydantic Models workflow skill. Use this skill when the user needs Create Pydantic models following the multi-model pattern for clean API contracts and the operator should design explicit request, update, response, and internal model boundaries before merging or handing off."
version: "0.0.1"
category: "machine-learning"
tags:
- "pydantic-models-py"
- "pydantic"
- "api-contracts"
- "request-models"
- "response-models"
- "patch-updates"
- "omni-enhanced"
complexity: "advanced"
risk: "safe"
tools:
- "codex-cli"
- "claude-code"
- "cursor"
- "gemini-cli"
- "opencode"
source: "omni-team"
author: "Omni Skills Team"
date_added: "2026-03-27"
date_updated: "2026-04-19"
source_type: "omni-curated"
maintainer: "Omni Skills Team"
family_id: "pydantic-models-py"
family_name: "Pydantic Models"
variant_id: "omni"
variant_label: "Omni Curated"
is_default_variant: true
derived_from: "skills/pydantic-models-py"
upstream_skill: "skills/pydantic-models-py"
upstream_author: "sickn33"
upstream_source: "community"
upstream_pr: "79"
upstream_head_repo: "diegosouzapw/awesome-omni-skills"
upstream_head_sha: "6bf093920a93e68fa8263cf6ee767d7407989d56"
curation_surface: "skills_omni"
enhanced_origin: "omni-skills-private"
source_repo: "diegosouzapw/awesome-omni-skills"
replaces:
- "pydantic-models-py"
---
# Pydantic Models
## Overview
Use this skill to create or refactor Pydantic models for API integration work where request and response contracts must stay explicit, stable, and safe.
The upstream intent is preserved: use a multi-model pattern instead of one overloaded model for every purpose. The enhanced workflow modernizes that pattern for **Pydantic v2** and focuses on operational API contract design:
- separate create, update, public response, and internal shapes when their contracts differ
- use aliases intentionally when wire format differs from Python naming
- treat PATCH semantics as distinct from create semantics
- adapt ORM or document objects with `from_attributes=True` instead of legacy `orm_mode`
- prevent accidental field leakage by serializing public models, not internal ones
This skill is framework-agnostic Python guidance. FastAPI-style patterns are referenced because they are common and well documented, but the workflow applies to general API integration work.
> Version guard: this workflow assumes **Pydantic v2** semantics such as `model_validate`, `model_dump`, `ConfigDict`, `field_validator`, and `from_attributes`.
## When to Use This Skill
Use this skill when:
- you need Pydantic models for an external or internal API contract
- one model is starting to mix input validation, storage fields, and response serialization concerns
- the task requires separate handling for create vs update vs response payloads
- the API uses a different field naming style on the wire, such as camelCase externally and snake_case in Python
- partial updates must preserve the difference between omitted fields and explicit `null`
- ORM, document, or service-layer objects must be adapted into response models safely
Do **not** use this skill as the primary router when:
- the user only needs a single ad hoc data container with no contract boundary concerns
- the task is mainly about database schema design rather than API payload design
- the task depends on framework-specific response plumbing more than on Pydantic model design
## Operating Table
| Situation | Recommended model family | Key choices | Primary methods | Main risk |
| --- | --- | --- | --- | --- |
| Create or POST request | `Create` / input model | required writable fields, `extra='forbid'`, clear constraints | `model_validate(...)` | accepting undeclared fields or weak validation |
| Partial update or PATCH request | `Update` model | all fields optional as transport inputs, use `exclude_unset=True` | `model_dump(exclude_unset=True)` | clearing stored values by mistake |
| Public API response | `Public` / `Read` model | expose only contract fields, serialize with aliases if wire format needs them | `model_validate(...)`, `model_dump(by_alias=True)` | leaking internal fields or wrong field names |
| Internal service response | `Internal` model | include operational metadata only if not public | `model_validate(...)`, `model_dump(...)` | reusing internal models as public DTOs |
| ORM or document adaptation | `Public` or `Internal` model with attribute adaptation | `from_attributes=True` when validating from objects | `model_validate(obj)` | legacy `orm_mode` assumptions or field shape mismatch |
| Persistence shape | separate `InDB` / persistence model only if contract differs materially | add store-only fields only when needed | validate near persistence boundary | unnecessary model sprawl |
For selection guidance and config tradeoffs, see `references/integration-patterns.md`.
## Workflow
1. **Identify contract boundaries before writing code.**
Decide whether the task truly needs separate models for create, update, public response, internal response, or persistence. Do not create extra model families unless the payloads differ in a way that matters.
2. **Start from the external contract, not the database shape.**
For API work, define what clients may send and receive first. Persistence-only fields such as internal IDs, `doc_type`, audit flags, revision tokens, or secret material should not appear in public response models unless explicitly required.
3. **Choose a model taxonomy.**
A practical default is:
- `ThingBase`: shared constraints only when reuse is genuinely helpful
- `ThingCreate`: fields accepted on creation
- `ThingUpdate`: partial-update transport model
- `ThingPublic`: fields returned to API clients
- `ThingInternal` or `ThingInDB`: only when internal or persistence needs differ materially
If `Base` inheritance makes public/private boundaries fuzzy, prefer separate models instead of inheritance.
4. **Set explicit config for request safety.**
For externally sourced request models, start conservative:
```python
from pydantic import BaseModel, ConfigDict
class WidgetCreate(BaseModel):
model_config = ConfigDict(extra='forbid')
```
Consider stricter settings intentionally. Reject undeclared fields unless you have a compatibility reason not to. Use `default_factory` for dynamic defaults instead of mutable literals.
5. **Define field naming policy and aliases deliberately.**
If Python code uses `snake_case` but the API contract uses `camelCase`, encode that policy explicitly. Be consistent about whether validation accepts Python names, wire aliases, or both.
Preferred rule of thumb:
- keep Python attributes idiomatic in code
- expose the wire contract through aliases
- serialize public payloads with `by_alias=True` when aliases define the contract
- avoid mixing ad hoc field-level aliasing and broad alias generators without a reason
6. **Separate create and update semantics.**
`Create` models usually express required writable fields. `Update` models usually make all updatable fields optional so the transport layer can represent omission.
Important distinction:
- **omitted field**: leave current stored value unchanged
- **field present with `null` / `None`**: clear it, if the contract allows
- **field present with value**: replace or update
Use `model_dump(exclude_unset=True)` when applying PATCH-like updates.
7. **Validate and adapt at the correct boundary.**
Use `model_validate(...)` when building models from request payloads, trusted dictionaries, or class instances. When validating from ORM or document objects, configure the target model with `from_attributes=True`.
8. **Serialize public responses from public models.**
Prefer:
- validate an internal object into `ThingPublic`
- serialize `ThingPublic` with `model_dump(by_alias=True)` if aliases define the contract
Avoid dumping a richer internal model and trying to hide fields with ad hoc exclude lists.
9. **Place business rules carefully.**
Use `field_validator` or `model_validator` for transport and shape validation that belongs to the data contract. Keep workflow-specific side effects, repository checks, and cross-service orchestration in endpoint or service logic.
10. **Check generated payloads explicitly.**
Before finalizing, verify:
- required vs optional fields match the real contract
- public output excludes internal metadata
- aliases serialize exactly as clients expect
- PATCH behavior preserves omitted fields
## Troubleshooting
### Incoming camelCase fields do not populate snake_case model fields
**Symptoms**
- requests fail validation even though field names look correct to the client
- response output uses the wrong field style
**Likely causes**
- aliases were defined but serialization is not using `by_alias=True`
- validation settings do not match the accepted request field style
- alias strategy is mixed inconsistently across fields
**Corrective actions**
- define one alias policy for the model family
- ensure the public serialization path uses `model_dump(by_alias=True)` when aliases define the API contract
- avoid silently accepting multiple naming styles unless compatibility requires it
### PATCH or update requests clear values unexpectedly
**Symptoms**
- omitted fields overwrite stored data with `None`
- updates behave like full replacement instead of partial modification
**Likely causes**
- create and update models are being reused as if they were identical
- update application logic uses the full dumped model instead of `exclude_unset=True`
- explicit `None` is not being distinguished from field omission
**Corrective actions**
- create a dedicated `Update` model
- apply updates using `model_dump(exclude_unset=True)`
- decide explicitly whether `None` means clear-the-value or invalid input for each field
### ORM or document objects fail validation
**Symptoms**
- validation errors occur when passing model instances or row objects into response models
- nested attributes do not serialize as expected
**Likely causes**
- target model is missing `from_attributes=True`
- attribute names on the object do not match the response model fields or aliases
- the object contains richer nested state than the response contract allows
**Corrective actions**
- enable attribute-based validation on the target response model
- validate into a public DTO rather than serializing the raw ORM object
- inspect field names and nested object shapes before assuming the failure is a Pydantic bug
### Extra fields are accepted or rejected unexpectedly
**Symptoms**
- clients can send undeclared fields without error
- valid-looking requests fail because of unrecognized keys
**Likely causes**
- `extra` handling was left implicit
- request compatibility expectations are unclear
**Corrective actions**
- set `extra='forbid'` for external request models unless a looser contract is intentional
- document any compatibility exceptions clearly
- do not use permissive extra handling as a shortcut for poor contract definition
### Public responses leak internal metadata
**Symptoms**
- internal IDs, persistence fields, or operational flags appear in API output
**Likely causes**
- internal and public models were merged for convenience
- responses are serialized from internal models with ad hoc exclusions
**Corrective actions**
- create a dedicated public response model
- validate internal data into the public model before serialization
- verify the exact wire payload with `model_dump(by_alias=True)` when aliases are used
## Examples
See `examples/request-response-example.md` for a complete worked example that includes:
- separate create, update, public, internal, and persistence-adaptation models
- a camelCase wire contract with snake_case Python attributes
- `extra='forbid'` on request models
- `from_attributes=True` for adapting an object into a public DTO
- a PATCH scenario showing omitted vs explicit `null`
## Additional Resources
- `references/integration-patterns.md` — model-family selection matrix, alias policy options, config defaults, and contract safety guidance
- Pydantic v2 documentation for models, config, aliases, serialization, validators, and attribute-based validation
- FastAPI documentation on extra models and body updates for common API usage patterns
- JSON Schema and OpenAPI references for contract-oriented field semantics
## Related Skills
Use related skills when the task drifts into:
- framework-specific endpoint wiring rather than model design
- database migrations or persistence schema design
- TypeScript client generation or OpenAPI publication workflow
When in doubt, keep this skill focused on **Pydantic model boundaries and API contract correctness** rather than general backend implementation.
Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.
No comments yet. Be the first to comment!