Partial Updates with PATCH
Exit

Partial Updates with PATCH

Understand the difference between PUT and PATCH and how exclude_unset works

The problem with full replacements

Your API can create, list, retrieve, and delete expenses. But what happens when a user needs to fix a typo in the description? Or change the amount from 12.00 to 15.00?

Without an update endpoint, the client must delete the expense and create a new one. That changes the identifier, breaks any references to the original record, and forces the client to resend every field.

PUT versus PATCH

HTTP defines two methods for updates:

  • PUT: Replaces the entire resource. The client must send all fields, even the ones that did not change. If the client omits a field, the server sets it to its default or removes it.
  • PATCH: Applies a partial update. The client sends only the fields that changed. Everything else stays the same.

For an expense tracker, PATCH is the better fit. A user updating the amount from 12.00 to 15.00 should not need to resend the description, category, and date.

How Pydantic tracks what was sent

When a client sends {"amount": 15.00}, Pydantic records that amount was the only field set by the client. The other fields have default values, but Pydantic marks them as unset — the client never provided them.

The method model_dump(exclude_unset=True) returns a dictionary containing only the fields the client actually sent:

updates.model_dump(exclude_unset=True)
# {"amount": 15.0}

Compare this to model_dump() without the flag:

updates.model_dump()
# {"description": None, "amount": 15.0, "category": None}

Without exclude_unset=True, merging these values into the stored expense would overwrite the description and category with None. The exclude_unset flag prevents that.

What you will build next

In the next two chapters, you will create an ExpenseUpdate model where every field is optional, then write a PATCH endpoint that merges the changes into the stored expense.

Next Chapter →