1

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

我有一个功能可以为每个工具箱获取所有小工具。参数类型提示来自这个 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}

这里的想法是要求此函数的用户使用以减少 db 命中数并加快代码速度来预取此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)

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

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

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

WithAnnotations[Model]来自 django-subs的类型(见这里)是一个选项,但它有问题

4

1 回答 1

0

我认为您最简单的解决方案是切换到使用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}

这使事情变得简单,并保持相同的功能。我不喜欢这样做,但是当你开始在 Django 中做动态的事情时,它很快就会成为最简单的解决方案。

于 2022-01-20T18:52:45.653 回答