Back
Jul 1, 2010

Overriding QuerySet in Django

Vladimir Sidorenko
Vladimir Sidorenko

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 (publishedin 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 - publishedand 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 getattris 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)

       # Теперь можно писать просто:
       # 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.

More thoughts

Jun 14, 2017Technology
How to Deploy a Django Application on Heroku?

In this article I'll show you how to deploy Django with Celery and Postgres to Heroku.

Vladimir Kalyuzhny
Vladimir Kalyuzhny
Nov 6, 2021Technology
Top 5 Restful API Design Best Practices

Learn about RESTful API design best practices with helpful developer tips

Vladimir Sidorenko
Vladimir Sidorenko
Mar 6, 2010Technology
Ajax form validation

There was a task to submit form with ajax, with server side validation of course. Obvious solution is to do validation and return json with erros. I didn't like idea of writing separate view for validation and then inserting errors in form html on client side. Especially since I already had a generic template for django form with errors display. In this article I'll describe how I solved the task.

Vladimir Sidorenko
Vladimir Sidorenko
Sep 1, 2021TechnologyBusiness
Top 10 Web Development Frameworks in 2021 - 2022

We have reviewed the top web frameworks for server and client-side development and compared their pros and cons. Find out which one can be a great fit for your next project.

Marina Sharapova
Marina Sharapova
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.

Vladimir Kalyuzhny
Vladimir Kalyuzhny
Feb 18, 2010Technology
Absolute urls in models

Everybody knows about permalink, but it's usually used only in get_absolute_url. I prefer to use it for all related model urls.class Event(models.Model):# [email protected] edit_url(self):return ('event_edit', (self.pk, ))And then in template:<a href="{{ event.edit_url }}">Редактировать событие</a>

Vladimir Sidorenko
Vladimir Sidorenko