Managers and QuerySets
1. What are Managers in Django?
A manager in Django is the interface through which database query operations are provided to Django models. Every model in Django has at least one manager, and by default, Django provides a Manager
object called objects
.
a. Default Manager
By default, every model has a manager named objects
, which allows you to interact with the model’s database records.
# Example model
class Book(models.Model):
= models.CharField(max_length=100)
title = models.CharField(max_length=100)
author = models.DateField()
published_date
# Using the default manager to query the database
= Book.objects.all() # Retrieves all books
books = Book.objects.get(id=1) # Retrieves a specific book by ID book
b. Custom Manager
You can create a custom manager to encapsulate logic specific to your model, allowing for more readable and reusable code.
# Custom manager
class BookManager(models.Manager):
def published_last_year(self):
= timezone.now().year - 1
last_year return self.filter(published_date__year=last_year)
# Using a custom manager
class Book(models.Model):
= models.CharField(max_length=100)
title = models.CharField(max_length=100)
author = models.DateField()
published_date
= BookManager() # Use the custom manager
objects
# Using the custom manager method
= Book.objects.published_last_year() last_year_books
2. Creating Custom Managers
Django allows you to define custom managers to encapsulate common queries, making your code more modular and readable. A custom manager can be defined by subclassing models.Manager
.
a. Basic Custom Manager
class PublishedBookManager(models.Manager):
def get_queryset(self):
# Override the default get_queryset method to return only published books
return super().get_queryset().filter(published_date__isnull=False)
# Using the custom manager in a model
class Book(models.Model):
= models.CharField(max_length=100)
title = models.CharField(max_length=100)
author = models.DateField()
published_date
# Define two managers: a default manager and a custom manager
= models.Manager() # Default manager
objects = PublishedBookManager() # Custom manager for published books published
In this example: - Book.objects.all()
will return all books. - Book.published.all()
will return only books that have a published_date
.
b. Multiple Managers
You can define multiple managers in a single model to access different sets of query logic.
class Book(models.Model):
= models.CharField(max_length=100)
title = models.CharField(max_length=100)
author = models.DateField()
published_date
# Default and custom managers
= models.Manager() # Default manager
objects = PublishedBookManager() # Custom manager published
3. Querying Methods
1. Basic Retrieval and Querying Methods
all()
: Retrieves all records from the database for that model.filter(**kwargs)
: Returns a newQuerySet
containing objects that match the given lookup parameters.exclude(**kwargs)
: Returns a newQuerySet
that excludes objects that match the given lookup parameters.get(**kwargs)
: Returns a single object matching the given lookup parameters. RaisesDoesNotExist
if no object is found andMultipleObjectsReturned
if more than one object matches.first()
: Returns the first object in theQuerySet
, orNone
if theQuerySet
is empty.last()
: Returns the last object in theQuerySet
, orNone
if theQuerySet
is empty.
2. Aggregation and Counting
count()
: Returns the number of objects in theQuerySet
.aggregate(**kwargs)
: Returns a dictionary with the results of aggregating over theQuerySet
.
3. Existence Check
exists()
: ReturnsTrue
if theQuerySet
contains any results, andFalse
if it is empty.
4. Creation and Deletion
create(**kwargs)
: Creates and saves a new object, returning the created object.bulk_create(objs, batch_size=None, ignore_conflicts=False)
: Inserts multiple objects into the database in a single query.bulk_update(objs, fields, batch_size=None)
: Updates multiple objects in a single query.get_or_create(**kwargs)
: Retrieves an object matching the given lookup parameters. If no matching object is found, it creates a new one with the provided defaults.update_or_create(**kwargs)
: Updates an object matching the given lookup parameters, creating one if necessary.delete()
: Deletes all objects in theQuerySet
(returns the number of objects deleted and a dictionary with details).
5. Advanced Querying
raw(raw_query, params=None, translations=None)
: Executes a raw SQL query and returns aRawQuerySet
instance.extra(select=None, where=None, params=None, tables=None, order_by=None, select_params=None)
: Adds extra SQL fragments to the query (deprecated in Django 3.1+).
6. Date and Time Methods
dates(field_name, kind, order='ASC')
: Returns aQuerySet
of all available dates for the specified field.datetimes(field_name, kind, order='ASC', tzinfo=None)
: Returns aQuerySet
of all available datetimes for the specified field.
7. Distinct and Ordering
distinct()
: Returns a newQuerySet
with distinct results.order_by(*field_names)
: Orders theQuerySet
by the given fields.reverse()
: Reverses the order of theQuerySet
.
8. Optimization and Caching
select_related(*fields)
: Creates an SQL join and includes related objects in theQuerySet
.prefetch_related(*lookups)
: Performs a separate lookup for each relationship and joins them in Python, which is more efficient for many-to-many relationships.only(*fields)
: Loads only the specified fields.defer(*fields)
: Defers the loading of specified fields until they are accessed.
9. Union, Intersection, and Difference
union(*other_qs, all=False)
: CombinesQuerySet
objects using SQLUNION
.intersection(*other_qs)
: CombinesQuerySet
objects using SQLINTERSECT
.difference(*other_qs)
: CombinesQuerySet
objects using SQLEXCEPT
.
10. Boolean and None Operations
none()
: Returns an emptyQuerySet
.
11. Custom Managers
You can create your own custom manager by subclassing models.Manager
and adding custom methods:
class CustomManager(models.Manager):
def active(self):
return self.filter(active=True)
class MyModel(models.Model):
= models.CharField(max_length=100)
name = models.BooleanField(default=True)
active
# Use the custom manager
= CustomManager() objects
12. Using Managers
# Using built-in manager methods
= MyModel.objects.all()
all_objects = MyModel.objects.filter(name__icontains="example")
filtered_objects
# Using a custom manager method
= MyModel.objects.active() active_objects
These methods make Django’s ORM powerful and flexible, allowing for easy and expressive database queries.
4. Manager Methods vs QuerySet Methods
- Manager Methods: Manager methods are useful when you want to return data that does not require chaining or modifying the base QuerySet.
- QuerySet Methods: QuerySet methods are ideal when you want to create reusable filtering logic that can be chained with other QuerySet methods.
When to Use Each:
- Use manager methods when the method represents an action that doesn’t require chaining (e.g., creating objects or counting objects).
- Use custom QuerySet methods when you want to filter or manipulate a set of results and keep the option of chaining other QuerySet methods.
5. Manager and QuerySet Best Practices
a. Keep Business Logic in Managers and QuerySets
Encapsulate complex queries or business logic inside custom managers and QuerySets to make your views and templates cleaner.
b. Use get_queryset()
Wisely
Always return a QuerySet
from the get_queryset()
method, as it allows you to further modify the query (e.g., chaining filters, ordering).
c. Leverage Lazy Evaluation
Django QuerySets are lazily evaluated, so you can build complex queries without immediately hitting the database. However, ensure queries are evaluated efficiently by minimizing unnecessary evaluations.
d. Avoid Logic in Views
Instead of placing filtering and querying logic in views, use custom managers or QuerySets to encapsulate and reuse this logic across your application.
e. Chaining Queries
When creating custom QuerySet methods, ensure they return a QuerySet so that you can continue to chain additional filters and operations.