Let's say I have the following Django models:
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)
I have a function to get all small tools for each toolbox. The argument type hint comes from 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}
The idea here is to require users of this function to prefetch this small_tools
field using prefetch_related()
to reduce the number of db hits and speed up the code:
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)
This all works great but mypy is complaining with the following error:
error: "Toolbox" has no attribute "small_tools" [attr-defined]
Is there anyway to fix this?
The WithAnnotations[Model]
type from django-subs (see here) is an option but it's buggy.