Move abstract ChangeLoggedModel under extras

This commit is contained in:
Jeremy Stretch 2020-07-09 16:49:48 -04:00
parent c3a7939a77
commit 8d7001fe56
11 changed files with 169 additions and 172 deletions

View File

@ -6,10 +6,9 @@ from taggit.managers import TaggableManager
from dcim.constants import CONNECTION_STATUS_CHOICES
from dcim.fields import ASNField
from dcim.models import CableTermination
from extras.models import CustomFieldModel, ObjectChange, TaggedItem
from extras.models import ChangeLoggedModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.utils import extras_features
from utilities.querysets import RestrictedQuerySet
from utilities.models import ChangeLoggedModel
from utilities.utils import serialize_object
from .choices import *
from .querysets import CircuitQuerySet

View File

@ -21,12 +21,11 @@ from dcim.choices import *
from dcim.constants import *
from dcim.fields import ASNField
from dcim.elevations import RackElevationSVG
from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.models import ChangeLoggedModel, ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.utils import extras_features
from utilities.choices import ColorChoices
from utilities.fields import ColorField, NaturalOrderingField
from utilities.querysets import RestrictedQuerySet
from utilities.models import ChangeLoggedModel
from utilities.mptt import TreeManager
from utilities.utils import serialize_object, to_meters
from utilities.validators import ExclusionValidator

View File

