Search code examples
pythondjangodjango-managers

What functions do the order of Django Managers affect?


So, I've read most of the docs and I've been looking around on SO a bit, but I can't quite find the answer to my question. I'll start with the code.

# Manager
class ActiveManager(models.Manager):
    def get_query_set(self):
        return super(ActiveManager, self).get_query_set().filter(is_active=True)
# Model
class ModelA(models.Model):
    # ...
    is_active = models.BooleanField()
    objects = ActiveManager()
    all_objects = models.Manager()

So, while I was playing around I noticed that if I wrote it this way and used get_object_or_404(), then it would use the ActiveManager to first search for all active records and then return the one related to my query. However, if I switched the order of the managers:

class ModelA(models.Model):
    # ...
    all_objects = models.Manager()
    objects = ActiveManager()

Then it uses the default manager, in this case all_objects, to do the query. I'm wondering what other functions does this change impact.

EDIT: I understand that the first manager found in the class becomes the default manager, but I'm wondering which specific functions use this default manager (like get_object_or_404)


Solution

  • Here's the relevant bit from the docs: "If you use custom Manager objects, take note that the first Manager Django encounters (in the order in which they're defined in the model) has a special status. Django interprets the first Manager defined in a class as the "default" Manager, and several parts of Django (including dumpdata) will use that Manager exclusively for that model. As a result, it's a good idea to be careful in your choice of default manager in order to avoid a situation where overriding get_query_set() results in an inability to retrieve objects you'd like to work with".

    If you look at the way get_object_or_404 is implemented, they use the _default_manager attribute of the model, which is how Django refers to the first manager encountered. (As far as I know, all Django internals work this way -- they never use Model.objects etc. because you shouldn't assume the default manager happens to be called objects).