Skip to main content

Instantiate Pydantic models directly from Django HttpRequest for request validation

Project description

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 validationdata = 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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

django_pydantic_client-0.1.2.tar.gz (7.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

django_pydantic_client-0.1.2-py3-none-any.whl (8.0 kB view details)

Uploaded Python 3

File details

Details for the file django_pydantic_client-0.1.2.tar.gz.

File metadata

  • Download URL: django_pydantic_client-0.1.2.tar.gz
  • Upload date:
  • Size: 7.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for django_pydantic_client-0.1.2.tar.gz
Algorithm Hash digest
SHA256 cdd0496e62e0c63bcae76b0f347efa9976d40b9fedff0a905cc2bf4d8dbb6cb6
MD5 eaf8de46a3c6e002567975cc250e15a5
BLAKE2b-256 e9d304aa8023c715f987786359c813e30379369b156af4953c62d9fc1beb9e91

See more details on using hashes here.

File details

Details for the file django_pydantic_client-0.1.2-py3-none-any.whl.

File metadata

File hashes

Hashes for django_pydantic_client-0.1.2-py3-none-any.whl
Algorithm Hash digest
SHA256 0ddd940b20129eb403e60ff79625e6cd7fba06c3e8ca7fcb0fb0a632f89b74ce
MD5 9df904f7adf194e4b86b063285bd2dee
BLAKE2b-256 22a273d864826f71578b11a35e955046566a0ef241562020281ecc51e5bbe3f1

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page