ORM Lens

DOL005 — Consider Q(…) over .filter().exclude() chain

Default severity: hint · Applicability: suggestion · Category: queryset

Detects a .filter(...).exclude(...) chain on one line. The pair can usually collapse into a single .filter(Q(...) & ~Q(...)) — one expression that states the whole predicate instead of two chained calls the reader has to compose mentally. Both forms already compile to a single query, so this is about legibility, not speed. This is a hint, not an error: on multi-valued relations (spanning a ManyToManyField or reverse FK), .exclude(...) and ~Q(...) are not equivalent — .exclude() removes objects for which any related row matches, while ~Q filters per joined row. Review before rewriting; there is deliberately no QuickFix.

Bad

posts = Post.objects.filter(published=True).exclude(author=request.user)

Good

from django.db.models import Q

posts = Post.objects.filter(Q(published=True) & ~Q(author=request.user))

Suppress

# orm-lens-disable-next-line DOL005

Or per-workspace in .vscode/settings.json: {"djangoOrmLens.rules": {"DOL005": "off"}}.