SyntaxStudy
Sign Up
Django Django ORM Queries and Managers
Django Beginner 1 min read

Django ORM Queries and Managers

Django's ORM provides a powerful QuerySet API for retrieving and manipulating database records. Every model class has a default manager accessed as Model.objects. You use this to build QuerySets — lazy database queries that are only executed when the data is actually needed. Common operations include filter(), exclude(), get(), all(), order_by(), values(), annotate(), and aggregate(). QuerySets support chaining, so you can build complex queries incrementally. For example, Post.objects.filter(status='published').order_by('-published_at')[:10] retrieves the ten most recent published posts. Django translates this chain into a single optimised SQL query. The select_related() and prefetch_related() methods are essential for avoiding N+1 query problems when working with related objects. Custom managers let you encapsulate commonly used QuerySets. By defining a class that inherits from models.Manager and adding it to your model, you can expose query shortcuts like Post.published.all() or Post.published.recent(). This keeps query logic in the model layer rather than scattered across views, improving maintainability and testability.
Example
# blog/models.py — custom manager + ORM query examples
from django.db import models
from django.utils import timezone


class PublishedManager(models.Manager):
    """Return only published posts."""
    def get_queryset(self):
        return super().get_queryset().filter(status=Post.STATUS_PUBLISHED)

    def recent(self, count=10):
        return self.get_queryset().order_by('-published_at')[:count]


class Post(models.Model):
    STATUS_DRAFT     = 'draft'
    STATUS_PUBLISHED = 'published'
    STATUS_CHOICES   = [(STATUS_DRAFT, 'Draft'), (STATUS_PUBLISHED, 'Published')]

    title        = models.CharField(max_length=200)
    body         = models.TextField()
    status       = models.CharField(max_length=10, choices=STATUS_CHOICES, default=STATUS_DRAFT)
    published_at = models.DateTimeField(null=True, blank=True)

    objects   = models.Manager()   # default manager
    published = PublishedManager() # custom manager

    class Meta:
        ordering = ['-published_at']


# --- ORM usage examples (e.g. in a view or shell) ---

# All published posts
posts = Post.published.all()

# Filter + chain
recent = Post.published.filter(published_at__year=2024).order_by('-published_at')

# Avoid N+1: fetch author in same query
from .models import Post
posts = Post.published.select_related('author', 'category').recent(5)

# Aggregate
from django.db.models import Count
stats = Post.objects.values('status').annotate(total=Count('id'))