Просмотр исходного кода

Closes #5901: Add 'created' and 'last_updated' fields to device component models

Jeremy Stretch 5 лет назад
Родитель
Сommit
07e6abdac4

+ 1 - 0
docs/release-notes/version-2.11.md

@@ -9,6 +9,7 @@
 * [#5370](https://github.com/netbox-community/netbox/issues/5370) - Extend custom field support to organizational models
 * [#5401](https://github.com/netbox-community/netbox/issues/5401) - Extend custom field support to device component models
 * [#5451](https://github.com/netbox-community/netbox/issues/5451) - Add support for multiple-selection custom fields
+* [#5901](https://github.com/netbox-community/netbox/issues/5901) - Add `created` and `last_updated` fields to device component models
 
 ### Other Changes
 

+ 33 - 15
netbox/dcim/api/serializers.py

@@ -288,7 +288,7 @@ class ConsolePortTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = ConsolePortTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'description']
+        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'description', 'created', 'last_updated']
 
 
 class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
@@ -302,7 +302,7 @@ class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = ConsoleServerPortTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'description']
+        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'description', 'created', 'last_updated']
 
 
 class PowerPortTemplateSerializer(ValidatedModelSerializer):
@@ -316,7 +316,10 @@ class PowerPortTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = PowerPortTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description']
+        fields = [
+            'id', 'url', 'device_type', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description',
+            'created', 'last_updated',
+        ]
 
 
 class PowerOutletTemplateSerializer(ValidatedModelSerializer):
@@ -338,7 +341,10 @@ class PowerOutletTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = PowerOutletTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description']
+        fields = [
+            'id', 'url', 'device_type', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'created',
+            'last_updated',
+        ]
 
 
 class InterfaceTemplateSerializer(ValidatedModelSerializer):
@@ -348,7 +354,9 @@ class InterfaceTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = InterfaceTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'mgmt_only', 'description']
+        fields = [
+            'id', 'url', 'device_type', 'name', 'label', 'type', 'mgmt_only', 'description', 'created', 'last_updated',
+        ]
 
 
 class RearPortTemplateSerializer(ValidatedModelSerializer):
@@ -358,7 +366,9 @@ class RearPortTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = RearPortTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'positions', 'description']
+        fields = [
+            'id', 'url', 'device_type', 'name', 'label', 'type', 'positions', 'description', 'created', 'last_updated',
+        ]
 
 
 class FrontPortTemplateSerializer(ValidatedModelSerializer):
@@ -369,7 +379,10 @@ class FrontPortTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = FrontPortTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description']
+        fields = [
+            'id', 'url', 'device_type', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description',
+            'created', 'last_updated',
+        ]
 
 
 class DeviceBayTemplateSerializer(ValidatedModelSerializer):
@@ -378,7 +391,7 @@ class DeviceBayTemplateSerializer(ValidatedModelSerializer):
 
     class Meta:
         model = DeviceBayTemplate
-        fields = ['id', 'url', 'device_type', 'name', 'label', 'description']
+        fields = ['id', 'url', 'device_type', 'name', 'label', 'description', 'created', 'last_updated']
 
 
 #
