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
Feb 3, 2025Technology
Figma for Developers: What Dev Mode Offers and How to Use It

This article explores Figma’s Dev Mode, a tool that streamlines design-to-code translation by enabling precise inspection, automated code generation, and seamless integration with design systems.

Jun 27, 2018Technology
How to Work With Legacy Code: Code Refactoring Techniques

In this article we'll review general approach to working with the best kind of projects - the ones with old untested and undocumented spaghetti code and a tight schedule. We'll review anger management techniques, coping mechanisms and some refactoring tips that might come in handy.

May 9, 2018Technology
How to Generate PDF Files in Python with Xhtml2pdf, WeasyPrint or Unoconv

Programmatic generation of PDF files is a frequent task when developing applications that can export reports, bills, or questionnaires. In this article, we will consider three common tools for creating PDFs, including their installation and converting principles.

May 26, 2017Technology
Tutorial: Django User Registration and Authentication

In this beginners friends article I'll explain how to make authentication with Google account on your Django site and how to make authentication for you REST API.

Dec 1, 2016Technology
How to Use Django & PostgreSQL for Full Text Search

For any project there may be a need to use a database full-text search. We expect high speed and relevant results from this search. When we face such problem, we usually think about Solr, ElasticSearch, Sphinx, AWS CloudSearch, etc. But in this article we will talk about PostgreSQL. Starting from version 8.3, a full-text search support in PostgreSQL is available. Let's look at how it is implemented in the DBMS itself.

Sep 23, 2010Technology
Dynamic class generation, QuerySetManager and use_for_related_fields

It appears that not everyone knows that in python you can create classes dynamically without metaclasses. I'll show an example of how to do it.So we've learned how to use custom QuerySet to chain requests:Article.objects.old().public()Now we need to make it work for related objects:user.articles.old().public()This is done using use_for_related_fields, but it needs a little trick.