为带有注释字段的 Django 模型键入提示

假设我有以下 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)

我有一个功能可以为每个工具箱获取所有小工具。参数类型提示来自 this SO answer

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}

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

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)

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

错误:“工具箱”没有属性“small_tools” [attr-defined]

Is there anyway to fix this?

The WithAnnotations[Model] type from django-subs (see here ) 是一个选项,但它是 buggy

stack overflow Type Hint for Django model with annotated field
原文答案

答案:

作者头像

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

另一种选择是切换到使用 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}

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