Django REST Framework Types
djangorestframework-types provides essential type stubs for Django REST Framework, enabling robust static type checking with tools like MyPy. As of version 0.9.0, it targets DRF 3.14+ and Python 3.8+, with updates typically released to support new DRF versions and features.
Common errors
-
mypy: Plugin 'drf_types.plugin.DrfPlugin' was not found
cause The `drf_types.plugin.DrfPlugin` module or class could not be located by MyPy, likely due to incorrect path or missing installation.fixEnsure `djangorestframework-types` is installed in the same environment MyPy is running in, and that the `plugins` line in `mypy.ini` is correct: `plugins = drf_types.plugin.DrfPlugin`. -
error: Module "rest_framework.serializers" has no attribute "Serializer" [attr-defined]
cause MyPy is unable to resolve the correct types for DRF components, often indicating that the `drf_types.plugin.DrfPlugin` is not active or correctly configured.fixVerify that `plugins = drf_types.plugin.DrfPlugin` is correctly placed in your `mypy.ini` file under the `[mypy]` section, and that your DRF version is supported (>=3.14). -
error: Incompatible types in assignment (expression has type "Any", variable has type "dict[str, str]")
cause This generic MyPy error, when related to DRF code, often means the type stubs for DRF (or Django) are not being fully applied, leading MyPy to infer `Any` instead of specific types.fixEnsure both `djangorestframework-types` and `django-stubs` are installed and their respective plugins are configured in `mypy.ini`. Check that you're using supported versions of Django and DRF.
Warnings
- breaking As of version 0.8.0, the `drf_types.plugin.DrfPlugin` must be explicitly listed in your `mypy.ini` under the `[mypy]` section. Omitting it will result in incomplete or incorrect type checking for DRF components.
- breaking Version 0.7.0 dropped support for Django REST Framework versions older than 3.14. Using `djangorestframework-types` with DRF < 3.14 may lead to type errors or unexpected behavior.
- gotcha For comprehensive type checking in a Django project, it is highly recommended to also install and configure `django-stubs`. `djangorestframework-types` builds upon `django-stubs` for core Django types.
- gotcha If you have custom DRF applications that define their own serializers, views, or models, MyPy's type checking might not fully understand them without explicit configuration. List them under the `[drf-types]` section in your `mypy.ini`.
Install
-
pip install djangorestframework-types mypy
Imports
- DrfPlugin
plugins = drf_types.plugin.DrfPlugin
Quickstart
# mypy.ini (create or update this file in your project root):
# [mypy]
# plugins =
# drf_types.plugin.DrfPlugin
#
# [drf-types]
# # Optional: List your custom DRF apps for deeper introspection
# # apps =
# # my_app
# # another_app
# quickstart_example.py (save this as a Python file):
from rest_framework import serializers
import os # For os.environ.get if needed for real data/auth
class UserSerializer(serializers.Serializer):
id: serializers.IntegerField = serializers.IntegerField(read_only=True)
username: serializers.CharField = serializers.CharField(max_length=150)
email: serializers.EmailField = serializers.EmailField()
def create(self, validated_data: dict[str, str]) -> dict[str, str]:
# In a real application, this would create a User model instance.
# This example just returns the data for demonstration.
print(f"Creating user: {validated_data.get('username', 'N/A')}")
return validated_data
def update(self, instance: dict, validated_data: dict[str, str]) -> dict:
# In a real application, this would update a User model instance.
print(f"Updating user: {instance.get('id', 'N/A')}")
instance['username'] = validated_data.get('username', instance.get('username', ''))
instance['email'] = validated_data.get('email', instance.get('email', ''))
return instance
# Example usage with type checking:
initial_data = {
"username": "testuser_" + os.environ.get('TEST_ID', '1'),
"email": "test@example.com"
}
serializer = UserSerializer(data=initial_data)
serializer.is_valid(raise_exception=True)
# `validated_data` is now correctly typed thanks to djangorestframework-types
validated_data: dict[str, str] = serializer.validated_data
# MyPy will detect issues like accessing non-existent keys:
# print(validated_data['non_existent_field']) # Mypy would flag this as an error
print(f"Validated username: {validated_data['username']}")
# To run type checking, ensure mypy.ini is configured as above, then:
# mypy quickstart_example.py