为何mypy结合django-stubs无法推断Django CharField选项类型?
Django模型字段与枚举类型的mypy类型不兼容问题原因分析
问题场景
模型定义
from django.db import models class MyChoice(models.TextChoices): FOO = "foo", _("foo") BAR = "bar", _("bar") BAZ = "baz", _("baz") class MyModel(models.Model): my_field = models.CharField(choices=MyChoice.choices, max_length=64)
函数调用与mypy错误
def use_choice(choice: MyChoice) -> None: pass def call_use_choice(model: MyModel) -> None: use_choice(model.my_field) # error: Argument 1 to "use_choice" has incompatible type "str"; expected "MyChoice" [arg-type]
环境配置
pyproject.toml:
[tool.poetry.dependencies] python = ">=3.10,<3.11" Django = "^3.2.8" [tool.poetry.dependencies] mypy = "^1.1.1" django-stubs = "^1.16.0"
mypy.ini:
[mypy] python_version = 3.10 ignore_missing_imports = True plugins = mypy_django_plugin.main [mypy.plugins.django-stubs] django_settings_module = "config.settings"
问题原因
- Django字段的存储本质:
models.CharField搭配TextChoices时,数据库中存储的是枚举的字符串值(比如"foo"),而非MyChoice枚举类的实例。当你从model.my_field取值时,得到的是原始字符串,不是MyChoice.FOO这类枚举对象。 - django-stubs的类型推断逻辑:django-stubs对带choices的CharField,类型推断仍然是
str,不会自动映射为对应的枚举类型。这是因为Django运行时并不会自动将数据库返回的字符串转换为枚举实例,类型工具也不会做这个隐式转换假设。 - 类型不匹配:函数
use_choice的参数要求是MyChoice枚举实例,但传入的model.my_field是字符串类型,因此mypy会检测到类型不兼容的错误。
内容的提问来源于stack exchange,提问作者tinom9
相关产品推荐
相关产品推荐

