Skip to content

DOL007 false positive: loop iterates model classes, not instances #72

Description

@jsabater

VS Code version

1.126.04524

OS

Ubuntu 24.04 (Tuxedo OS)

Steps to reproduce

DOL007 fires on a plain class-attribute access when the loop iterates over model classes (as returned by apps.get_models()), reporting an N+1 and suggesting select_related() / prefetch_related(). No query is involved.

An abstract base declares two retention periods as plain class attributes:

  class Auditory(models.Model):
      ANONYMISE_AFTER: ClassVar[dt.timedelta | None] = None
      PURGE_AFTER: ClassVar[dt.timedelta | None] = None

      class Meta:
          abstract = True
      
  A helper collects the concrete models that inherit it:
      
  def auditory_models() -> list[type[Auditory]]:
      """Every concrete model inheriting Auditory."""
      return [
          model
          for model in apps.get_models()
          if issubclass(model, Auditory) and not model._meta.abstract
      ]

A sweep visits each model and reads its period:

  for model in auditory_models():
      if model.ANONYMISE_AFTER is None:   # <-- DOL007 reported here
          continue
      ...

Reported message:

Attribute access 'model.ANONYMISE_AFTER' inside a loop over 'auditory_models()' - consider .select_related() or .prefetch_related() to avoid an N+1.

Notes:

  • apps.get_models() returns model classes (ModelBase instances), not model instances, so model.ANONYMISE_AFTER is an in-memory __mro__ lookup on a class object.
  • ANONYMISE_AFTER is not a field and not a relation, so select_related() and prefetch_related() have nothing to act on.

This is the bit of code used to verify it:

  with CaptureQueriesContext(connection) as captured:
      for model in auditory_models():
          _ = model.ANONYMISE_AFTER
  assert len(captured.captured_queries) == 0

Sample models.py (minimized)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions