Managers & QuerySets
Every model has a objects attribute — this is the Manager. It's your entry point to the database.
The Manager
Post.objects # → Manager
Post.objects.all() # → QuerySet (all posts)
Post.objects.filter(active=True) # → QuerySet (filtered)
The Manager proxies most calls to a QuerySet, but also provides convenience methods:
# Direct creation
post = await Post.objects.create(title="Hello", slug="hello")
# Get or create
post, created = await Post.objects.get_or_create(
slug="hello",
defaults={"title": "Hello"},
)
# Update or create
post, created = await Post.objects.update_or_create(
slug="hello",
defaults={"title": "Updated"},
)
# Bulk lookup
posts = await Post.objects.in_bulk([1, 2, 3])
# → {1: <Post pk=1>, 2: <Post pk=2>, 3: <Post pk=3>}
The QuerySet
A QuerySet is a lazy, chainable representation of a database query.
Lazy Evaluation
# Nothing hits the database yet
qs = Post.objects.filter(active=True).order_by("-views")
# NOW the query executes
posts = await qs
Immutability
Every QuerySet method returns a new QuerySet — the original is never modified:
base = Post.objects.all()
filtered = base.filter(active=True) # base is unchanged
ordered = base.order_by("-views") # base is still unsorted
Chainable API
posts = await (
Post.objects
.filter(active=True)
.exclude(title__startswith="Draft")
.order_by("-views", "title")
.limit(20)
.offset(40)
.distinct()
)
QuerySet Methods
Filtering
Post.objects.filter(active=True)
Post.objects.filter(views__gt=100)
Post.objects.filter(title__contains="Python")
Post.objects.exclude(status="draft")
Retrieval
post = await Post.objects.get(pk=1) # Raises DoesNotExist or MultipleObjectsReturned
post = await Post.objects.first() # Returns None if empty
post = await Post.objects.last() # Returns None if empty
Aggregation
stats = await Post.objects.aggregate(
total=Count("id"),
avg=Avg("views"),
)
posts = await Post.objects.values("author_id").annotate(
count=Count("id"),
total=Sum("views"),
)
Slicing
# First 10
first_ten = await Post.objects.all()[:10]
# Pagination
page_two = await Post.objects.all()[10:20]
# Single item by index
third = await Post.objects.all()[2]
Async Iteration
async for post in Post.objects.filter(active=True):
print(post.title)
Count & Exists
count = await Post.objects.filter(active=True).count()
exists = await Post.objects.filter(active=True).exists()
Update & Delete
# Bulk update
updated = await Post.objects.filter(active=False).update(active=True)
# Bulk delete
deleted = await Post.objects.filter(views=0).delete()
Sync/Aasync Bridge
Use Ryx from synchronous code:
from ryx import run_sync
# Blocks until query completes
posts = run_sync(Post.objects.filter(active=True))
post = run_sync(Post.objects.get(pk=1))
count = run_sync(Post.objects.count())
Next Steps
→ Filtering — Deep dive into lookups → Q Objects — OR, NOT, and complex expressions