django-stubs
PEP 484 type stubs and a custom mypy plugin that bring precise static typing to Django's dynamic ORM and framework internals.
Repository Health
Technical Analysis
django-stubs contains type stubs and a custom mypy plugin that give Django projects precise static type checking. Django relies on runtime “magic” — dynamically generated manager attributes, metaclass-driven model fields, settings resolved from arbitrary modules — that plain type stubs can’t express on their own. The mypy plugin reads an app’s Django settings and model registry at analysis time to fill in the gaps: it infers queryset/manager generics, generates reverse relation accessors, validates Meta class attributes, and resolves lazy translation types.
The project ships as two installable pieces: django-stubs (the stubs plus the mypy plugin) and django-stubs-ext (a small runtime helper package that monkeypatches Django’s generic classes so QuerySet[MyModel]-style annotations work outside of type-checking, and that can be safely imported at runtime). Both are maintained together in this monorepo alongside a pytest-mypy-plugins-based test suite that runs real mypy analysis against hundreds of Django code samples.
Basic support for pyright, pyrefly, and ty is also checked in CI, though the mypy plugin remains the primary integration path and the one with full Django-specific type inference. The project tracks new Django and mypy releases closely, with an explicit compatibility matrix in the README mapping each django-stubs release to the Django and mypy versions it supports.
What You Get
- Full Django type stubs - PEP 484 stubs covering models, forms, views, middleware, URLs, templates, and the rest of Django’s public API.
- A custom mypy plugin - reads your app registry and
django_settings_moduleat analysis time to type model managers, querysets, and reverse relations accurately. django-stubs-extruntime package - a companion package withmonkeypatch()to make Django’s generic classes (QuerySet[Model],Manager[Model]) subscriptable at runtime, plusTypedModelMetaandWithAnnotationshelpers.- Configurable strictness settings -
strict_settingsandstrict_model_abstract_attrslet you dial down type strictness for dynamic settings modules or abstract base models. - Basic pyright/pyrefly/ty support - stub coverage is checked against three additional type checkers in CI, for teams not using mypy.
Common Use Cases
- Catching ORM misuse before runtime - a team enables the mypy plugin in CI so that incorrect field types, bad manager usage, or wrong queryset chaining fail the build instead of production.
- Typing custom managers and querysets - a developer subclasses
models.Manager[MyModel]andmodels.QuerySet[MyModel]and gets accurate return types oncreate(),get(), and chained queryset methods. - Working with reverse relations safely - a codebase with many
ForeignKeyandManyToManyFieldrelations uses the plugin’s auto-generatedRelatedManager/ManyRelatedManagertypes instead of hand-writing them. - Migrating a large Django codebase to typed Python - an engineering team incrementally adds mypy to an existing Django app, using
django-stubs-ext.monkeypatch()so generic model types work at runtime during the transition. - Annotating queryset
.annotate()results - a project usesWithAnnotations[Model, TypedDict]to give computed/annotated fields proper types instead of losing type information after.annotate()calls.
Under The Hood
Architecture
django-stubs is organized as two cooperating pieces: a large tree of .pyi stub files under django-stubs/ that mirror Django’s own package layout (db, forms, http, views, urls, etc.), and mypy_django_plugin/, a mypy Plugin subclass (NewSemanalDjangoPlugin in main.py) that hooks into mypy’s semantic analysis pipeline via get_additional_deps, attribute/method/function hooks, and dynamic class-def hooks. The plugin builds a DjangoContext from the project’s django_settings_module, which lets transformers/ modules (models.py, managers.py, querysets.py, forms.py, auth.py, settings.py, and others) resolve real app config, model fields, and settings values at analysis time rather than relying on static stub declarations alone. This is the core design tension the project manages: Django’s runtime dynamism versus mypy’s static analysis model, bridged by re-running a subset of Django’s own registration logic inside the plugin.
Tech Stack
The project is pure Python (99.8% by the GitHub language breakdown), targeting Python 3.11+ and built with uv_build in a uv workspace that also contains the ext sub-package (django-stubs-ext). Core dependencies are django itself, typing-extensions, and types-pyyaml; optional dependency groups add support for Oracle (oracledb) and Redis (redis, types-redis) backends. Static analysis tooling is unusually broad for a stubs package: mypy (the primary target), pyright, pyrefly, and ty are all configured and checked in CI, each with its own dependency group and settings block in pyproject.toml.
Code Quality
Testing relies on pytest-mypy-plugins, which runs real mypy analysis against YAML-defined test cases under tests/ (organized by Django subsystem: models, managers, fields, forms, views, contrib) and compares the resulting diagnostics against expected output — a pattern well suited to a project whose actual product is type-checker behavior. tests/assert_type/ additionally exercises the stubs directly against pyright/pyrefly/ty in strict mode. Linting is comprehensive: ruff with an extensive rule selection (bugbear, pyflakes, pyupgrade, flake8-type-checking, flake8-pyi, and more) plus codespell, and CI (test.yml) runs the full suite on each push. strict_type_ignore conventions are enforced by disabling generic # type: ignore in favor of tool-specific ignore comments, catching stale suppressions.
What Makes It Unique
Unlike most typeshed-style stub packages, django-stubs pairs its stubs with a mypy plugin that performs live introspection of the consuming project’s Django app registry and settings module during type checking — effectively re-deriving parts of Django’s own dynamic behavior (reverse relation names, Meta attribute validation, manager generics) inside the type checker rather than trying to express it all statically. Checking basic compatibility against three additional type checkers (pyright, pyrefly, ty) in the same CI run, despite none of them supporting a plugin hook, is also uncommon discipline for a project this specialized.
Used by 2 apps in this directory
ArchiveBox
Bookmarks Archiving
Self-hosted web archiving that saves HTML, PDFs, screenshots, media, and code in open formats you own forever
Flagsmith
Developer Tools · Devops · Ab Testing Experimentation
Open-source feature flagging, remote config, and A/B/multivariate testing platform for web, mobile, and server-side apps — self-host or use the hosted SaaS.