Django: Use auto_now and auto_now_add Correctly — When to Switch to default=timezone.now
Most Django models have two timestamp fields: created_at to know when a record was created and updated_at for the last edit. The quickest way is auto_now_add=True for created_at and auto_now=True for updated_at — Django fills in both and you never touch them. But these two options have three common "traps": you can't assign an old date when importing data, bulk update() doesn't change updated_at,…
Django models commonly include two timestamp fields: created_at to indicate when a record was generated, and updated_at for the most recent modification. The simplest method is utilizing auto_now_add=True for created_at and auto_now=True for updated_at, with Django automatically populating both values. However, there are three typical pitfalls to be aware of.
When importing 500 previous blog posts and wishing to preserve their initial publication dates, creating a Post object with a predetermined created_at value does not retain the original date. This happens because auto_now_add only executes during the creation process, overwriting any values passed during the create() operation with timezone.now().
A second issue arises during bulk updates. Altering the status of 1,000 posts to published doesn't update the updated_at field of all posts. This is due to QuerySet.update() running SQL directly, bypassing the save() method, so auto_now doesn't trigger. Consequently, users viewing the last updated timestamp will see an outdated date despite the content having changed.
To maintain the original date during import, instead of using auto_now_add for created_at, use default=timezone.now. This default assigns the current time through the function, rather than calling it. This approach allows for creating records without specifying created_at, importing old dates, and keeping them editable in the admin and ModelForm.
For bulk updates, explicitly pass updated_at using timezone.now() to ensure it is updated. If you prefer to retain auto_now_add because you rarely modify created_at, you can still do so by creating the record first, assigning created_at afterward, and saving again. This works because auto_now_add only runs on INSERT operations.
In summary, apply auto_now_add/auto_now to tables where only a timestamp is needed, like logs or posts whose dates you never edit. For business data such as post publish dates, expiry dates, or event start dates that you may need to edit manually, import old data, or let users change in the admin, use default=timezone.now. Always verify that updated_at is updated after every QuerySet.update() or bulk_update() operation to prevent outdated timestamps.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.