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.1.tar.gz (7.5 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.1-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: django_pydantic_client-0.1.1.tar.gz
  • Upload date:
  • Size: 7.5 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.1.tar.gz
Algorithm Hash digest
SHA256 fb13014111f74d4a3eab190f09e6f2027330a68e309d10b80dc7cbdbd635bb1b
MD5 f6e77193bc9c95c216be476bfd8558d4
BLAKE2b-256 82fd03b99c53da8c71d7b1f776d75e0c13ba8b5f206d7d5b1ddf38ebab044c5c

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for django_pydantic_client-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 5c40c76dba51b1e0cc77d887848ced1812ac55278bfe5c0a89002196d9aa8337
MD5 ee32e9ad42098243310cb29b85afc1e7
BLAKE2b-256 9c250becd1b70e2011defd13b2a85a844b121ed374247ed29fec6470b7f654f8

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