Django adds backwards relations at runtime which aren't caught by mypy
which only does static analysis.
To make mypy
happy (and to make it work with your editor's autocomplete) you need to add an explicit type hint to Site
:
class Site(models.Model):
organization: "Organization"
class Organization(models.Model):
site = models.OneToOneField(Site)
Using quotes around the type is needed since we are doing a forward reference to Organization
before it has been defined.
For foreign keys and many-to-many relationships, you can do the same thing, but using a QuerySet
type hint instead:
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: There is a django-stubs package which is meant to integrate with mypy
, however I haven't used it personally. It may provide a solution for this without having to explicitly add type hints to models.
isinstance(o.employees, models.QuerySet)
is False.type(o.employees)
showsdjango.db.models.fields.related_descriptors.create_reverse_many_to_one_manager.<locals>.RelatedManager
. Also, if Employee defines custom objects manager (models.Manager) namedEmployeeManager
, thenisinstance(o.employees, EmployeeManager)
is True. and without this custom objects manager,isinstance(o.employees, models.Manager)
is True – Katharyn