Define Custom Query Sets in Model Managers for Code Reuse

Define Custom Query Sets in Model Managers for Code Reuse

ยท

2 min read

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)

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")

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()

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)

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)

๐Ÿš€๐Ÿš€๐Ÿš€

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

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