@ -1,11 +1,13 @@
from .change_logging import ChangeLoggedModel, ObjectChange
from .customfields import CustomField, CustomFieldChoice, CustomFieldModel, CustomFieldValue
from .models import (
ConfigContext, ConfigContextModel, CustomLink, ExportTemplate, Graph, ImageAttachment, JobResult, ObjectChange,
Report, Script, Webhook,
ConfigContext, ConfigContextModel, CustomLink, ExportTemplate, Graph, ImageAttachment, JobResult, Report, Script,
Webhook,
)
from .tags import Tag, TaggedItem
__all__ = (
'ChangeLoggedModel',
'ConfigContext',
'ConfigContextModel',
'CustomField',

View File

@ -0,0 +1,155 @@
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
from django.contrib.postgres.fields import JSONField
from django.db import models
from django.urls import reverse
from utilities.querysets import RestrictedQuerySet
from utilities.utils import serialize_object
from extras.choices import *
#
# Change logging
#
class ChangeLoggedModel(models.Model):
"""
An abstract model which adds fields to store the creation and last-updated times for an object. Both fields can be
null to facilitate adding these fields to existing instances via a database migration.
"""
created = models.DateField(
auto_now_add=True,
blank=True,
null=True
)
last_updated = models.DateTimeField(
auto_now=True,
blank=True,
null=True
)
class Meta:
abstract = True
def to_objectchange(self, action):
"""
Return a new ObjectChange representing a change made to this object. This will typically be called automatically
by extras.middleware.ChangeLoggingMiddleware.
"""
return ObjectChange(
changed_object=self,
object_repr=str(self),
action=action,
object_data=serialize_object(self)
)
class ObjectChange(models.Model):
"""
Record a change to an object and the user account associated with that change. A change record may optionally
indicate an object related to the one being changed. For example, a change to an interface may also indicate the
parent device. This will ensure changes made to component models appear in the parent model's changelog.
"""
time = models.DateTimeField(
auto_now_add=True,
editable=False,
db_index=True
)
user = models.ForeignKey(
to=User,
on_delete=models.SET_NULL,
related_name='changes',
blank=True,
null=True
)
user_name = models.CharField(
max_length=150,
editable=False
)
request_id = models.UUIDField(
editable=False
)
action = models.CharField(
max_length=50,
choices=ObjectChangeActionChoices
)
changed_object_type = models.ForeignKey(
to=ContentType,
on_delete=models.PROTECT,
related_name='+'
)
changed_object_id = models.PositiveIntegerField()
changed_object = GenericForeignKey(
ct_field='changed_object_type',
fk_field='changed_object_id'
)
related_object_type = models.ForeignKey(
to=ContentType,
on_delete=models.PROTECT,
related_name='+',
blank=True,
null=True
)
related_object_id = models.PositiveIntegerField(
blank=True,
null=True
)
related_object = GenericForeignKey(
ct_field='related_object_type',
fk_field='related_object_id'
)
object_repr = models.CharField(
max_length=200,
editable=False
)
object_data = JSONField(
editable=False
)
objects = RestrictedQuerySet.as_manager()
csv_headers = [
'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object_id',
'related_object_type', 'related_object_id', 'object_repr', 'object_data',
]
class Meta:
ordering = ['-time']
def __str__(self):
return '{} {} {} by {}'.format(
self.changed_object_type,
self.object_repr,
self.get_action_display().lower(),
self.user_name
)
def save(self, *args, **kwargs):
# Record the user's name and the object's representation as static strings
if not self.user_name:
self.user_name = self.user.username
if not self.object_repr:
self.object_repr = str(self.changed_object)
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('extras:objectchange', args=[self.pk])
def to_csv(self):
return (
self.time,
self.user,
self.user_name,
self.request_id,
self.get_action_display(),
self.changed_object_type,
self.changed_object_id,
self.related_object_type,
self.related_object_id,
self.object_repr,
self.object_data,
)

View File

@ -2,7 +2,6 @@ import json
import uuid
from collections import OrderedDict
import django_rq
from django.contrib.auth.models import User
from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType
@ -15,12 +14,13 @@ from django.urls import reverse
from django.utils import timezone
from rest_framework.utils.encoders import JSONEncoder
from utilities.querysets import RestrictedQuerySet
from utilities.utils import deepmerge, render_jinja2
from extras.choices import *
from extras.constants import *
from extras.models import ChangeLoggedModel
from extras.querysets import ConfigContextQuerySet
from extras.utils import extras_features, FeatureQuery, image_upload
from utilities.querysets import RestrictedQuerySet
from utilities.utils import deepmerge, render_jinja2
#
@ -684,116 +684,3 @@ class JobResult(models.Model):
func.delay(*args, job_id=str(job_result.job_id), job_result=job_result, **kwargs)
return job_result
#
# Change logging
#
class ObjectChange(models.Model):
"""
Record a change to an object and the user account associated with that change. A change record may optionally
indicate an object related to the one being changed. For example, a change to an interface may also indicate the
parent device. This will ensure changes made to component models appear in the parent model's changelog.
"""
time = models.DateTimeField(
auto_now_add=True,
editable=False,
db_index=True
)
user = models.ForeignKey(
to=User,
on_delete=models.SET_NULL,
related_name='changes',
blank=True,
null=True
)
user_name = models.CharField(
max_length=150,
editable=False
)
request_id = models.UUIDField(
editable=False
)
action = models.CharField(
max_length=50,
choices=ObjectChangeActionChoices
)
changed_object_type = models.ForeignKey(
to=ContentType,
on_delete=models.PROTECT,
related_name='+'
)
changed_object_id = models.PositiveIntegerField()
changed_object = GenericForeignKey(
ct_field='changed_object_type',
fk_field='changed_object_id'
)
related_object_type = models.ForeignKey(
to=ContentType,
on_delete=models.PROTECT,
related_name='+',
blank=True,
null=True
)
related_object_id = models.PositiveIntegerField(
blank=True,
null=True
)
related_object = GenericForeignKey(
ct_field='related_object_type',
fk_field='related_object_id'
)
object_repr = models.CharField(
max_length=200,
editable=False
)
object_data = JSONField(
editable=False
)
objects = RestrictedQuerySet.as_manager()
csv_headers = [
'time', 'user', 'user_name', 'request_id', 'action', 'changed_object_type', 'changed_object_id',
'related_object_type', 'related_object_id', 'object_repr', 'object_data',
]
class Meta:
ordering = ['-time']
def __str__(self):
return '{} {} {} by {}'.format(
self.changed_object_type,
self.object_repr,
self.get_action_display().lower(),
self.user_name
)
def save(self, *args, **kwargs):
# Record the user's name and the object's representation as static strings
if not self.user_name:
self.user_name = self.user.username
if not self.object_repr:
self.object_repr = str(self.changed_object)
return super().save(*args, **kwargs)
def get_absolute_url(self):
return reverse('extras:objectchange', args=[self.pk])
def to_csv(self):
return (
self.time,
self.user,
self.user_name,
self.request_id,
self.get_action_display(),
self.changed_object_type,
self.changed_object_id,
self.related_object_type,
self.related_object_id,
self.object_repr,
self.object_data,
)

View File

@ -2,9 +2,9 @@ from django.db import models
from django.utils.text import slugify
from taggit.models import TagBase, GenericTaggedItemBase
from extras.models import ChangeLoggedModel
from utilities.choices import ColorChoices
from utilities.fields import ColorField
from utilities.models import ChangeLoggedModel
from utilities.querysets import RestrictedQuerySet

View File

@ -10,9 +10,8 @@ from django.urls import reverse
from taggit.managers import TaggableManager
from dcim.models import Device, Interface
from extras.models import CustomFieldModel, ObjectChange, TaggedItem
from extras.models import ChangeLoggedModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.utils import extras_features
from utilities.models import ChangeLoggedModel
from utilities.querysets import RestrictedQuerySet
from utilities.utils import serialize_object
from virtualization.models import VirtualMachine, VMInterface

View File

@ -14,9 +14,8 @@ from django.utils.encoding import force_bytes
from taggit.managers import TaggableManager
from dcim.models import Device
from extras.models import CustomFieldModel, TaggedItem
from extras.models import ChangeLoggedModel, CustomFieldModel, TaggedItem
from extras.utils import extras_features
from utilities.models import ChangeLoggedModel
from utilities.querysets import RestrictedQuerySet
from .exceptions import InvalidKey
from .hashers import SecretValidationHasher

View File

@ -4,9 +4,8 @@ from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey
from taggit.managers import TaggableManager
from extras.models import CustomFieldModel, ObjectChange, TaggedItem
from extras.models import ChangeLoggedModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.utils import extras_features
from utilities.models import ChangeLoggedModel
from utilities.mptt import TreeManager
from utilities.querysets import RestrictedQuerySet
from utilities.utils import serialize_object

View File

@ -1,41 +0,0 @@
from django.db import models
from extras.models import ObjectChange
from utilities.utils import serialize_object
__all__ = (
'ChangeLoggedModel',
)
class ChangeLoggedModel(models.Model):
"""
An abstract model which adds fields to store the creation and last-updated times for an object. Both fields can be
null to facilitate adding these fields to existing instances via a database migration.
"""
created = models.DateField(
auto_now_add=True,
blank=True,
null=True
)
last_updated = models.DateTimeField(
auto_now=True,
blank=True,
null=True
)
class Meta:
abstract = True
def to_objectchange(self, action):
"""
Return a new ObjectChange representing a change made to this object. This will typically be called automatically
by extras.middleware.ChangeLoggingMiddleware.
"""
return ObjectChange(
changed_object=self,
object_repr=str(self),
action=action,
object_data=serialize_object(self)
)

View File

@ -7,10 +7,9 @@ from taggit.managers import TaggableManager
from dcim.choices import InterfaceModeChoices
from dcim.models import BaseInterface, Device
from extras.models import ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.models import ChangeLoggedModel, ConfigContextModel, CustomFieldModel, ObjectChange, TaggedItem
from extras.utils import extras_features
from utilities.fields import NaturalOrderingField
from utilities.models import ChangeLoggedModel
from utilities.ordering import naturalize_interface
from utilities.query_functions import CollateAsChar
from utilities.querysets import RestrictedQuerySet