Skip to main content

django-pydantic-client

Skip the serializer. Validate Django requests with Pydantic models — one line, zero boilerplate.

CI / Publish PyPI version Python versions Downloads License


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 ValidationError to 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)

Source distribution for django-pydantic-client 0.1.2
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)

Table of built distributions (wheels) for django-pydantic-client 0.1.2
File Interpreter ABI Platform Actions
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.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page