MCPcopy
hub / github.com/typeddjango/django-stubs

github.com/typeddjango/django-stubs @6.0.6 sqlite

repository ↗ · DeepWiki ↗ · release 6.0.6 ↗
589 symbols 2,308 edges 136 files 113 documented · 19%
README

django-stubs

test Checked with mypy StackOverflow

This package contains type stubs and a custom mypy plugin to provide more precise static types and type inference for Django framework. Django uses some Python "magic" that makes having precise types for some code patterns problematic. This is why we need this project. The final goal is to be able to get precise types for most common patterns.

Installation

pip install 'django-stubs[compatible-mypy]'

To make mypy aware of the plugin, you need to add

[mypy]
plugins =
    mypy_django_plugin.main

[mypy.plugins.django-stubs]
django_settings_module = "myproject.settings"

in your mypy.ini or setup.cfg file.

pyproject.toml configurations are also supported:

[tool.mypy]
plugins = ["mypy_django_plugin.main"]

[tool.django-stubs]
django_settings_module = "myproject.settings"

Two things happening here:

  1. We need to explicitly list our plugin to be loaded by mypy
  2. You can either specify django_settings_module as seen above, or let django_stubs use the DJANGO_SETTINGS_MODULE variable from your environment.

This fully working typed boilerplate can serve you as an example.

Version compatibility

We rely on different django and mypy versions:

django-stubs Mypy version Django version Django partial support Python version
6.0.6 1.13 - 2.1 6.0 5.2, 5.1, 5.0 3.10 - 3.14
6.0.5 1.13 - 2.1 6.0 5.2, 5.1, 5.0 3.10 - 3.14
6.0.4 1.13 - 2.0 6.0 5.2, 5.1, 5.0 3.10 - 3.14
6.0.3 1.13 - 1.20 6.0 5.2, 5.1, 5.0 3.10 - 3.14
6.0.2 1.13 - 1.20 6.0 5.2, 5.1, 5.0 3.10 - 3.14
6.0.1 1.13 - 1.19 6.0 5.2, 5.1, 5.0 3.10 - 3.14
6.0.0 1.13 - 1.19 6.0 5.2, 5.1, 5.0 3.10 - 3.14
5.2.9 1.13 - 1.19 5.2 5.1, 5.0 3.10 - 3.13
5.2.8 1.13 - 1.19 5.2 5.1, 5.0 3.10 - 3.13
5.2.7 1.13 - 1.18 5.2 5.1, 5.0 3.10 - 3.13
5.2.6 1.13 - 1.18 5.2 5.1, 5.0 3.10 - 3.13
5.2.5 1.13 - 1.18 5.2 5.1, 5.0 3.10 - 3.13
5.2.4 1.13 - 1.18 5.2 5.1, 5.0 3.10 - 3.13
5.2.3 1.13 - 1.18 5.2 5.1, 5.0 3.10 - 3.13
5.2.2 1.13 - 1.17 5.2 5.1, 5.0 3.10 - 3.13
5.2.1 1.13 - 1.16 5.2 5.1, 5.0 3.10 - 3.13
5.2.0 1.13+ 5.2 5.1, 5.0 3.10 - 3.13
5.1.3 1.13+ 5.1 4.2 3.9 - 3.13
5.1.2 1.13+ 5.1 4.2 3.9 - 3.13
5.1.1 1.13.x 5.1 4.2 3.8 - 3.12
5.1.0 1.11.x 5.1 4.2 3.8 - 3.12
5.0.4 1.11.x 5.0 4.2 3.8 - 3.12
5.0.3 1.11.x 5.0 4.2 3.8 - 3.12
5.0.2 1.10.x 5.0 4.2 3.8 - 3.12
5.0.1 1.10.x 5.0 4.2 3.8 - 3.12
5.0.0 1.10.x 5.0 4.2, 4.1 3.8 - 3.12
4.2.7 1.7.x 4.2 4.1, 3.2 3.8 - 3.12
4.2.6 1.6.x 4.2 4.1, 3.2 3.8 - 3.12
4.2.5 1.6.x 4.2 4.1, 3.2 3.8 - 3.12
4.2.4 1.5.x 4.2 4.1, 3.2 3.8 - 3.11
4.2.3 1.4.x 4.2 4.1, 3.2 3.8 - 3.11
4.2.2 1.4.x 4.2 4.1, 3.2 3.8 - 3.11
4.2.1 1.3.x 4.2 4.1, 3.2 3.8 - 3.11
4.2.0 1.2.x 4.2 4.1, 4.0, 3.2 3.7 - 3.11
1.16.0 1.1.x 4.1 4.0, 3.2 3.7 - 3.11
1.15.0 1.0.x 4.1 4.0, 3.2 3.7 - 3.11
1.14.0 0.990+ 4.1 4.0, 3.2 3.7 - 3.11

