Deserialize JobLogEntry timestamp

This commit is contained in:
Jeremy Stretch 2025-07-09 09:30:38 -04:00
parent 92a13a4226
commit e95c3825de
4 changed files with 29 additions and 2 deletions

View File

@ -2,6 +2,8 @@ import django.contrib.postgres.fields
import django.core.serializers.json import django.core.serializers.json
from django.db import migrations, models from django.db import migrations, models
import utilities.json
class Migration(migrations.Migration): class Migration(migrations.Migration):
@ -15,6 +17,7 @@ class Migration(migrations.Migration):
name='log_entries', name='log_entries',
field=django.contrib.postgres.fields.ArrayField( field=django.contrib.postgres.fields.ArrayField(
base_field=models.JSONField( base_field=models.JSONField(
decoder=utilities.json.JobLogDecoder,
encoder=django.core.serializers.json.DjangoJSONEncoder encoder=django.core.serializers.json.DjangoJSONEncoder
), ),
blank=True, blank=True,

View File

@ -20,6 +20,7 @@ from core.choices import JobStatusChoices
from core.dataclasses import JobLogEntry from core.dataclasses import JobLogEntry
from core.models import ObjectType from core.models import ObjectType
from core.signals import job_end, job_start from core.signals import job_end, job_start
from utilities.json import JobLogDecoder
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
from utilities.rqworker import get_queue_for_model from utilities.rqworker import get_queue_for_model
@ -111,7 +112,7 @@ class Job(models.Model):
log_entries = ArrayField( log_entries = ArrayField(
base_field=models.JSONField( base_field=models.JSONField(
encoder=DjangoJSONEncoder, encoder=DjangoJSONEncoder,
# TODO: Specify a decoder to handle ISO 8601 timestamps decoder=JobLogDecoder,
), ),
blank=True, blank=True,
default=list, default=list,

View File

@ -62,7 +62,8 @@ class JobTable(NetBoxTable):
class JobLogEntryTable(BaseTable): class JobLogEntryTable(BaseTable):
timestamp = tables.Column( timestamp = columns.DateTimeColumn(
timespec='milliseconds',
verbose_name=_('Time'), verbose_name=_('Time'),
) )
level = tables.Column( level = tables.Column(

View File

@ -1,10 +1,14 @@
import decimal import decimal
import json
from django.core.serializers.json import DjangoJSONEncoder from django.core.serializers.json import DjangoJSONEncoder
from utilities.datetime import datetime_from_timestamp
__all__ = ( __all__ = (
'ConfigJSONEncoder', 'ConfigJSONEncoder',
'CustomFieldJSONEncoder', 'CustomFieldJSONEncoder',
'JobLogDecoder',
) )
@ -29,3 +33,21 @@ class ConfigJSONEncoder(DjangoJSONEncoder):
return type(o).__name__ return type(o).__name__
return super().default(o) return super().default(o)
class JobLogDecoder(json.JSONDecoder):
"""
Deserialize JobLogEntry timestamps.
"""
def __init__(self, *args, **kwargs):
kwargs['object_hook'] = self._deserialize_entry
super().__init__(*args, **kwargs)
def _deserialize_entry(self, obj: dict) -> dict:
if obj.get('timestamp'):
# Deserialize a timestamp string to a native datetime object
try:
obj['timestamp'] = datetime_from_timestamp(obj['timestamp'])
except ValueError:
pass
return obj