Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Django : Does it make sense to override save method in a mixin?

I ask myself if it make sense to override save method in a mixin.

In my project I have, for good reasons, to override the save method in several models. At first, I have to create a custom model class which inherit from models.Model. However semantically, what I am doing is giving a role to a class (rather than defining an object in its own right), that's why I think it's better to write a mixin. An other reason is because we may use multiple inheritance in near future. On the over hand, this line in overriden save method :

super(MyMixin, self).save(*args, **kwargs)

does not make sens as it can only be used with a django.db.models.Model class.

class MyMixin(object):

    def save(self, *args, **kwargs):
        ...
        super(MyMixin, self).save(*args, **kwargs)
        ...

Could you help me decide the best choice ? (Mixin or custom model)

like image 538
fabien-michel Avatar asked Jan 11 '23 09:01

fabien-michel


1 Answers

The way the mro (method resolution order) works, both methods are perfectly valid. The abstract model case is quite simple: you have a single inheritance chain, and each call to super is called on the next class up in the chain. So if you have:

class MyBaseModel(models.Model):
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

class MyModel(MyBaseModel):
    def save(self, *args, **kwargs):
        super().save(*args, **kwargs)

The call in MyModel will propogate to MyBaseModel, and the call in MyBaseModel will propogate to models.Model.

With multiple inheritance, the inheritance chain is slightly different. The first class upwards in the inheritance chain is the first base class defined. So if you have class MyModel(MyMixin, models.Model), MyMixin will be the first class upwards. Next, when super() is called in MyMixin (with a MyModel instance), it will look for siblings of the MyMixin class. That means that the next method to be called is the save method on models.Model.

Considering this, it is perfectly fine to use a mixin to override the save methods. In both cases, the MyModel save method will be called first, then the mixin/abstract model's save method, and finally the models.Model save method.

Note:

This is a simplified explanation of the method resolution order that works in this specific case. The actual algorithm for determining the order is the C3 linearization algorithm. A complete explanation can be found here.

like image 58
knbk Avatar answered Jan 16 '23 21:01

knbk