[Django]-Django auto_now behaviour

9πŸ‘

βœ…

In Django, you have auto_now and auto_now_add both.

From the docs:

DateField.auto_now

Automatically set the field to now every time the object is saved. (which means when it is first created too)

DateField.auto_now_add

Automatically set the field to now when the object is first created.

Edit:

If you want your updated_at field to be null when the object is first created, you can simply pass null=True alongside with auto_now=True to the DateTimeField:

class MetaData(models.Model):
    # ...
    updated_at = models.DateTimeField(auto_now=True, null=True)
    # ...
πŸ‘€wencakisa

1πŸ‘

There is also another way to do that. It is better to do what wencakisa recommended, unless you are using save method within your model.

As it is written in the documentation

The field is only automatically updated when calling Model.save(). The
field isn’t updated when making updates to other fields in other ways
such as QuerySet.update(), though you can specify a custom value for
the field in an update like that.

So, even if you use auto_now, but call save method for example to generate a slug address, the time will be assigned to the field with auto_now when the object is created.

How to handle such situation and keep the field updated_at with a null value after creation and before update?

For example, if you are using an UpdateView, assign the time there in a form_valid method.

models.py

class MetaData(models.Model):
    created_at = models.DateTimeField(auto_now_add=True, auto_now=False)
    created_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True,
                                   related_name='%(app_label)s_%(class)s_created_by')
    updated_at = models.DateTimeField(null=True)
    updated_by = models.ForeignKey(settings.AUTH_USER_MODEL, blank=True, null=True,
                                   related_name='%(app_label)s_%(class)s_updated_by')

    def save(self, *args, **kwargs):
        # SOMETHING HERE
        super().save(*args, **kwargs)

views.py

class UpdateMetaData(generic.UpdateView):
    # SOMETHING HERE

    def form_valid(self, form):
        self.object = form.save(commit=False)
        self.object.updated_at = timezone.now()
        self.object.save()
        return super().form_valid(form)

You should have null value for updated_at after creation and the right time value after update of the field.

I think that in the same way you can also assign the update author to updated_by.

πŸ‘€Jakub Siwiec

Leave a comment