带注释字段的 Django 模型的类型提示

Joh*_*etz 6 python django type-hinting django-stubs

假设我有以下 Django 模型:

class Toolbox(models.Model):
    name = models.CharField(max_length=255)
    tools = models.ManyToManyField("Tool")

class Tool(models.Model):
    class Size(models.TextChoices):
        SMALL = "S"
        MEDIUM = "M"
        LARGE = "L"

    name = models.CharField(max_length=255)
    size = models.CharField(max_length=10, choices=Size.choices)
Run Code Online (Sandbox Code Playgroud)

我有一个功能可以获取每个工具箱的所有小工具。参数类型提示来自这个 SO 答案

from django.db.models import QuerySet

def get_toolbox_to_small_tools_mappings(
    toolboxes: QuerySet | list[Toolbox],
) -> dict[Toolbox, list[Tool]]:
    return {toolbox: toolbox.small_tools for toolbox in toolboxes}
Run Code Online (Sandbox Code Playgroud)

这里的想法是要求该函数的用户预取该small_tools字段,prefetch_related()以减少数据库命中次数并加快代码速度:

toolboxes = Toolbox.objects.prefetch_related(
    Prefetch(
        "tools",
        queryset=Tool.objects.filter(size=Tool.Size.SMALL),
        to_attr="small_tools",
    )
)
toolbox_to_small_tools_mappings = get_toolbox_to_small_tools_mappings(toolboxes)
Run Code Online (Sandbox Code Playgroud)

这一切都很好,但 mypy 抱怨以下错误:

错误:“工具箱”没有属性“small_tools”[属性定义]

有没有什么办法解决这一问题?

WithAnnotations[Model]django-subs 中的类型(参见此处)是一个选项,但它有问题

JGC*_*JGC -1

您最好的选择可能是使用 django-stubs 中的类型注释或禁用注释(类型:忽略)。

一种替代选择是切换到 using getattr,但这有缺点(见下文)。

from django.db.models import QuerySet

def get_toolbox_to_small_tools_mappings(
    toolboxes: QuerySet | list[Toolbox],
) -> dict[Toolbox, list[Tool]]:
    return {toolbox: getattr(toolbox, "small_tools") for toolbox in toolboxes}
Run Code Online (Sandbox Code Playgroud)

这使事情变得简单,并保持相同的功能,但代价是影响重构工具和其他无法翻译此代码的开发人员 IDE 功能。

  • 我不同意。重构工具不会翻译此类代码。最好使用(即使有错误)类型注释并推迟“修复”它,直到类型提示成为一等公民 (2认同)