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.0.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.0-py3-none-any.whl (7.7 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: django_pydantic_client-0.1.0.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.0.tar.gz
Algorithm Hash digest
SHA256 5385e9393d68d8f23768c933e4c2222d8d83edef2371dee64c8022e6ce3232c2
MD5 f3d4dbf0dc6ae784df2a5b1070078f29
BLAKE2b-256 273c93a3506059c531f40155369ff4c6d924b57b4d9343c8971f84d3abc3b409

See more details on using hashes here.

File details

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

File metadata

File hashes

Hashes for django_pydantic_client-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 b20debcbc27f18a8e439791deb6b81f10dd4734c1d8289313fa3b16eb2ac5e86
MD5 7825831bd2014a342872052aa71a7d33
BLAKE2b-256 96230b0660ec4265df6c5c782893c8f6721081ffcedc837fb6ccfb57f8a034da

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