DEV Community

Cover image for Define Custom Query Sets in Model Managers for Code Reuse
Mangabo Kolawole
Mangabo Kolawole

Posted on

Define Custom Query Sets in Model Managers for Code Reuse

Django provides a great way to query your database with few lines of code and without writing SQL. However, there are some cases when you'll find yourself repeating the same piece of code logic in a project.🥶

Problem

Let's say we've added a new field to a model to create a public_id based on uuid4.

class Product(models.Model):
    public_id = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4, editable=False)
Enter fullscreen mode Exit fullscreen mode

Basically, this public_id will be used instead of the id of an object to perform CRUD actions.
Suppose that a user makes a request to retrieve a specific object in the database.
A solid logic will look like this:

public_id = kwargs.get("public_id")
try:
    product = Product.objects.get(public_id=public_id)
except ObjectDoesNotExist:
    raise Http404("Product does not exist")
Enter fullscreen mode Exit fullscreen mode

Simple logic right here, until you are adding other models to your project that use the same public_id field and you find yourself repeating the same piece of code logic.

Solution

Custom model managers allow developers to write extra methods for a model.

Returning to the example, let's create a custom Manager class for the Product model.

class ProductManager(models.Manager):
    def get_object_by_public_id(self, public_id):
        try:
            instance = self.get(public_id=public_id)
            return instance
        except ObjectDoesNotExist as e:
            raise e

class Product(models.Model):
    public_id = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4, editable=False)

    objects = ProductManager()
Enter fullscreen mode Exit fullscreen mode

And when retrieving an object, the code will simply be:

public_id = kwargs.get("public_id")

product = Product.objects.get_object_by_public_id(public_id)
Enter fullscreen mode Exit fullscreen mode

If you have other models in the database, let's suppose a Shop model or a User model with also a public_id field. We can write an AbstractManager class.

class AbstractManager(models.Manager):
    def get_object_by_public_id(self, public_id):
        try:
            instance = self.get(public_id=public_id)
            return instance
        except (ObjectDoesNotExist, ValueError, TypeError) as e:
            raise e

class ShopManager(AbstractManager):
    pass

class ProductManager(AbstractManager):
    pass

class Product(models.Model):
    public_id = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4, editable=False)

    objects = ProductManager()

class Shop(models.Model):
    public_id = models.UUIDField(db_index=True, unique=True, default=uuid.uuid4, editable=False)

    objects = ShopManager()

product = Product.objects.get_object_by_public_id(public_id)
shop = Shop.objects.get_object_by_public_id(public_id)
Enter fullscreen mode Exit fullscreen mode

🚀🚀🚀

You can learn more about managers in the official documentation of Django.

Article posted using bloggu.io. Try it for free.

Discussion (0)