Исправить Django «Неразрешенную ссылку на атрибут» для предварительно выбранного поля

#python #django #django-orm #type-hinting #prefetch

#python #django #django-orm #подсказка типа #предварительная выборка

Вопрос:

Допустим, у меня есть следующие модели 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)
 

У меня есть функция для получения всех небольших инструментов для каждого набора инструментов. Это @queries_disabled() происходит из django-zen-queries, чтобы убедиться, что небольшие инструменты были предварительно выбраны и избежать проблем с производительностью N 1.

 @queries_disabled()
def get_toolbox_to_small_tools_mappings(toolboxes: list[Toolbox]) -> dict:
    return {toolbox: toolbox.small_tools for toolbox in toolboxes}
 

Проблема в том, что мой редактор (PyCharm) выдает предупреждение:

Неразрешенная ссылка на атрибут ‘small_tools’ для класса ‘Toolbox’

Я могу исправить это, изменив подсказку типа аргумента:

 def get_toolbox_to_small_tools_mappings(toolboxes: list[Toolbox] | QuerySet): ...
 

Мне это кажется немного странным. Есть ли лучший способ исправить это?

Более того, я хотел бы предоставить полезное сообщение об ошибке вызывающей функции, если они забудут выполнить предварительную выборку этих данных. Прямо сейчас сообщение об ошибке:

Ошибка атрибута: объект «Toolbox» не имеет атрибута «small_tools»

Как я могу предоставить более явное сообщение об ошибке, в котором говорится что-то вроде:

Объект «Toolbox» не имеет атрибута «small_tools». Вы должны выполнить предварительную выборку этого поля.

Комментарии:

1. Из любопытства, почему это кажется хакерским? Наборы инструментов будут здесь набором запросов, верно?

2. Мне не нравится Union здесь. Я бы предпочел сделать что-то вроде QuerySet[Toolbox] . Но это кажется невозможным, основываясь на моих исследованиях.

3. Да, не без django-заглушек. WRT сообщение об ошибке, не могли бы вы перехватить AttributeError и создать собственное исключение?

4. Похоже , что примечания из django-stubs — это то, что мне здесь нужно