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:
Q(a=1) | Q(b=2) → a=1 OR b=2Q(a=1) & Q(b=2) → a=1 AND b=2 (same as filter(a=1, b=2))~Q(a=1) → NOT (a=1)You can mix Q objects with regular kwargs in the same .filter() call, but Q objects must come first.
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.
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.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."