Verified against Claude Code · 2026-07-21
Design Pydantic v2 models that validate a real domain, not just shapes
A prompt for designing Pydantic v2 models with field constraints, cross-field validators, and deliberate optional/required decisions from a description of real-world business rules.
The prompt
Ready to copy — highlighted parts are example details you can swap.
Design Pydantic v2 models for the domain below. The goal is models that reject bad data at the boundary, not models that just describe field names and types. DOMAIN A booking for a rental property, plus the guest making it BUSINESS RULES TO ENFORCE check-out date must be after check-in date; number of guests can't exceed the property's max_occupancy; a booking under 2 nights requires a minimum-stay override flag REQUIREMENTS 1. Use Pydantic v2 syntax specifically: model_config = ConfigDict(...), not the v1-style class Config. Use Field(...) constraints (gt, max_length, pattern, etc.) for anything checkable declaratively, before reaching for a custom validator. 2. Use @field_validator for single-field logic that Field() can't express, and @model_validator(mode="after") for anything depending on more than one field (e.g. end_date must be after start_date). Name which business rule each validator enforces, in a comment. 3. Be deliberate about Optional versus required — a field should only be optional if the domain genuinely allows it to be absent, not because it's convenient during construction. Justify each optional field in one line. 4. Use Annotated[...] types for any constraint you'd otherwise repeat across multiple models, instead of copy-pasting the same Field(...) arguments everywhere. 5. Serialization: API is camelCase JSON (checkInDate), Python code should stay snake_case. If any field needs a different name on the wire than in Python, use alias or an AliasGenerator and set populate_by_name correctly, rather than manually renaming keys after the fact. 6. Give every model a docstring stating what real-world entity it represents and what invalid state it's specifically guarding against. OUTPUT FORMAT 1. The models, in dependency order. 2. A short table: business rule, and which model or validator enforces it. 3. One example payload that should raise ValidationError, and what the error tells the caller.
Customize the highlighted detailsoptional — the prompt above already works
Why this works
Requiring Pydantic v2 syntax by name matters because a large share of tutorials and training data still show v1 patterns (class Config, the bare @validator decorator), and an underspecified prompt will produce a plausible-looking mix of both APIs that fails at import time on a v2-only install. Requiring a one-line justification for every Optional field directly counters the reflexive habit of marking everything Optional to avoid construction friction during development, which quietly defeats the entire point of using Pydantic for validation — a field that's "optional" only because it was annoying to require lets genuinely missing data flow silently downstream. Separating @field_validator from @model_validator(mode="after") by exact use case, rather than leaving the choice to the model, mirrors the real API distinction: a single-field validator literally cannot see other fields, so a cross-field rule like end date after start date has to live in the model-level validator or it can't be expressed at all.
What you get back
class BookingCreate(BaseModel): """A guest's request to book a property for a date range.""" model_config = ConfigDict(populate_by_name=True) check_in: date = Field(alias="checkInDate") check_out: date = Field(alias="checkOutDate") guest_count: int = Field(gt=0) override_min_stay: bool = False # optional: only relevant when a stay is under the minimum @model_validator(mode="after") def check_out_after_check_in(self) -> "BookingCreate": # enforces: check-out must be after check-in if self.check_out <= self.check_in: raise ValueError("check_out must be after check_in") return self Rule table: "check-out after check-in" -> check_out_after_check_in model_validator; "guest_count <= max_occupancy" -> field_validator cross-checked against the Property model at the service layer (not a static Field constraint, since it depends on another record). Invalid payload: {"checkInDate": "2026-09-10", "checkOutDate": "2026-09-09", "guestCount": 2} raises ValidationError: "check_out must be after check_in" — tells the caller exactly which rule failed, not just that the payload is invalid.
Verified against
Claude Code Sonnet 4.6 · 2026-07-21
ChatGPT GPT-5.1 · 2026-07-23
Changelog
- 2026-07-23 — Initial publish, verified against Claude Code (Sonnet 4.6) and ChatGPT (GPT-5.1) on Pydantic 2.9.
Need this built into your business?
If a prompt isn't enough — custom software, built and maintained for you — that's Scult's day job.
EXPLORE CUSTOM SOFTWARE

