[Django]-Override save method for every class in models.Model

5πŸ‘

βœ…

Your base model must be abstract:

class LogModel(models.Model):

    class Meta:
        abstract = True

    created = models.DateTimeField(editable=False)
    updated = models.DateTimeField()

    def save(self, force_insert=False, force_update=False, using=None, update_fields=None):
        # Use self._state.adding to check if this is a new instance,
        # ID not being empty is not a guarantee that the instance
        # exists in the database
        # and if `update_fields` is passed, you must add the fields to the
        # list or they won't be saved in the database.
        if force_insert or self._state.adding:
            self.created = timezone.now()
            if update_fields and 'created' not in update_fields:
                update_fields.append('created')
        self.updated = timezone.now()
        if update_fields and 'updated' not in update_fields:
            update_fields.append('updated')
        return super(LogModel, self).save(*args, **kwargs)

However, if you override the save() method, this means it won’t be editable in any form. If this is what you want, then you are better to use auto_now and auto_now_add:

class LogModel(models.Model):

    class Meta:
        abstract = True

    created = models.DateTimeField(auto_now_add=True)
    updated = models.DateTimeField(auto_now=True)

1πŸ‘

Instead of overriding save method, you could define auto_now_add and auto_now parameters in the Model field like:

created = models.DateTimeField(auto_now_add=True)
updated = models.DateTimeField(auto_now=True)

For more information on these parameters, you can check the django docs.

1πŸ‘

It can be done by defining Abstract Base Model and define save method there and create all the models by inheriting from the abstract class. e.g.

class MyAbstractModel(models.Model):
    created = models.DateTimeField(editable=False)
    updated = models.DateTimeField()

    def save(self, *args, **kwargs):
        if self._state.adding:
            self.created = timezone.now()
        self.updated = timezone.now()
        return super(LogModel, self).save(*args, **kwargs)

    class Meta:
        abstract = True

and create child model class from it:

class Record(MyAbstractModel):
    pass

0πŸ‘

Unfortunately, using update_fields in .save() does not trigger fields with auto_now, so I overridden save method this way:

class BaseModel(models.Model):
    class Meta:
        abstract = True

    created_at = models.DateTimeField(auto_now_add=True)
    updated_at = models.DateTimeField(auto_now=True)

    _base_update_fields = ['updated_at']

    def save(
        self, force_insert=False, force_update=False,
        using=None, update_fields=None
    ):
        _update_fields = None

        if update_fields is not None:
            _update_fields = self._base_update_fields + update_fields

        super().save(
            force_insert=force_insert, force_update=force_update,
            using=using, update_fields=_update_fields
        )
πŸ‘€Ersain

Leave a comment