What "partial" support means, and why we don't pin to the exact Django/mypy version, is explained in https://github.com/typeddjango/django-stubs/discussions/2101#discussioncomment-9276632.

Features

Type checking of Model Meta attributes

[!NOTE] If you are using the mypy plugin and have django_stub_ext installed, your model Meta classes will be automatically type-checked without further changes.

By inheriting from the TypedModelMeta class, you can ensure you're using correct types for attributes:

from django.db import models
from django_stubs_ext.db.models import TypedModelMeta

class MyModel(models.Model):
    example = models.CharField(max_length=100)

    class Meta(TypedModelMeta):
        ordering = ["example"]
        constraints = [
            models.UniqueConstraint(fields=["example"], name="unique_example"),
        ]

Other typed base classes

  • django_stubs_ext.db.router.TypedDatabaseRouter can be used as base when implementing custom database routers.

Settings

django-stubs has a few settings, which you can list in:

  • pyproject.toml, under the table [tool.django-stubs]
  • mypy.ini under the table [mypy.plugins.django-stubs]

The supported settings are:

  • django_settings_module, a string, default to os.getenv(DJANGO_SETTINGS_MODULE).

Specify the import path of your settings module, the same as Django’s DJANGO_SETTINGS_MODULE environment variable.

  • strict_settings, a boolean, default true.

Set to false if using dynamic settings, as described below.

  • strict_model_abstract_attrs, a boolean, default true.

Set to false if you want to keep .objects, .DoesNotExist, .NotUpdated, and .MultipleObjectsReturned attributes on models.Model type. See here why this is dangerous to do by default.

FAQ

Is this an official Django project?

No, it is not. We are independent from Django at the moment. There's a proposal to merge our project into the Django itself. You can show your support by liking the PR.

Is it safe to use this in production?

Yes, it is! This project does not affect your runtime at all. It only affects mypy type checking process.

But, it does not make any sense to use this project without mypy.

mypy crashes when I run it with this plugin installed

The current implementation uses Django's runtime to extract information about models, so it might crash if your installed apps or models.py are broken.

In other words, if your manage.py runserver crashes, mypy will crash too. You can also run mypy with --tb option to get extra information about the error.

I cannot use QuerySet or Manager with type annotations

You can get a TypeError: 'type' object is not subscriptable when you will try to use QuerySet[MyModel], Manager[MyModel] or some other Django-based Generic types.

This happens because these Django classes do not support __class_getitem__ magic method in runtime.

  1. You can go with our django_stubs_ext helper, that patches all the types we use as Generic in django.

Install it:

bash pip install django-stubs-ext # as a production dependency

And then place in your top-level settings:

```python import django_stubs_ext

django_stubs_ext.monkeypatch() ```

You can add extra types to patch with django_stubs_ext.monkeypatch(extra_classes=[YourDesiredType])

If you use generic symbols in django.contrib.auth.forms, you will have to do the monkeypatching manually in your first AppConfig.ready. This is currently required because django.contrib.auth.forms cannot be imported until django is initialized.

```python
import django_stubs_ext
from django.apps import AppConfig

class ClientsConfig(AppConfig):
    name = "clients"

    def ready(self) -> None:
        from django.contrib.auth.forms import SetPasswordMixin, SetUnusablePasswordMixin

        # For Django version prior to 5.1, use `extra_classes=[SetPasswordForm, AdminPasswordChangeForm]` instead.
        django_stubs_ext.monkeypatch(extra_classes=[SetPasswordMixin, SetUnusablePasswordMixin])
```
  1. You can use strings instead: 'QuerySet[MyModel]' and 'Manager[MyModel]', this way it will work as a type for mypy and as a regular str in runtime.

How can I create a HttpRequest that's guaranteed to have an authenticated user?

Django's built in HttpRequest has the attribute user that resolves to the type User | AnonymousUser where User is the user model specified by the AUTH_USER_MODEL setting.

