← all lessons

dailyfeed · 2026-04-27 · djangoormqueries

Q objects

The idea

filter(a=1, b=2) always means a=1 AND b=2. There's no kwarg syntax for OR. To express OR, NOT, or anything more complex than "all of these", wrap each clause in Q(...) and combine with Python's bitwise operators:

You can mix Q objects with regular kwargs in the same .filter() call, but Q objects must come first.

How it shows up

crawl_feeds needs feeds where next_check_at is unset or in the past:

from django.db.models import Q

UserFeed.objects.filter(
    Q(next_check_at__isnull=True) | Q(next_check_at__lte=current)
)

Without Q, you'd have to issue two queries and union them in Python — slower and clunkier.

Read more

Exercises

  1. Negate it — write a queryset that finds feeds that have errored but not yet recovered (last_error_at set AND last_success_at either NULL or earlier than last_error_at). Done when: the queryset runs in manage.py shell without error and returns the feeds you expect.
  2. Mix Q with kwargs — combine Q(...) | Q(...) with a user=request.user kwarg in the same .filter(). Confirm the kwarg ANDs with the OR group. Done when: you can articulate the order-of-operations rule: "Q objects first, kwargs second; kwargs are ANDed onto whatever the Q expression resolves to."