paint-brush
How to Make Things Less Complicated With Django Model Managersby@simplifiedweb
259 reads

How to Make Things Less Complicated With Django Model Managers

by Dev MehtaFebruary 23rd, 2023
Read on Terminal Reader
Read this story w/o Javascript
tldt arrow

Too Long; Didn't Read

In this article, we will learn about django model managers. A manager manages a set of models and a model is just a row in that table. By default, Django adds a `Manager` with name `objects` to every Django model class. However, if you want to use ` objects` as a field name, or if you. want to define a name for the `Manager, you can rename it on. that class. For example, if I wanted all posts to start with how_to, I could use a manager that starts with how to.
featured image - How to Make Things Less Complicated With Django Model Managers
Dev Mehta HackerNoon profile picture

In this article, we will learn about Django model managers. Recently, when I was scrolling through the r/django Reddit community, I was excited to help other Django developers solve their errors.


I went through some posts and read the problems to get started, and I found the first problem I liked to solve.


The problem was “I would like to apply logic to my apps by having methods written in models.py. What is the best way to go about this? The documentation is great for the basics but I am getting frustrated when working to apply business logic outside of views.py. Any good resources on this type of flow? Business Logic in models.py?


You may have faced this frustration too sometimes because Django is a robust framework for perfectionists with deadlines; it expects us to figure this out ourselves (Or, so I thought because this question was very well covered in the documentation, which, if you’re like me, you might not have read it).


So, I gave them the solution that I generally use to write repetitive or common Django filter queries in the models.py file where you define your models, like this:


from  django.db import models

class Post(models.Model):
    title = models.CharField(max_length=70)
    # ...
    
    def get_howto_guides(self):
        return Post.objects.filter(title__istartswith="how to")


At first, I didn't see anything wrong with this. I was still learning and trying to make things work. But soon, people on Reddit pointed out that this approach was not optimal, and that the best place for this is the manager.


A manager manages a set of models (so basically, an SQL table), and a model is just a row in that table (it shouldn't know about other rows). And boy, I was embarrassed.


I soon realized that as our codebase will grow, our models will become bloated with business logic that was better suited to our model managers.


It wasn't until I stumbled across the concept of model managers that I realized there was a better way to organize my code(If you use Reddit, join r/django. You will learn so many new things daily).


Model managers, I learned, are a way to encapsulate model-level operations and queries in a clean and modular way.

How to Do It


By default, Django adds a Manager with the name objects to every Django model class. However, if you want to use objects as a field name, or if you want to use a name other than objects for the Manager, you can rename it on a per-model basis.


To rename the Manager for a given class, define a class attribute of type models.Manager() on that model. For example:


from django.db import models

class Post(models.Model):
    # ...
    how_to = models.Manager()


Here, Post.how_to will generate an AttributeError , while Post.how_to.all() returns all the objects from that manager.


Now, I can fit all my business logic about “How to Guide Posts” in my how_to model manager. For example, if I wanted all the posts that start with How to, or are basically how-to-do-x type of articles, I will write the following model manager separately for those kinds of posts.


from django.db import models

class HowtoPostsManager(models.Manager):
    def get_queryset(self):
        return super().get_queryset().filter(title__istartswith="how to")
        # istartswith lookup field is used to
        # lookup case-insensitive titles.
        
class Post(models.Model):
    # ...
    objects = models.Manager() # Default Manager
    how_to = models.HowtoPostsManager() # our custom manager


Now, Post.objects.all() will return all the posts from the database, while Post.how_to.all(), will return only posts whose title starts with “How to”.


This example also pointed out another interesting technique: using multiple managers on the same model. You can attach as many Manager() instances to a model as you’d like. This is a non-repetitive way to define common “filters” for your models.

QuerySets as Model Managers

You can also define common filters as model managers in your Django models. For example:

from django.db import models

class HowtoQuery(models.QuerySet):
    def title_starts_with_howto(self):
        return self.filter(title__istartswith="how to")
        
class Post(models.Model):
    # ...
    objects = models.Manager() # Default Manager
    how_to = HowtoQuery.as_manager() # our custom manager

# This will be identicle to the previous code example,
# we looked at


Not every QuerySet method makes sense at the Manager level; for instance django prevents the QuerySet.delete() method from being copied onto the Manager class.


With model managers, I could write custom methods for my models that handled complex logic, filtering, and aggregation. I could also create new querysets that were specific to my application's needs which made it easier to reuse code across my views.


As I started to use model managers more in my applications, I found that my code was becoming cleaner and easier to read. I could also remove a lot of code from my models and keep my business logic closer to where it belonged.


In retrospect, it's hard to believe that I didn't know about model managers even after coding in Django for a considerable amount of time.


But I'm grateful that I came across this concept when I did, as it completely transformed the way I wrote code and helped me to become a better Django developer.


So, to anyone who is struggling with complex views and a messy codebase, I highly recommend exploring the power of model managers in Django. You might be surprised by how much they can simplify your code and improve your overall development experience.


Also published here