If you want a HttpRequest that you can type-annotate with where you know that the user is authenticated you can subclass the normal HttpRequest class like so:

from django.http import HttpRequest
from my_user_app.models import MyUser


class AuthenticatedHttpRequest(HttpRequest):
    user: MyUser

And then use AuthenticatedHttpRequest instead of the standard HttpRequest for when you know that the user is authenticated. For example in views using the @login_required decorator.

Why am I getting incompatible return type errors on my custom managers?

If you declare your custom managers without generics and override built-in methods you might see an error message about incompatible error messages, something like this:

from django.db import models

class MyManager(model.Manager):
    def create(self, **kwargs) -> "MyModel":
        pass

will cause this error message:

error: Return type "MyModel" of "create" incompatible with return type "_T" in supertype "BaseManager"

This is happening because the Manager class is generic, but without specifying generics the built-in manager methods are expected to return the generic type of the base manager, which is any model. To fix this issue you should declare your manager with your model as the type variable:

class MyManager(models.Manager["MyModel"]):
    ...

How do I annotate cases where I called QuerySet.annotate?

Django-stubs provides a special type, django_stubs_ext.WithAnnotations[Model, <Annotations>], which indicates that the Model has been annotated, meaning it requires extra attributes on the model instance.

You should provide a TypedDict of these attributes, e.g. WithAnnotations[MyModel, MyTypedDict], to specify which annotated attributes are present.

Currently, the mypy plugin can recognize that specific names were passed to QuerySet.annotate and include them in the type, but does not record the types of these attributes.

The knowledge of the specific annotated fields is not yet used in creating more specific types for QuerySet's values, values_list, or filter methods, however knowledge that the model was annotated is used to create a broader type result type for values/values_list, and to allow filtering on any field.

from typing import TypedDict
from django_stubs_ext import WithAnnotations
from django.db import models
from django.db.models.expressions import Value


class MyModel(models.Model):
    username = models.CharField(max_length=100)


class MyTypedDict(TypedDict):
    foo: str


def func(m: WithAnnotations[MyModel, MyTypedDict]) -> str:
    print(m.bar)  # Error, since field "bar" is not in MyModel or MyTypedDict.
    return m.foo  # OK, since we said field "foo" was allowed


func(MyModel.objects.annotate(foo=Value("")).get(id=1))  # OK
func(MyModel.objects.annotate(bar=Value("")).get(id=1))  # Error

You can also use WithAnnotations in custom QuerySet methods by making the querys

Core symbols most depended-on inside this repo

lookup_typeinfo
called by 16
mypy_django_plugin/transformers/models.py
lookup_typeinfo_or_incomplete_defn_error
called by 13
mypy_django_plugin/transformers/models.py
get_field_related_model_cls
called by 11
mypy_django_plugin/django/context.py
add_new_var_to_model_class
called by 10
mypy_django_plugin/transformers/models.py
_new_dependency
called by 9
mypy_django_plugin/main.py
get_model_class_by_fullname
called by 8
mypy_django_plugin/django/context.py
get_primary_key_field
called by 8
mypy_django_plugin/django/context.py
get_django_metadata
called by 8
mypy_django_plugin/lib/helpers.py

Shape

Function 293
Class 149
Method 147

Languages

Python100%

Modules by API surface

mypy_django_plugin/transformers/models.py68 symbols
mypy_django_plugin/lib/helpers.py58 symbols
mypy_django_plugin/transformers/querysets.py40 symbols
mypy_django_plugin/django/context.py33 symbols
tests/assert_type/contrib/admin/test_options.py23 symbols
tests/assert_type/views/test_function_based_views.py21 symbols
tests/assert_type/contrib/admin/test_decorators.py21 symbols
tests/assert_type/db/models/test_enums.py20 symbols
mypy_django_plugin/transformers/managers.py19 symbols
mypy_django_plugin/main.py17 symbols
tests/assert_type/utils/test_functional.py15 symbols
tests/assert_type/template/test_library.py14 symbols

Used by 2 indexed graphs manifest dependencies, hub-wide

Dependencies from manifests, versioned

django-stubs-ext6.0.2 · 1×
types-pyyaml
typing-extensions4.11.0 · 1×

For agents

$ claude mcp add django-stubs \
  -- python -m otcore.mcp_server <graph>

⬇ download graph artifact