Django: typehinting обратных / related_name / ForeignKey отношений

Допустим, у нас есть следующие модели:

class Site(models.Model):
    # This is djangos build-in Site Model
    pass

class Organization(models.Model):
    site = models.OneToOneField(Site)

А если я использую это где-то в каком-то другом классе:

organization = self.site.organization

Тогда mypy жалуется:

Site has no attribute "organization"

Как я могу сделать так, чтобы mypy был счастлив здесь?

Я только немного знаю английский, и я не знаю, что это правда. Но вы можете добавить

site = models.OneToOneField(Site, on_delete=models.CASCADE)

Вам необходимо установить атрибут related_name:

class Organization(models.Model):
    site = models.OneToOneField(Site, related_name="organization")

Django добавляет обратные связи во время выполнения, которые не улавливаются mypy, который делает только статический анализ.

Чтобы сделать mypy счастливым (и заставить его работать с автозаполнением вашего редактора), вам нужно добавить явную подсказку типа к Site:

class Site(models.Model):
    organization: "Organization"

class Organization(models.Model):
    site = models.OneToOneField(Site)

Использование кавычек вокруг типа необходимо, поскольку мы делаем переднюю ссылку на Organization до того, как он был определен.

Для внешних ключей и отношений "многие-ко-многим" можно сделать то же самое, но используя вместо этого подсказку типа QuerySet:

class Organization(models.Model):
    site = models.OneToOneField(Site)
    employees: models.QuerySet["Employee"]

class Employee(models.Model):
    organization = models.ForeignKey(
        Organization,
        on_delete=models.CASCADE,
        related_name="employees",
    )

EDIT: Существует пакет django-stubs, который предназначен для интеграции с mypy, однако лично я его не использовал. Он может обеспечить решение этой проблемы без необходимости явного добавления подсказок типов в модели.

Вернуться на верх