← all lessons

dailyfeed · 2026-04-27 · djangoormqueries

Field lookups

The idea

In a Django queryset, the double underscore isn't just a quirk of Python names — it's a small query language. field__lookup=value maps to a SQL operator:

Lookup SQL
__exact (default) =
__lt, __lte, __gt, __gte <, <=, >, >=
__in IN (...)
__isnull IS NULL / IS NOT NULL
__icontains, __istartswith LIKE '%...%', case-insensitive
__date, __year, __month DATE(col) = ..., etc.
__regex, __iregex regex match

The double underscore also crosses ForeignKey relations: Story.objects.filter(feed__user=request.user) joins through feed to filter on the related user.

How it shows up

This PR uses three lookups close together:

Q(next_check_at__isnull=True) | Q(next_check_at__lte=current)   # IS NULL / <=
Story.objects.filter(feed__user=user, published_at__date=digest_date)  # join + DATE()

Joining across a relation and truncating a date in one filter is what makes the ORM feel powerful — the SQL underneath is far from simple.

Read more

Exercises

  1. Read the SQL — pick any non-trivial queryset in this repo, run it in manage.py shell, and print str(qs.query) to see the generated SQL. Note which lookups produced which clauses. Done when: you've matched at least three __lookups to their SQL counterparts in your own code.
  2. Span a relation — write a query that finds all UserFeeds belonging to staff users (user__is_staff=True). Done when: the queryset returns the right rows in shell.

My notes