Skip to content

Fix auto_now field not updated with save(update_fields=[...])#2122

Open
Br1an67 wants to merge 3 commits intotortoise:developfrom
Br1an67:fix/auto-now-update-fields
Open

Fix auto_now field not updated with save(update_fields=[...])#2122
Br1an67 wants to merge 3 commits intotortoise:developfrom
Br1an67:fix/auto-now-update-fields

Conversation

@Br1an67
Copy link
Contributor

@Br1an67 Br1an67 commented Mar 1, 2026

Description

When calling model.save(update_fields=['some_field']), fields with auto_now=True were not automatically included in the update, so their timestamps were not refreshed.

Motivation and Context

Fixes #1512

Django's ORM automatically includes auto_now fields when update_fields is specified. Tortoise-ORM should behave the same way — auto_now fields should always be updated on save regardless of whether they are explicitly listed in update_fields.

How Has This Been Tested?

Added test_update_auto_now_with_update_fields in tests/test_update.py that:

  1. Creates an Event, sets its modified timestamp to the past
  2. Updates only the name field via save(update_fields=['name'])
  3. Verifies the modified (auto_now) field was also updated to today

Checklist:

  • My code follows the code style of this project.
  • My change requires a change to the documentation.
  • I have read the CONTRIBUTING document.
  • I have added tests to cover my changes.
  • All new and existing tests passed.

When calling model.save(update_fields=['field']), fields with
auto_now=True were not included in the update, so their timestamps
were not refreshed. Now auto_now fields are automatically appended
to update_fields before executing the update.
update_fields = list(update_fields)
for field_name, field_obj in self._meta.fields_map.items():
if field_name not in update_fields and getattr(field_obj, "auto_now", False):
update_fields.append(field_name)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what about queryset .update() and .bulk_update() methods?

Add auto_now fields to BulkUpdateQuery so bulk_update() automatically
includes auto_now fields, consistent with Django's behavior.

QuerySet.update() intentionally does not handle auto_now — it is a
raw SQL operation where the caller provides explicit values, matching
Django's documented behavior.
Copy link
Contributor Author

@Br1an67 Br1an67 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! I've added support to bulk_update() as well — the new commit auto-includes auto_now fields in BulkUpdateQuery, with a corresponding test.

For QuerySet.update(), this intentionally does not auto-set auto_now — it's a raw SQL operation where the caller provides explicit values. This matches Django's documented behavior.

@itzNikshit
Copy link

Good catch! I've added support to bulk_update() as well — the new commit auto-includes auto_now fields in BulkUpdateQuery, with a corresponding test.

For QuerySet.update(), this intentionally does not auto-set auto_now — it's a raw SQL operation where the caller provides explicit values. This matches Django's documented behavior.

Yes, that makes sense. The PR looks good to me. This will now solve the ‘auto_now’ fields issue without explicitly passing them in ‘updated_fields’

Add auto_now field injection to UpdateQuery so that
QuerySet.update() automatically sets auto_now fields to the
current time when they are not explicitly specified.

Add test_queryset_update_auto_now to verify the behavior.
@Br1an67
Copy link
Contributor Author

Br1an67 commented Mar 3, 2026

Thanks for the review! Good point about queryset.update().

I've updated the PR to handle all three cases:

  1. save(update_fields=[...]) — already handled (injects auto_now fields into update_fields)
  2. bulk_update() — already handled (injects auto_now fields into BulkUpdateQuery)
  3. queryset.update()now added: UpdateQuery automatically injects timezone.now() for auto_now fields not explicitly specified in kwargs

Added test_queryset_update_auto_now to verify the new behavior.

@codspeed-hq
Copy link

codspeed-hq bot commented Mar 3, 2026

Merging this PR will not alter performance

✅ 24 untouched benchmarks


Comparing Br1an67:fix/auto-now-update-fields (50120a2) with develop (03703a7)

Open in CodSpeed

@abondar
Copy link
Member

abondar commented Mar 3, 2026

I am not sure right now if we should include this fix in that way, at least regarding querset.update

On one hand that seems logical, but at the same time it is implicit and differs from django behaviour.
Maybe we should promote more using db_default in case user wants that field to be always updated? Although it hard to imagine cases where user don't want "auto_now" field to not be updated on .update(..) queries

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

auto_now field does not get updated on model.save(update_fields=[]) if it is not included in update_fields

3 participants