Skip the serializer. Validate Django requests with Pydantic models — one line, zero boilerplate.
Documentation: https://django-pydantic.readthedocs.io
Source Code: https://github.com/NEFORCEO/django-pydantic
django-pydantic-client lets you replace manual request parsing in Django views with Pydantic models. Pass a HttpRequest directly to your schema — get a fully validated, typed Python object back, or an automatic HTTP 422 response if validation fails.
Key features:
- One-line validation —
data = MySchema(request) - Automatic 422 errors — middleware converts
ValidationErrorto structured JSON, no try/except needed - Smart data merging — GET params + POST form / JSON body + URL kwargs, all in one object
- Zero configuration — middleware auto-installs via
INSTALLED_APPS, nothing else to do - Full Pydantic v2 — validators,
Field(),model_config, computed fields, custom types
Requirements
- Python 3.10+
- Django 4.2+
- Pydantic 2.0+
Installation
pip install django-pydantic-client
Add to INSTALLED_APPS — that's the only configuration step:
# settings.py
INSTALLED_APPS = [
...
"django_pydantic",
]
PydanticValidationMiddleware is injected automatically. You do not need to touch MIDDLEWARE.
Quick start
Define a schema:
# myapp/schema.py
from pydantic import EmailStr, Field
from django_pydantic import RequestModel
class SignupSchema(RequestModel):
username: str = Field(min_length=3, max_length=32)
email: EmailStr
age: int = Field(ge=18)
Use it in a view:
# myapp/views.py
from django.http import JsonResponse
from .schema import SignupSchema
def signup(request):
data = SignupSchema(request) # validates GET / POST / JSON body
# data.username, data.email, data.age — typed and validated
return JsonResponse({"username": data.username})
Wire up the URL:
# urls.py
from django.urls import path
from myapp.views import signup
urlpatterns = [
path("signup/", signup),
]
On invalid input the response is automatic — no extra code required:
{
"detail": [
{"type": "missing", "loc": ["username"], "msg": "Field required"},
{"type": "value_error", "loc": ["email"], "msg": "value is not a valid email address"}
]
}
How data sources are merged
| Source | When used |
|---|---|
request.GET |
Always (any HTTP method) |
request.POST |
Non-GET/HEAD/DELETE, no JSON content-type |
| JSON body | Content-Type: application/json |
| URL kwargs | Passed explicitly: MySchema(request, pk=pk) |
Later sources override earlier ones. URL kwargs always win.
URL path parameters
# urls.py
path("users/<int:pk>/", user_detail)
# views.py
def user_detail(request, pk):
data = UserSchema(request, pk=pk) # pk merged with highest priority
user = User.objects.get(pk=data.pk)
...
Full Pydantic v2 support
from pydantic import Field, field_validator, computed_field
from django_pydantic import RequestModel
class OrderSchema(RequestModel):
product_id: int = Field(gt=0)
quantity: int = Field(ge=1, le=100)
coupon: str = ""
@field_validator("coupon")
@classmethod
def normalise_coupon(cls, v: str) -> str:
return v.strip().upper()
@computed_field
@property
def total_label(self) -> str:
return f"{self.quantity}x product #{self.product_id}"
Class-based views
from django.views import View
from django.http import JsonResponse
from .schema import ArticleCreateSchema
class ArticleView(View):
def post(self, request):
data = ArticleCreateSchema(request)
article = Article.objects.create(
title=data.title,
body=data.body,
author=request.user,
)
return JsonResponse({"id": article.pk}, status=201)
Error handling (opt-in)
The middleware handles errors automatically. To customise for a specific view:
from pydantic import ValidationError
def signup(request):
try:
data = SignupSchema(request)
except ValidationError as exc:
errors = {e["loc"][0]: e["msg"] for e in exc.errors(include_url=False)}
return JsonResponse({"errors": errors}, status=400)
return JsonResponse({"ok": True})
License
This project is licensed under the terms of the MIT license.
Metadata
Release files for django-pydantic-client 0.1.2
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| django_pydantic_client-0.1.2.tar.gz | 7.6 kB | Without provenance | Details for django_pydantic_client-0.1.2.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| django_pydantic_client-0.1.2-py3-none-any.whl | Python 3 | none | any | Details for django_pydantic_client-0.1.2-py3-none-any.whl |
Total release size: 15.6 kB
Release files / django_pydantic_client-0.1.2.tar.gz
| Download URL | django_pydantic_client-0.1.2.tar.gz |
|---|---|
| Size | 7.6 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
cdd0496e62e0c63bcae76b0f347efa9976d40b9fedff0a905cc2bf4d8dbb6cb6
|
|
BLAKE2b-256 checksum How to use checksums |
e9d304aa8023c715f987786359c813e30379369b156af4953c62d9fc1beb9e91
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / django_pydantic_client-0.1.2-py3-none-any.whl
| Download URL | django_pydantic_client-0.1.2-py3-none-any.whl |
|---|---|
| Size | 8.0 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
0ddd940b20129eb403e60ff79625e6cd7fba06c3e8ca7fcb0fb0a632f89b74ce
|
|
BLAKE2b-256 checksum How to use checksums |
22a273d864826f71578b11a35e955046566a0ef241562020281ecc51e5bbe3f1
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Security for django-pydantic-client 0.1.2
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.