Django Custom Queryset vs Custom Manager for Database queries

Note: this applies to Django >= 1.7

From the docs:

A Manager is the interface through which database query operations are provided to Django models. At least one Manager exists for every model in a Django application.

There are two reasons you might want to customize a Manager: to add extra Manager methods, and/or to modify the initial QuerySet the Manager returns.

Since Django 1.7 and onwards, we no longer need to create custom manager and custom queryset separately. We can turn custom queryset into manager like so.
objects = EcomProductQuerySet.as_manager()

Custom Queryset is a way to simplify the database queries. For example if we have a database model like so:

from django.db import models
import os
import random

def get_filename_ext(filepath):
    base_name = os.path.basename(filepath)
    name, ext = os.path.splitext(base_name)
    return name, ext

def upload_image_path(instance, filename):
    new_filename = random.randint(1,348753947539457)
    name, ext = get_filename_ext(filename)
    final_filename = f'{new_filename}{ext}'
    return f'ecom_products/{new_filename}/{final_filename}'


class EcomProductQuerySet(models.query.QuerySet):
    def get_by_id(self, id):
        qs = self.filter(id=id)
        if qs.count() == 1:
            return qs.first()
        return None
    
    def featured(self):
        return self.filter(featured=True)

    def active(self):
        return self.filter(active=True)


class EcomProduct(models.Model):
    title = models.CharField(max_length=100)
    description = models.TextField(null=False, blank=False)
    price = models.DecimalField(decimal_places=2, max_digits=10, null=False, blank=False, default=1.00)
    image = models.ImageField(upload_to=upload_image_path, null=True, blank=True)
    featured = models.BooleanField(default=False)
    active = models.BooleanField(default=True)

    # objects = EcomProductManager()
    objects = EcomProductQuerySet.as_manager()

    def __str__(self):
        return self.title

Here, I could have used EcomProduct.objects.filter(featutred=True) to get only the featured products. Instead, we created a method in custom queryset called featured. Now we can get the featured products like so:
EcomProduct.objects.featured(). This might be a trivial example, but this concept really makes a difference in larger queries.

Query Chaining

Another excellent feature of a queryset is its ability to chain. An example of it is here. In the listview, we create a queryset that only shows “featured” items AMONGST “active” items. These chains can be arbitrarily long.

class EcomProductFeaturedListView(ListView):
    queryset = EcomProduct.objects.active().featured()
    template_name = 'ecom_product/list.html'

Note that we could have made this particular query like so (without any custom querysets), but using these custom querysets makes our queries look more DRY and cleaner.

EcomProduct.objects.filter(active=True, featured=True)
Tek Shinobi
Author: Tek Shinobi

Hiya Ninjas, I am the ninja who invented the fire, wheel, science, technology and everything intelligent this humanity has ever experienced since its evolution from monkeys and germs. Actually, above is a partial list. I also was involved with the Big Bang that created this universe. What was it like before the Big Bang is so secret that if I tell you, I will have to turn you into a hobbit and force you to be my gardener. Okay. Sayonanra, Namaste Tek Shinobi




No Comments


You can leave the first : )



Leave a Reply

Your email address will not be published. Required fields are marked *