Introduction

Types have become an important part of Python development. Django uses a fair bit of magic to achieve its ergonomics. That magic can sometimes make type checking difficult. Installing django-stubs gets you quite far, but there are still situations when some type checkers still need some help.

One of these situations can arise when you use related object managers.

Cannot access member X for type Y

Let’s create some fictional models to illustrate the problem.

class Author(models.Model):
    name = models.TextField(max_length=20)


class Category(models.Model):
    name = models.TextField(max_length=20)


class Article(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    authors = models.ManyToManyField(Author, related_name="articles")

A common way of accessing related objects in Django is through related managers. In the above example that could look something like this:

category = Category.objects.get(pk=1)
print(category.article_set.all())


author = Author.objects.get(pk=1)
print(author.articles.all())

The problem? Both article_set and articles are dynamically added to the instance and the type checker doesn’t know anything about them.

Diagnostics as reported by pyright.

Helping the type checker

We can help the type checker by adding the attributes to the respective models when the type checker is running:

from typing import TYPE_CHECKING

from django.db import models

if TYPE_CHECKING:
    from django.db.models.manager import RelatedManager


class Author(models.Model):
    name = models.TextField(max_length=20)

    if TYPE_CHECKING:
        articles: RelatedManager["Article"]


class Category(models.Model):
    name = models.TextField(max_length=20)

    if TYPE_CHECKING:
        article_set: RelatedManager["Article"]


class Article(models.Model):
    category = models.ForeignKey(Category, on_delete=models.CASCADE)
    authors = models.ManyToManyField(Author, related_name="articles")

Now proceed and use related object managers without any type errors!

Want to know more about how we can work together and launch a successful digital energy service?