Just use pip install pydantic-partial to install the library.
Note: pydantic-partial is compatible with pydantic version 2.x on Python 3.10, 3.11, 3.12,
3.13 and 3.14. This is also ensured running all tests on all those versions using tox.
Create partial models from your normal pydantic models. Partial models will allow some or all fields to be optional and thus not be required when creating the model instance.
Partial models can be used to support PATCH HTTP requests where the user only wants
to update some fields of the model and normal validation for required fields is not
required. It may also be used to have partial response DTOs where you want to skip
certain fields, this can be useful in combination with exclude_none. It is - like
shown in these examples - intended to be used with API use cases, so when using
pydantic with for example FastAPI.
Disclaimer: This is still an early release of pydantic-partial. Things might
change in the future. PR welcome. ;-)
pydantic-partial provides a mixin to generate partial model classes. The mixin can
be used like this:
import pydantic
from pydantic_partial import PartialModelMixin
# Something model, then can be used as a partial, too:
class Something(PartialModelMixin, pydantic.BaseModel):
name: str
age: int
# Create a full partial model
FullSomethingPartial = Something.model_as_partial()
FullSomethingPartial() # Same as FullSomethingPartial(name=None, age=None)You also may create partial models without using the mixin:
import pydantic
from pydantic_partial import create_partial_model
# Something model, without the mixin:
class Something(pydantic.BaseModel):
name: str
age: int
# Create a full partial model
FullSomethingPartial = create_partial_model(Something)
FullSomethingPartial() # Same as FullSomethingPartial(name=None, age=None)pydantic-partial can be used to create partial models that only change some
of the fields to being optional. Just pass the list of fields to be optional to
the as_partial() or create_partial_model() function.
import pydantic
from pydantic_partial import create_partial_model
class Something(pydantic.BaseModel):
name: str
age: int
# Create a partial model only for the name attribute
FullSomethingPartial = create_partial_model(Something, 'name')
FullSomethingPartial(age=40) # Same as FullSomethingPartial(name=None, age=40)
# This would still raise an error: FullSomethingPartial(age=None, ...)Partial models can be created changing the field of all nested models to being optional, too.
from typing import List
import pydantic
from pydantic_partial import PartialModelMixin, create_partial_model
class InnerSomething(PartialModelMixin, pydantic.BaseModel):
name: str
class OuterSomething(pydantic.BaseModel):
name: str
things: List[InnerSomething]
# Create a full partial model
RecursiveOuterSomethingPartial = create_partial_model(OuterSomething, recursive=True)
RecursiveOuterSomethingPartial(things=[
{},
])Note: The inner model MUST extend the PartialModelMixin mixin. Otherwise
pydantic-partial will not be able to detect which fields may allow to being
converted to partial models.
Also note: My recommendation would be to always create such recursive partials by creating partials for all the required models and then override the fields on you outer partial model class. This is way more explicit.
pydantic-partial ships a mypy plugin so that partial models created with
model_as_partial() are understood by static type checking, not just at runtime.
Enable it alongside Pydantic's own plugin (both are required — the plugin reads the
field metadata pydantic.mypy produces):
# pyproject.toml
[tool.mypy]
plugins = ["pydantic.mypy", "pydantic_partial.mypy"]from pydantic import BaseModel
from pydantic_partial import PartialModelMixin
class Foo(PartialModelMixin, BaseModel):
id: int
PartialFoo = Foo.model_as_partial()
reveal_type(PartialFoo()) # PartialFoo, with id: int | None
PartialFoo() # no error - all fields are optional
def something(x: PartialFoo) -> None: # PartialFoo is a real, usable type
...The plugin also understands field-selecting calls, where only the named fields become optional and the rest keep their original requiredness:
class User(PartialModelMixin, BaseModel):
id: int
name: str
PatchName = User.model_as_partial("name")
PatchName(id=1) # OK, only `name` was made optional
PatchName() # error: missing named argument "id"
reveal_type(PatchName(id=1).name) # str | NoneSupported: the no-argument model_as_partial() / as_partial() call (all fields become
optional) and calls that select fields by literal name (model_as_partial("name")), both in
the Partial = Model.model_as_partial(...) assignment form.
recursive= is not fully supported yet: the call still produces a flat partial (top-level
fields become optional), but nested models are not recursed into, so it is stricter than the
runtime behaviour rather than wrong.
These fall back to the checker's default instead (never a crash or a silently wrong type):
field lists that cannot be resolved statically (non-literal arguments, *args splats, or
dotted names like "items.name"), and non-assignment uses. pyright is not supported yet.
Without the mypy plugin described above (for example under pyright, or for the
partial variants the plugin does not cover yet), pydantic-partial cannot generate new
class types that are supported by the Python typing system rules. In those cases the
partial models will only be recognized as the same as their original model classes -
type checkers will not know about the partial model changes and thus will think all
those partial fields are still required.
This is due to the fact that Python itself has no concept of partials. pydantic-partial
could (in theory) provide plugins for mypy for example to "patch" this in, but this would
be a massive amount of work while being kind of a bad hack. The real solution would be to
have a partial type in Python itself, but this is not planned for the near future as far
as I know.
My recommendation is to use pydantic-partial only for API use cases where you do not
need to work with the partial aspects of the models - they are just the DTOs (data transfer
objects) you are using. If you need to use partial models in other cases you might get
errors by your type checker - if you use one. Please be aware of this.
Note: Not having a good solution in Python itself for this is the reason pydantic does
not support partial models in the first place. pydantic-partial is just a really good
workaround for this issue.
See issue 2 in this project and
issue 1673
in the pydantic project for reference.
Having that all said: If anyone wants to get a working plugin for mypy or others ready,
I'm going to very much support this.
If you want to contribute to this project, feel free to just fork the project, create a dev branch in your fork and then create a pull request (PR). If you are unsure about whether your changes really suits the project please create an issue first, to talk about this.
Please do not contribute AI generated code unless we explicitly talked about this and agreed upon doing so first. In general I do not want AI contributions.