diff --git a/CHANGELOG.md b/CHANGELOG.md index 109bcdd4..98294e0e 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,8 @@ ## Next Release +- feat: Make timestamp in LogEntry overwritable. ([#476](https://github.com/jazzband/django-auditlog/pull/476)) +- ## 2.2.1 (2022-11-28) #### Fixes diff --git a/auditlog/migrations/0013_alter_logentry_timestamp.py b/auditlog/migrations/0013_alter_logentry_timestamp.py new file mode 100644 index 00000000..a395916c --- /dev/null +++ b/auditlog/migrations/0013_alter_logentry_timestamp.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.4 on 2022-12-15 21:24 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("auditlog", "0012_add_logentry_action_access"), + ] + + operations = [ + migrations.AlterField( + model_name="logentry", + name="timestamp", + field=models.DateTimeField( + db_index=True, + default=django.utils.timezone.now, + verbose_name="timestamp", + ), + ), + ] diff --git a/auditlog/models.py b/auditlog/models.py index e073c882..7bb34615 100644 --- a/auditlog/models.py +++ b/auditlog/models.py @@ -14,6 +14,7 @@ from django.db import DEFAULT_DB_ALIAS, models from django.db.models import Q, QuerySet from django.utils import formats +from django.utils import timezone as django_timezone from django.utils.encoding import smart_str from django.utils.translation import gettext_lazy as _ @@ -355,7 +356,9 @@ class Action: blank=True, null=True, verbose_name=_("remote address") ) timestamp = models.DateTimeField( - db_index=True, auto_now_add=True, verbose_name=_("timestamp") + default=django_timezone.now, + db_index=True, + verbose_name=_("timestamp"), ) additional_data = models.JSONField( blank=True, null=True, verbose_name=_("additional data") diff --git a/auditlog_tests/tests.py b/auditlog_tests/tests.py index e88c706e..0d2bef45 100644 --- a/auditlog_tests/tests.py +++ b/auditlog_tests/tests.py @@ -200,6 +200,24 @@ def test_create_log_to_object_from_other_database(self): log_entry._state.db, "default", msg=msg ) # must be created in default database + def test_default_timestamp(self): + start = django_timezone.now() + self.test_recreate() + end = django_timezone.now() + history = self.obj.history.latest() + self.assertTrue(start <= history.timestamp <= end) + + def test_manual_timestamp(self): + timestamp = datetime.datetime(1999, 12, 31, 23, 59, 59, tzinfo=timezone.utc) + LogEntry.objects.log_create( + instance=self.obj, + timestamp=timestamp, + changes="foo bar", + action=LogEntry.Action.UPDATE, + ) + history = self.obj.history.filter(timestamp=timestamp, changes="foo bar") + self.assertTrue(history.exists()) + class NoActorMixin: def check_create_log_entry(self, obj, log_entry):