Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Adding to the "constructor" of a django model

I want to do an extra initalization whenever instances of a specific django model are created. I know that overriding __init__ can lead to trouble. What other alternatives should I consider?

Update. Additional details: The intent is to initialize a state-machine that the instances of that model represent. This state-machine is provided by an imported library, and it's inner state is persisted by my django-model. The idea is that whenever the model is loaded, the state machine would be automatically initialized with the model's data.

like image 819
Filipe Correia Avatar asked Feb 23 '12 15:02

Filipe Correia


2 Answers

Overriding __init__ might work, but it's bad idea and it's not the Django way.

The proper way of doing it in Django is using signals.

The ones that are of interest to you in this case are pre_init and post_init.

django.db.models.signals.pre_init

Whenever you instantiate a Django model, this signal is sent at the beginning of the model’s __init__() method.

django.db.models.signals.post_init

Like pre_init, but this one is sent when the __init__(): method finishes

So your code should be something like

from django.db import models
from django.db.models.signals import post_init

class MyModel(models.Model):
  # normal model definition...

def extraInitForMyModel(**kwargs):
   instance = kwargs.get('instance')
   do_whatever_you_need_with(instance)

post_init.connect(extraInitForMyModel, MyModel)

You can as well connect signals to Django's predefined models.

like image 146
vartec Avatar answered Nov 06 '22 06:11

vartec


While I agree that there often is a better approach than overriding the __init__ for what you want to do, it is possible and there might be cases where it could be useful.

Here is an example on how to correctly override the __init__ method of a model without interfering with Django's internal logic:

from django.db import models

class Book(models.Model):
    title = models.CharField(max_length=100)

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        # add your own logic

like image 38
Erik Kalkoken Avatar answered Nov 06 '22 06:11

Erik Kalkoken