Validate the Date Format
Exit

Validate the Date Format

Add a custom validator that checks the date field is in YYYY-MM-DD format

💻

Writing code and entering commands is only available on desktop. Open this page on a larger screen to complete this chapter.

Why validation matters

Your Expense model already validates types and values. Pydantic rejects negative amounts, empty descriptions, and invalid categories automatically. But the date field is defined as Optional[str] = None — Pydantic checks that the value is a string (or None), but it does not check the format. A client can send "banana" as a date and your API will accept it.

In a production API, you would validate every input that has a specific format or business rule. This course focuses on building endpoints, so we will add one custom validator for the date field to show you the pattern. The same technique applies to any field that needs format checking.

How field validators work

Built-in constraints like Field(gt=0) handle simple rules. But format validation — checking that a string follows a specific pattern — requires custom logic. Pydantic's @field_validator decorator lets you write that logic as a method on your model. It receives the field value, validates it, and returns it. If the value is invalid, the method raises a ValueError, and Pydantic converts it into a validation error with a clear message.

@field_validator("date")
@classmethod
def validate_date_format(cls, v):
    # v is the value of the date field
    # return v if valid, raise ValueError if not

A regular method uses self as its first argument — it works on a finished object. But when Pydantic validates input data, the object does not exist yet. The @classmethod decorator makes the method receive the class (cls) instead of an instance (self), so it can run before the object is created. Pydantic requires this for field validators.

Parsing dates with strptime

Python's datetime.strptime() parses a string into a date object using a format pattern. If the string does not match the pattern, it raises a ValueError. You can use this to validate the format without keeping the parsed result — just check that the parsing succeeds.

The format "%Y-%m-%d" matches strings like "2024-01-15" (four-digit year, two-digit month, two-digit day).

Instructions

Add a custom date validator to the Expense model.

  1. Add from datetime import datetime to the imports at the top of the file.
  2. Add field_validator to the existing pydantic import, so it reads from pydantic import BaseModel, Field, field_validator.
  3. Inside the Expense class, after the date field, add the @field_validator("date") decorator followed by @classmethod on the next line.
  4. Define a method named validate_date_format that takes two parameters — cls and v — then inside it, write if v is not None:.
  5. Inside the if block, add a try / except ValueError block. In the try, call datetime.strptime(v, "%Y-%m-%d") — this attempts to parse v as a date using that exact format. If the string does not match, Python raises a ValueError automatically. Catch it and raise ValueError("Date must be in YYYY-MM-DD format").
  6. After the if block, return v.