VSCodeで開発しているDjangoを利用した個人プロジェクトで、動的に生成されるフィールドの型チェックがうまくいかず、試行錯誤を繰り返しました。最終的に解決策を見つけたので、その内容を紹介します。
検証に利用した環境
- ツール
- ライブラリ
- Django v5.1.6
- Django REST framework v3.15.2
- リポジトリ
1. Mypyプラグインを利用する
django-stubs と djangorestframework-stubs を dev dependencies に追加して下記のようにMypyプラグインの設定を行います。
django_settings_module
は環境変数 DJANGO_SETTINGS_MODULE
で設定することも可能です。
[dependency-groups]
dev = [
# ...
"django-stubs[compatible-mypy]>=5.1.3",
"djangorestframework-stubs[compatible-mypy]>=3.15.3",
# ...
]
[tool.django-stubs]
django_settings_module = "myproject.settings"
[tool.mypy]
plugins = ["mypy_django_plugin.main", "mypy_drf_plugin.main"]
Mypyプラグインの役割は下記URLの説明がわかりやすいです。
2. TypedModelMeta
を継承する
dependencies に django-stubs-ext を追加し、 Model
の Meta
で TypedModelMeta
を継承します。
[project]
dependencies = [
# ...
"django-stubs-ext>=5.1.2",
# ...
]
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"),
]
3. python -m mypy
で Mypy を実行する
python -m mypy
や uv run -m mypy
で実行しないと動的に生成されるフィールドの型チェックで下記のようなエラーが発生します。
error: "MyModel" has no attribute "id" [attr-defined]
error: "MyModel" has no attribute "foo_id" [attr-defined]
なお、pre-commit
の設定では pre-commit/mirrors-mypy に entry: python -m mypy
を指定しても良いのですが、下記のように設定すると django-stubs 等のバージョンを additional_dependencies
で指定する必要がなくなり、依存関係の管理が楽になるかもしれません。
repos:
- repo: local
hooks:
- id: mypy
name: mypy
entry: uv run -m mypy
language: system
types_or: [python, pyi]
args: [--scripts-are-modules]
require_serial: true
4. Pylance を型チェックで利用しない
VSCodeのPython用 Language Server である Pylance には django-stubs をフォークした django-types が含まれているため、動的に生成されるフィールド以外であれば型チェックが可能ですが、動的に生成されるフィールドについてはMypyプラグインのような仕組みがないため今のところ型チェックを行うことができません。
VSCode上で動的に生成されるフィールドの型チェックを行うためには Pylance の型チェックを無効化した後、後述する Mypy Type Checker を利用する必要があります。
{
// ...
"python.analysis.typeCheckingMode": "off",
// ...
}
なお、python.analysis.typeCheckingMode
はデフォルト値が off
であるため、設定削除でも型チェックを無効化できます。
5. Mypy Type Checker を型チェックで利用する
django-stubs[compatible-mypy]
の Mypy と Mypy Type Checker で利用する Mypy のバージョンをあわせるため、下記のような設定を行います。
{
// ...
"mypy-type-checker.importStrategy": "fromEnvironment",
"python.defaultInterpreterPath": "${workspaceFolder}/.venv",
// ...
}
なお、上記の設定を行うと Mypy Type Checker は下記のように python -m mypy
で Mypy を実行してくれるようです。
/path/to/.venv/bin/python -m mypy --no-color-output --no-error-summary --show-absolute-path --show-column-numbers --show-error-codes --no-pretty --show-error-end /path/to/foo.py
この方法で型チェックを行う場合の懸念点
- 動的に生成されるフィールドはコード補完の候補に現れない
- 行えるのは型チェックだけ
- 機能リクエストはされている様子
- 環境変数
DJANGO_SETTINGS_MODULE
を Mypy Type Checker で利用するのに手間がかかる -
Django REST framework の型を書くのがつらい
-
djangorestframework-stubs のソースを読まないとエラーの原因がわからなかったりする
- Django の型では今のところそんなことはない
- Django REST framework のかわりに Django Ninja と Django Ninja Extra を利用すると楽
-
djangorestframework-stubs のソースを読まないとエラーの原因がわからなかったりする