QuerySets & Filtering
QuerySets are lazy, chainable queries that the ORM turns into SQL.
Syntax
Model.objects.filter(field__lookup=value)A QuerySet is the result of a query. It is lazy — no SQL runs until you actually use the data — and chainable, so you can build up complex queries step by step.
Filter with field lookups using a double underscore, such as title__contains or created__year.
Example
from blog.models import Post
# Field lookups
Post.objects.filter(title__icontains="django")
Post.objects.filter(created__year=2026)
Post.objects.filter(views__gte=100)
# Chain, order and limit
recent = (Post.objects
.filter(published=True)
.exclude(title="")
.order_by("-created")[:5])When to use it
- A developer uses filter(author=user) to retrieve only the posts written by the logged-in user.
- A search feature uses filter(title__icontains=query) to perform a case-insensitive keyword search.
- A developer chains exclude() and order_by() on a queryset to sort and filter results in one expression.
More examples
Filter with field lookups
Uses field lookups like icontains and gte to filter querysets with flexible conditions.
from .models import Post
# Exact match
posts = Post.objects.filter(author__username="alice")
# Case-insensitive contains
results = Post.objects.filter(title__icontains="django")
# Date range
from datetime import date
recent = Post.objects.filter(published_at__gte=date(2024, 1, 1))Exclude and chain querysets
Chains exclude(), order_by(), select_related(), and slicing to build an efficient queryset.
# Exclude drafts, order by newest first
published = (
Post.objects
.exclude(draft=True)
.order_by("-published_at")
.select_related("author")
)[:10]Q objects for complex queries
Uses Q objects to combine filter conditions with OR logic, which .filter() alone cannot express.
from django.db.models import Q
# Posts by alice OR tagged 'django'
posts = Post.objects.filter(
Q(author__username="alice") | Q(tags__name="django")
)
Discussion