How to Update Django Model Field Without Invoking Model Validation and model field logic (e.g. auto_now)

There are usecases where we want to update a field in Django model but don't want to invoke model validations.

Suppose we have User model and we want to update the last_seen field for a particular user. We also have a modified_at field which gets auto updated whenever the model's save method is called.

1
2
3
4
5
6
7

class User(models.Model):
    name = models.CharField(max_length=50)
    last_seen = models.DateTimeField(null=True, blank=True, default=None)
    created_at = models.DateTimeField(auto_now_add=True)
    modified_at = models.DateTimeField(auto_now=True)

if we update the last_seen field, the modified_at field gets auto updated

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16

>>> u = User.objects.get(id=1)
>>> u.last_seen
datetime.datetime(2021, 1, 17, 13, 5, 33, 57169, tzinfo=<UTC>)
>>> u.modified_at 
datetime.datetime(2021, 1, 17, 13, 5, 33, 69221, tzinfo=<UTC>)

>>> u.modified_at = timezone.now()
>>> u.save()

>>> u = User.objects.get(id=1)
>>> u.last_seen
datetime.datetime(2021, 1, 17, 13, 8, 58, 963775, tzinfo=<UTC>)
>>> u.modified_at
datetime.datetime(2021, 1, 17, 13, 8, 58, 964039, tzinfo=<UTC>)

Now, we will use the update_fields option to update only selected field in model.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17

>>> u = User.objects.get(id=1)
>>> u.last_seen
datetime.datetime(2021, 1, 17, 13, 8, 58, 963775, tzinfo=<UTC>)
>>> u.modified_at
datetime.datetime(2021, 1, 17, 13, 8, 58, 964039, tzinfo=<UTC>)
>>> u.last_seen = timezone.now()
>>> u.save(update_fields=['last_seen'])

>>> u = User.objects.get(id=1)
>>> u.last_seen = timezone.now()
>>> u = User.objects.get(id=1)
>>> u.last_seen
datetime.datetime(2021, 1, 17, 13, 14, 17, 541996, tzinfo=<UTC>)
>>> u.modified_at
datetime.datetime(2021, 1, 17, 13, 8, 58, 964039, tzinfo=<UTC>)

As seen above, only last_seen field gets update and our save() method code is not executed.