Back
Jul 1, 2010

Overriding QuerySet in Django

As you know, model managers can be overriden in Django. It's convenient to add custom filtration method there:

Article.objects.published()
Article.objects.old()

But these custom methods cannot be chained:

Article.objects.published().old()

Overriding manager doesn't allow it, because after first manager method is invoked (published in this case), we receive queryset as a result, which knows nothing about custom manager methods. So we have to add custom methods to queryset. This can look like this:

class ArticleQuerySet(models.query.QuerySet):

    def published(self):
        return self.filter("...")

    def old(self):
        return self.filter("...")

Now we need to make manager user this class. In order to do this, let's override manager's get_query_set method:

class ArticleManager(models.Manager):

    def get_query_set(self):
        return ArticleQuerySet(self.model, using=self._db)


class Article(models.Model):
    # ...

    objects = ArticleManager()

This allows to make queties like:

Article.objects.all().published().old()

Here we invoke all to get queryset instance, because this time manager doesn't have custom methods - published and old. To avoid this, we can make manager look for undefined methods in queryset:

class ArticleManager(models.Manager):

    def get_query_set(self):
        return ArticleQuerySet(self.model, using=self._db)

    def getattr(self, key):
        return getattr(self.get_query_set(), key)

Note that getattr is only invoked when attribute is not found by usual means.

Manager can be further improved to be more generic:

class QuerySetManager(models.Manager):

    def init(self, queryset_class, args, **kwargs):
        self.queryset_class = queryset_class
        super(QuerySetManager, self).init(args, **kwargs)

    def get_query_set(self):
        return self.queryset_class(self.model, using=self._db)

    def getattr(self, key):
        return getattr(self.get_query_set(), key)


# Now you can simply write:
# objects = QuerySetManager(ArticleQuerySet)

 

Update

After article was published, I found out that this idea is not all that new and unique :)

It's funny that only after I implemented my own solution, I've managed to make correct search query.

Subscribe for the news and updates

More thoughts
Aug 18, 2022Technology
5 Best Practices of RESTful API Design to Keep Your Users Happy

Dive into our guide to RESTful API best practices

May 12, 2022Technology
Increasing performance by using proper query structure

Earlier in our previous article "Improve efficiency of your SELECT queries" we discussed ways to profile and optimize the performance of SELECT queries. However, to write complex yet efficient SQL queries, there is a thing to remember about.

Apr 19, 2022Technology
Improve efficiency of your SELECT queries

SQL is a fairly complicated language with a steep learning curve. For a large number of people who make use of SQL, learning to apply it efficiently takes lots of trials and errors. Here are some tips on how you can make your SELECT queries better. The majority of tips should be applicable to any relational database management system, but the terminology and exact namings will be taken from PostgreSQL.

Jan 22, 2017Technology
Django vs Rails Performance

This article is aimed for beginners, who are trying to choose between Ruby on Rails and Django. Let’s see which is fastest and why.

Aug 31, 2016Technology
Angular vs React Comparison

In this article, we will compare two most popular JS Libraries (Angular vs React). Both of them were created by professionals and have been used in famous big projects.

Aug 8, 2016TechnologyBusiness
How To Add HTML5 Geolocation To Your Web App?

In this article I will describe how to integrate geolocation HTML5 function to a web app so you can then easily implement it in your apps or websites. As an example we are going to create small web app which will be able to calculate the shortest route between detected user’s location and predefined destination using Google Maps API.