@@ -498,6 +511,7 @@ class ConsoleServerPortSerializer(TaggedObjectSerializer, CableTerminationSerial
         fields = [
             'id', 'url', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'cable_peer_type',
             'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields',
+            'created', 'last_updated',
         ]
 
 
@@ -516,6 +530,7 @@ class ConsolePortSerializer(TaggedObjectSerializer, CableTerminationSerializer,
         fields = [
             'id', 'url', 'device', 'name', 'label', 'type', 'description', 'cable', 'cable_peer', 'cable_peer_type',
             'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields',
+            'created', 'last_updated',
         ]
 
 
@@ -544,7 +559,7 @@ class PowerOutletSerializer(TaggedObjectSerializer, CableTerminationSerializer,
         fields = [
             'id', 'url', 'device', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'cable',
             'cable_peer', 'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type',
-            'connected_endpoint_reachable', 'tags', 'custom_fields',
+            'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
 
 
@@ -563,7 +578,7 @@ class PowerPortSerializer(TaggedObjectSerializer, CableTerminationSerializer, Co
         fields = [
             'id', 'url', 'device', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'cable',
             'cable_peer', 'cable_peer_type', 'connected_endpoint', 'connected_endpoint_type',
-            'connected_endpoint_reachable', 'tags', 'custom_fields',
+            'connected_endpoint_reachable', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
 
 
@@ -589,7 +604,7 @@ class InterfaceSerializer(TaggedObjectSerializer, CableTerminationSerializer, Co
             'id', 'url', 'device', 'name', 'label', 'type', 'enabled', 'lag', 'mtu', 'mac_address', 'mgmt_only',
             'description', 'mode', 'untagged_vlan', 'tagged_vlans', 'cable', 'cable_peer', 'cable_peer_type',
             'connected_endpoint', 'connected_endpoint_type', 'connected_endpoint_reachable', 'tags', 'custom_fields',
-            'count_ipaddresses',
+            'created', 'last_updated', 'count_ipaddresses',
         ]
 
     def validate(self, data):
@@ -616,7 +631,7 @@ class RearPortSerializer(TaggedObjectSerializer, CableTerminationSerializer, Cus
         model = RearPort
         fields = [
             'id', 'url', 'device', 'name', 'label', 'type', 'positions', 'description', 'cable', 'cable_peer',
-            'cable_peer_type', 'tags', 'custom_fields',
+            'cable_peer_type', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
 
 
@@ -642,7 +657,7 @@ class FrontPortSerializer(TaggedObjectSerializer, CableTerminationSerializer, Cu
         model = FrontPort
         fields = [
             'id', 'url', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'cable',
-            'cable_peer', 'cable_peer_type', 'tags', 'custom_fields',
+            'cable_peer', 'cable_peer_type', 'tags', 'custom_fields', 'created', 'last_updated',
         ]
 
 
@@ -653,7 +668,10 @@ class DeviceBaySerializer(TaggedObjectSerializer, CustomFieldModelSerializer):
 
     class Meta:
         model = DeviceBay
-        fields = ['id', 'url', 'device', 'name', 'label', 'description', 'installed_device', 'tags', 'custom_fields']
+        fields = [
+            'id', 'url', 'device', 'name', 'label', 'description', 'installed_device', 'tags', 'custom_fields',
+            'created', 'last_updated',
+        ]
 
 
 #
@@ -672,7 +690,7 @@ class InventoryItemSerializer(TaggedObjectSerializer, CustomFieldModelSerializer
         model = InventoryItem
         fields = [
             'id', 'url', 'device', 'parent', 'name', 'label', 'manufacturer', 'part_id', 'serial', 'asset_tag',
-            'discovered', 'description', 'tags', 'custom_fields', '_depth',
+            'discovered', 'description', 'tags', 'custom_fields', 'created', 'last_updated', '_depth',
         ]
 
 

+ 170 - 0
netbox/dcim/migrations/0123_standardize_models.py

@@ -9,41 +9,151 @@ class Migration(migrations.Migration):
     ]
 
     operations = [
+        migrations.AddField(
+            model_name='consoleport',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='consoleport',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='consoleport',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='consoleporttemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='consoleporttemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='consoleserverport',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='consoleserverport',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='consoleserverport',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='consoleserverporttemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='consoleserverporttemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='devicebay',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='devicebay',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='devicebay',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='devicebaytemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='devicebaytemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
         migrations.AddField(
             model_name='devicerole',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='frontport',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='frontport',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='frontport',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='frontporttemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='frontporttemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='interface',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='interface',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='interface',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='interfacetemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='interfacetemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='inventoryitem',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='inventoryitem',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='inventoryitem',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
         migrations.AddField(
             model_name='manufacturer',
             name='custom_field_data',
@@ -54,16 +164,56 @@ class Migration(migrations.Migration):
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='poweroutlet',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='poweroutlet',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='poweroutlet',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='poweroutlettemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='poweroutlettemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='powerport',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='powerport',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='powerport',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='powerporttemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='powerporttemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
         migrations.AddField(
             model_name='rackgroup',
             name='custom_field_data',
@@ -74,11 +224,31 @@ class Migration(migrations.Migration):
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='rearport',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
         migrations.AddField(
             model_name='rearport',
             name='custom_field_data',
             field=models.JSONField(blank=True, default=dict, encoder=django.core.serializers.json.DjangoJSONEncoder),
         ),
+        migrations.AddField(
+            model_name='rearport',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='rearporttemplate',
+            name='created',
+            field=models.DateField(auto_now_add=True, null=True),
+        ),
+        migrations.AddField(
+            model_name='rearporttemplate',
+            name='last_updated',
+            field=models.DateTimeField(auto_now=True, null=True),
+        ),
         migrations.AddField(
             model_name='region',
             name='custom_field_data',

+ 2 - 2
netbox/dcim/models/device_component_templates.py

@@ -6,7 +6,7 @@ from dcim.choices import *
 from dcim.constants import *
 from extras.models import ObjectChange
 from extras.utils import extras_features
-from netbox.models import BigIDModel
+from netbox.models import BigIDModel, ChangeLoggingMixin
 from utilities.fields import NaturalOrderingField
 from utilities.querysets import RestrictedQuerySet
 from utilities.ordering import naturalize_interface
@@ -28,7 +28,7 @@ __all__ = (
 )
 
 
-class ComponentTemplateModel(BigIDModel):
+class ComponentTemplateModel(ChangeLoggingMixin, BigIDModel):
     device_type = models.ForeignKey(
         to='dcim.DeviceType',
         on_delete=models.CASCADE,

+ 2 - 2
netbox/dcim/models/device_components.py

@@ -13,7 +13,7 @@ from dcim.constants import *
 from dcim.fields import MACAddressField
 from extras.models import ObjectChange, TaggedItem
 from extras.utils import extras_features
-from netbox.models import BigIDModel, CustomFieldsMixin
+from netbox.models import PrimaryModel
 from utilities.fields import NaturalOrderingField
 from utilities.mptt import TreeManager
 from utilities.ordering import naturalize_interface
@@ -38,7 +38,7 @@ __all__ = (
 )
 
 
-class ComponentModel(CustomFieldsMixin, BigIDModel):
+class ComponentModel(PrimaryModel):
     """
     An abstract model inherited by any model which has a parent Device.
     """

+ 1 - 0
netbox/netbox/models.py

@@ -10,6 +10,7 @@ from utilities.utils import serialize_object
 
 __all__ = (
     'BigIDModel',
+    'ChangeLoggingMixin',
     'CustomFieldsMixin',
     'NestedGroupModel',
     'OrganizationalModel',

+ 1 - 0
netbox/templates/dcim/device_component.html

@@ -30,6 +30,7 @@
         {% endif %}
     </div>
     <h1>{% block title %}{{ object.device }} / {{ object }}{% endblock %}</h1>
+    {% include 'inc/created_updated.html' %}
     <ul class="nav nav-tabs">
         <li role="presentation"{% if not active_tab %} class="active"{% endif %}>
             <a href="{{ object.get_absolute_url }}">{{ object|meta:"verbose_name"|bettertitle }}</a>