DEV Community

Cover image for How ORM(Object-Relational Mapping) uses the descriptor protocol?
Sumit Roy
Sumit Roy

Posted on

How ORM(Object-Relational Mapping) uses the descriptor protocol?

Recap

(Nostalgia)
From my previous post, we understood what is descriptor protocol and how to use it in many cases. How to modify the .(dot) operator and changing behaviour while setting the value.

Coming to the point

You might have heard about Django, and also about how cool is it's ORM. You can define classes and that's it. It will handle all the complexities of the backend database.

You can declare tables as class, columns as class attributes and rows as objects of that class

# of course you need to import models of Django.
class User(models.Model):
    email = models.CharField(max_length=50)
    mobile = models.IntegerField()
...
Enter fullscreen mode Exit fullscreen mode

So this class will be treated as user table and entries in this table are basically objects of this class. To handle fetch, update and filter out queries Django uses manager. There is a default manager provided by Django but you can modify it.

class UserManager(models.Manager):
    def get_queryset(self):
...
# this will modify _filter_ behaviour.
Enter fullscreen mode Exit fullscreen mode

So all these cool features Djnago gives in its ORM and many more.

Some familiar instances

If you have used Django ORM or any other similar, you might have come across something like this

...
class Order(models.Model):
    user = models.ForeignKey(User)
...

Enter fullscreen mode Exit fullscreen mode

Now suppose we want to change any attribute_(say first_name)_ of a user via order instance. So we will have to do something like this

...
o.user.first_name = "Sumit"
...
Enter fullscreen mode Exit fullscreen mode

Here Django uses their famous ForwardManyToOneDescriptor to handle the reference. If you want to check more on this you can go to their source code

Few lines are here

if value is not None and not isinstance(value, self.field.remote_field.model._meta.concrete_model):
            raise ValueError(
                'Cannot assign "%r": "%s.%s" must be a "%s" instance.' % (
                    value,
                    instance._meta.object_name,
                    self.field.name,
                    self.field.remote_field.model._meta.object_name,
                )
            )
Enter fullscreen mode Exit fullscreen mode

It checks the type of value, whether it matches the instance of the related class or not.

Conclusion

So basically even though we don't use descriptor protocol in our day to day coding but this is one secret that the guys building the framework knows and it's a nice tool to have.

Liked my post?

Top comments (0)