Overriding get() method in models

Given the poll app example in the Django tutorial. You can perform a get operation to fetch poll questions from the database.

In : Question.objects.get(pk=1)
Out: <Question: Question object>

This blog post shows how to override that method. It is not on the model itself. Question.objects gives you the manager.

In : Question.objects
Out: <django.db.models.manager.Manager at 0x10d3b8860>

You can drop in a custom manager in your models.py.

class QuestionManager(models.Manager):
    pass

class Question(models.Model):
    objects = QuestionManager()

which results in...

In : Question.objects
Out: <app.models.QuestionManager at 0x107456e48>

But we are not quite there yet. Question.objects.get is doing some delegation magic and actually calling get on an instance of QuerySet. We can replace

class QuestionQuerySet(models.query.QuerySet):
    def get(self, **kwargs):
        print('hello world')
        return super().get(**kwargs)

class QuestionManager(models.Manager.from_queryset(QuestionQuerySet)):
    pass

Voilà!

In : Question.objects.get(pk=1)
hello world
Out: <Question: Question object>

References:

  • https://docs.djangoproject.com/en/1.10/topics/db/managers/#from-queryset
  • https://docs.djangoproject.com/en/1.10/ref/models/querysets/#get

Note that more modern Django versions (since 1.7), provide an easier way to do this. Check out the as_manager() QuerySet method.

https://docs.djangoproject.com/en/2.2/topics/db/managers/#creating-a-manager-with-queryset-methods


get isn't a method on the model - you access it via objects, so it's a method on the Manager. See the official Manager documentation.

The way you have defined the method signature, the request is available as args[0].