Skip to main content

Ordering & Pagination

Control the sort order and size of your result sets.

Ordering

# Ascending
await Post.objects.order_by("title")

# Descending (prefix with -)
await Post.objects.order_by("-views")

# Multiple fields
await Post.objects.order_by("-views", "title")

# Default ordering from Meta
class Post(Model):
class Meta:
ordering = ["-created_at"] # Applied automatically

Limit & Offset

# First 10
await Post.objects.limit(10)

# Skip 20, take 10
await Post.objects.limit(10).offset(20)

Slicing

QuerySets support Python slice syntax:

# First 10
await Post.objects.all()[:10]

# Page 2 (items 10-19)
await Post.objects.all()[10:20]

# Single item by index
third = await Post.objects.all()[2]
warning

Negative indexing (qs[-1]) is not supported — use .order_by().first() instead.

Pagination Pattern

async def paginate(queryset, page: int = 1, per_page: int = 20):
offset = (page - 1) * per_page
items = await queryset.limit(per_page).offset(offset)
total = await queryset.count()
return {
"items": items,
"total": total,
"page": page,
"pages": (total + per_page - 1) // per_page,
}

# Usage
result = await paginate(Post.objects.filter(active=True), page=2, per_page=10)

Distinct

# SELECT DISTINCT
await Post.objects.filter(active=True).distinct()

Next Steps

Aggregations — Count, Sum, Avg, and more