From bc6b5bc4be52e3310a1e1d7ad4bdd40db9ae290a Mon Sep 17 00:00:00 2001 From: Jeremy Stretch Date: Fri, 4 Nov 2022 08:28:09 -0400 Subject: [PATCH] Closes #10545: Standardize description & comment fields on primary models (#10834) * Standardize description & comments fields on primary models * Update REST API serializers * Update forms * Update tables * Update templates --- docs/release-notes/version-3.4.md | 51 +++++++ netbox/circuits/api/serializers.py | 4 +- netbox/circuits/forms/bulk_edit.py | 6 +- netbox/circuits/forms/bulk_import.py | 2 +- netbox/circuits/forms/model_forms.py | 9 +- .../0041_standardize_description_comments.py | 18 +++ netbox/circuits/models/circuits.py | 11 +- netbox/circuits/models/providers.py | 17 +-- netbox/circuits/tables/providers.py | 4 +- netbox/dcim/api/serializers.py | 41 +++--- netbox/dcim/forms/bulk_edit.py | 131 ++++++++++++++---- netbox/dcim/forms/bulk_import.py | 17 +-- netbox/dcim/forms/model_forms.py | 40 +++--- netbox/dcim/forms/object_import.py | 4 +- .../0165_standardize_description_comments.py | 78 +++++++++++ netbox/dcim/models/cables.py | 6 +- netbox/dcim/models/devices.py | 24 +--- netbox/dcim/models/power.py | 10 +- netbox/dcim/models/racks.py | 9 +- netbox/dcim/models/sites.py | 11 +- netbox/dcim/tables/cables.py | 3 +- netbox/dcim/tables/devices.py | 78 +++++------ netbox/dcim/tables/devicetypes.py | 44 ++---- netbox/dcim/tables/modules.py | 6 +- netbox/dcim/tables/power.py | 6 +- netbox/dcim/tables/racks.py | 9 +- netbox/ipam/api/serializers.py | 39 +++--- netbox/ipam/forms/bulk_edit.py | 90 +++++++++--- netbox/ipam/forms/bulk_import.py | 24 ++-- netbox/ipam/forms/model_forms.py | 50 ++++--- .../0063_standardize_description_comments.py | 73 ++++++++++ netbox/ipam/models/fhrp.py | 8 +- netbox/ipam/models/ip.py | 32 +---- netbox/ipam/models/l2vpn.py | 8 +- netbox/ipam/models/services.py | 10 +- netbox/ipam/models/vlans.py | 14 +- netbox/ipam/models/vrfs.py | 14 +- netbox/ipam/tables/fhrp.py | 4 +- netbox/ipam/tables/ip.py | 26 ++-- netbox/ipam/tables/l2vpn.py | 8 +- netbox/ipam/tables/services.py | 10 +- netbox/ipam/tables/vlans.py | 3 +- netbox/ipam/tables/vrfs.py | 10 +- netbox/netbox/models/__init__.py | 21 ++- netbox/templates/circuits/provider.html | 4 + netbox/templates/dcim/cable.html | 5 + netbox/templates/dcim/cable_edit.html | 23 +-- netbox/templates/dcim/device.html | 6 +- netbox/templates/dcim/device_edit.html | 1 + netbox/templates/dcim/devicetype.html | 4 + netbox/templates/dcim/module.html | 4 + netbox/templates/dcim/moduletype.html | 4 + netbox/templates/dcim/powerfeed.html | 4 + netbox/templates/dcim/powerpanel.html | 41 +++--- netbox/templates/dcim/rack.html | 4 + netbox/templates/dcim/rack_edit.html | 1 + netbox/templates/dcim/rackreservation.html | 1 + netbox/templates/dcim/virtualchassis.html | 7 +- .../templates/dcim/virtualchassis_edit.html | 8 +- netbox/templates/ipam/aggregate.html | 1 + netbox/templates/ipam/asn.html | 1 + netbox/templates/ipam/fhrpgroup.html | 1 + netbox/templates/ipam/fhrpgroup_edit.html | 11 +- netbox/templates/ipam/ipaddress.html | 1 + netbox/templates/ipam/ipaddress_edit.html | 7 + netbox/templates/ipam/iprange.html | 7 +- netbox/templates/ipam/l2vpn.html | 1 + netbox/templates/ipam/prefix.html | 1 + netbox/templates/ipam/routetarget.html | 1 + netbox/templates/ipam/service.html | 7 +- netbox/templates/ipam/service_create.html | 7 + netbox/templates/ipam/service_edit.html | 7 + netbox/templates/ipam/servicetemplate.html | 13 +- netbox/templates/ipam/vlan.html | 7 +- netbox/templates/ipam/vlan_edit.html | 7 + netbox/templates/ipam/vrf.html | 1 + netbox/templates/tenancy/contact.html | 4 + netbox/templates/virtualization/cluster.html | 4 + .../virtualization/virtualmachine.html | 4 + netbox/templates/wireless/wirelesslan.html | 1 + netbox/templates/wireless/wirelesslink.html | 1 + .../templates/wireless/wirelesslink_edit.html | 6 + netbox/tenancy/api/serializers.py | 4 +- netbox/tenancy/forms/bulk_edit.py | 14 +- netbox/tenancy/forms/bulk_import.py | 2 +- netbox/tenancy/forms/model_forms.py | 4 +- .../0009_standardize_description_comments.py | 18 +++ netbox/tenancy/models/contacts.py | 8 +- netbox/tenancy/models/tenants.py | 12 +- netbox/tenancy/tables/contacts.py | 4 +- netbox/virtualization/api/serializers.py | 8 +- netbox/virtualization/forms/bulk_edit.py | 18 ++- netbox/virtualization/forms/bulk_import.py | 4 +- netbox/virtualization/forms/model_forms.py | 10 +- .../0034_standardize_description_comments.py | 23 +++ netbox/virtualization/models.py | 12 +- netbox/virtualization/tables/clusters.py | 4 +- .../virtualization/tables/virtualmachines.py | 4 +- netbox/wireless/api/serializers.py | 4 +- netbox/wireless/forms/bulk_edit.py | 28 ++-- netbox/wireless/forms/bulk_import.py | 7 +- netbox/wireless/forms/model_forms.py | 11 +- .../0007_standardize_description_comments.py | 23 +++ netbox/wireless/models.py | 16 +-- netbox/wireless/tables/wirelesslan.py | 9 +- 105 files changed, 1014 insertions(+), 534 deletions(-) create mode 100644 netbox/circuits/migrations/0041_standardize_description_comments.py create mode 100644 netbox/dcim/migrations/0165_standardize_description_comments.py create mode 100644 netbox/ipam/migrations/0063_standardize_description_comments.py create mode 100644 netbox/tenancy/migrations/0009_standardize_description_comments.py create mode 100644 netbox/virtualization/migrations/0034_standardize_description_comments.py create mode 100644 netbox/wireless/migrations/0007_standardize_description_comments.py diff --git a/docs/release-notes/version-3.4.md b/docs/release-notes/version-3.4.md index cc9fc90d2..158e7a77f 100644 --- a/docs/release-notes/version-3.4.md +++ b/docs/release-notes/version-3.4.md @@ -69,18 +69,69 @@ A new `PluginMenu` class has been introduced, which enables a plugin to inject a * circuits.provider * Removed the `asn`, `noc_contact`, `admin_contact`, and `portal_url` fields + * Added a `description` field +* dcim.Cable + * Added `description` and `comments` fields +* dcim.Device + * Added a `description` field * dcim.DeviceType + * Added a `description` field * Added optional `weight` and `weight_unit` fields +* dcim.Module + * Added a `description` field * dcim.ModuleType + * Added a `description` field * Added optional `weight` and `weight_unit` fields +* dcim.PowerFeed + * Added a `description` field +* dcim.PowerPanel + * Added `description` and `comments` fields * dcim.Rack + * Added a `description` field * Added optional `weight` and `weight_unit` fields +* dcim.RackReservation + * Added a `comments` field +* dcim.VirtualChassis + * Added `description` and `comments` fields * extras.CustomLink * Renamed `content_type` field to `content_types` * extras.ExportTemplate * Renamed `content_type` field to `content_types` +* ipam.Aggregate + * Added a `comments` field +* ipam.ASN + * Added a `comments` field * ipam.FHRPGroup + * Added a `comments` field * Added optional `name` field +* ipam.IPAddress + * Added a `comments` field +* ipam.IPRange + * Added a `comments` field +* ipam.L2VPN + * Added a `comments` field +* ipam.Prefix + * Added a `comments` field +* ipam.RouteTarget + * Added a `comments` field +* ipam.Service + * Added a `comments` field +* ipam.ServiceTemplate + * Added a `comments` field +* ipam.VLAN + * Added a `comments` field +* ipam.VRF + * Added a `comments` field +* tenancy.Contact + * Added a `description` field +* virtualization.Cluster + * Added a `description` field +* virtualization.VirtualMachine + * Added a `description` field +* wireless.WirelessLAN + * Added a `comments` field +* wireless.WirelessLink + * Added a `comments` field ### GraphQL API Changes diff --git a/netbox/circuits/api/serializers.py b/netbox/circuits/api/serializers.py index 4a8e2bd28..2bcb0895a 100644 --- a/netbox/circuits/api/serializers.py +++ b/netbox/circuits/api/serializers.py @@ -31,8 +31,8 @@ class ProviderSerializer(NetBoxModelSerializer): class Meta: model = Provider fields = [ - 'id', 'url', 'display', 'name', 'slug', 'account', - 'comments', 'asns', 'tags', 'custom_fields', 'created', 'last_updated', 'circuit_count', + 'id', 'url', 'display', 'name', 'slug', 'account', 'description', 'comments', 'asns', 'tags', + 'custom_fields', 'created', 'last_updated', 'circuit_count', ] diff --git a/netbox/circuits/forms/bulk_edit.py b/netbox/circuits/forms/bulk_edit.py index 12975b5d6..6e9ae516c 100644 --- a/netbox/circuits/forms/bulk_edit.py +++ b/netbox/circuits/forms/bulk_edit.py @@ -30,6 +30,10 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm): required=False, label='Account number' ) + description = forms.CharField( + max_length=200, + required=False + ) comments = CommentField( widget=SmallTextarea, label='Comments' @@ -40,7 +44,7 @@ class ProviderBulkEditForm(NetBoxModelBulkEditForm): (None, ('asns', 'account', )), ) nullable_fields = ( - 'asns', 'account', 'comments', + 'asns', 'account', 'description', 'comments', ) diff --git a/netbox/circuits/forms/bulk_import.py b/netbox/circuits/forms/bulk_import.py index 77ebb3de9..d0bdb09a7 100644 --- a/netbox/circuits/forms/bulk_import.py +++ b/netbox/circuits/forms/bulk_import.py @@ -18,7 +18,7 @@ class ProviderCSVForm(NetBoxModelCSVForm): class Meta: model = Provider fields = ( - 'name', 'slug', 'account', 'comments', + 'name', 'slug', 'account', 'description', 'comments', ) diff --git a/netbox/circuits/forms/model_forms.py b/netbox/circuits/forms/model_forms.py index 03c473d62..ab1b6bca2 100644 --- a/netbox/circuits/forms/model_forms.py +++ b/netbox/circuits/forms/model_forms.py @@ -1,4 +1,3 @@ -from django import forms from django.utils.translation import gettext as _ from circuits.models import * @@ -7,8 +6,8 @@ from ipam.models import ASN from netbox.forms import NetBoxModelForm from tenancy.forms import TenancyForm from utilities.forms import ( - BootstrapMixin, CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, - SelectSpeedWidget, SmallTextarea, SlugField, StaticSelect, + CommentField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, SelectSpeedWidget, SlugField, + StaticSelect, ) __all__ = ( @@ -30,14 +29,14 @@ class ProviderForm(NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Provider', ('name', 'slug', 'asns', 'tags')), + ('Provider', ('name', 'slug', 'asns', 'description', 'tags')), ('Support Info', ('account',)), ) class Meta: model = Provider fields = [ - 'name', 'slug', 'account', 'asns', 'comments', 'tags', + 'name', 'slug', 'account', 'asns', 'description', 'comments', 'tags', ] help_texts = { 'name': "Full name of the provider", diff --git a/netbox/circuits/migrations/0041_standardize_description_comments.py b/netbox/circuits/migrations/0041_standardize_description_comments.py new file mode 100644 index 000000000..49cdefcba --- /dev/null +++ b/netbox/circuits/migrations/0041_standardize_description_comments.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2022-11-03 18:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('circuits', '0040_provider_remove_deprecated_fields'), + ] + + operations = [ + migrations.AddField( + model_name='provider', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + ] diff --git a/netbox/circuits/models/circuits.py b/netbox/circuits/models/circuits.py index 7100c9796..9d302bb8e 100644 --- a/netbox/circuits/models/circuits.py +++ b/netbox/circuits/models/circuits.py @@ -7,7 +7,7 @@ from django.urls import reverse from circuits.choices import * from dcim.models import CabledObjectModel from netbox.models import ( - ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, NetBoxModel, TagsMixin, + ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, PrimaryModel, TagsMixin, ) from netbox.models.features import WebhooksMixin @@ -27,7 +27,7 @@ class CircuitType(OrganizationalModel): return reverse('circuits:circuittype', args=[self.pk]) -class Circuit(NetBoxModel): +class Circuit(PrimaryModel): """ A communications circuit connects two points. Each Circuit belongs to a Provider; Providers may have multiple circuits. Each circuit is also assigned a CircuitType and a Site. Circuit port speed and commit rate are measured @@ -73,13 +73,6 @@ class Circuit(NetBoxModel): blank=True, null=True, verbose_name='Commit rate (Kbps)') - description = models.CharField( - max_length=200, - blank=True - ) - comments = models.TextField( - blank=True - ) # Generic relations contacts = GenericRelation( diff --git a/netbox/circuits/models/providers.py b/netbox/circuits/models/providers.py index bd63ff0c6..18a81dcef 100644 --- a/netbox/circuits/models/providers.py +++ b/netbox/circuits/models/providers.py @@ -2,8 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation from django.db import models from django.urls import reverse -from dcim.fields import ASNField -from netbox.models import NetBoxModel +from netbox.models import PrimaryModel __all__ = ( 'ProviderNetwork', @@ -11,7 +10,7 @@ __all__ = ( ) -class Provider(NetBoxModel): +class Provider(PrimaryModel): """ Each Circuit belongs to a Provider. This is usually a telecommunications company or similar organization. This model stores information pertinent to the user's relationship with the Provider. @@ -34,9 +33,6 @@ class Provider(NetBoxModel): blank=True, verbose_name='Account number' ) - comments = models.TextField( - blank=True - ) # Generic relations contacts = GenericRelation( @@ -57,7 +53,7 @@ class Provider(NetBoxModel): return reverse('circuits:provider', args=[self.pk]) -class ProviderNetwork(NetBoxModel): +class ProviderNetwork(PrimaryModel): """ This represents a provider network which exists outside of NetBox, the details of which are unknown or unimportant to the user. @@ -75,13 +71,6 @@ class ProviderNetwork(NetBoxModel): blank=True, verbose_name='Service ID' ) - description = models.CharField( - max_length=200, - blank=True - ) - comments = models.TextField( - blank=True - ) class Meta: ordering = ('provider', 'name') diff --git a/netbox/circuits/tables/providers.py b/netbox/circuits/tables/providers.py index a117274ff..9de8d25b2 100644 --- a/netbox/circuits/tables/providers.py +++ b/netbox/circuits/tables/providers.py @@ -39,8 +39,8 @@ class ProviderTable(ContactsColumnMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = Provider fields = ( - 'pk', 'id', 'name', 'asns', 'account', 'asn_count', - 'circuit_count', 'comments', 'contacts', 'tags', 'created', 'last_updated', + 'pk', 'id', 'name', 'asns', 'account', 'asn_count', 'circuit_count', 'description', 'comments', 'contacts', + 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'account', 'circuit_count') diff --git a/netbox/dcim/api/serializers.py b/netbox/dcim/api/serializers.py index 19de84791..9317d7c51 100644 --- a/netbox/dcim/api/serializers.py +++ b/netbox/dcim/api/serializers.py @@ -210,8 +210,8 @@ class RackSerializer(NetBoxModelSerializer): fields = [ 'id', 'url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'weight', 'weight_unit', 'desc_units', 'outer_width', - 'outer_depth', 'outer_unit', 'mounting_depth', 'comments', 'tags', 'custom_fields', 'created', - 'last_updated', 'device_count', 'powerfeed_count', + 'outer_depth', 'outer_unit', 'mounting_depth', 'description', 'comments', 'tags', 'custom_fields', + 'created', 'last_updated', 'device_count', 'powerfeed_count', ] @@ -243,8 +243,8 @@ class RackReservationSerializer(NetBoxModelSerializer): class Meta: model = RackReservation fields = [ - 'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description', 'tags', - 'custom_fields', + 'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description', + 'comments', 'tags', 'custom_fields', ] @@ -324,8 +324,8 @@ class DeviceTypeSerializer(NetBoxModelSerializer): model = DeviceType fields = [ 'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', - 'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'comments', 'tags', - 'custom_fields', 'created', 'last_updated', 'device_count', + 'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'description', + 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', ] @@ -333,13 +333,12 @@ class ModuleTypeSerializer(NetBoxModelSerializer): url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail') manufacturer = NestedManufacturerSerializer() weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False) - # module_count = serializers.IntegerField(read_only=True) class Meta: model = ModuleType fields = [ - 'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'comments', 'tags', - 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'description', + 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] @@ -656,8 +655,8 @@ class DeviceSerializer(NetBoxModelSerializer): fields = [ 'id', 'url', 'display', 'name', 'device_type', 'device_role', 'tenant', 'platform', 'serial', 'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'parent_device', 'status', 'airflow', 'primary_ip', - 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'comments', - 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', + 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', 'vc_priority', 'description', + 'comments', 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', ] @swagger_serializer_method(serializer_or_field=NestedDeviceSerializer) @@ -681,8 +680,8 @@ class ModuleSerializer(NetBoxModelSerializer): class Meta: model = Module fields = [ - 'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'comments', 'tags', - 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'description', + 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] @@ -1020,7 +1019,7 @@ class CableSerializer(NetBoxModelSerializer): model = Cable fields = [ 'id', 'url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant', 'label', 'color', - 'length', 'length_unit', 'tags', 'custom_fields', 'created', 'last_updated', + 'length', 'length_unit', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] @@ -1086,8 +1085,8 @@ class VirtualChassisSerializer(NetBoxModelSerializer): class Meta: model = VirtualChassis fields = [ - 'id', 'url', 'display', 'name', 'domain', 'master', 'tags', 'custom_fields', 'member_count', - 'created', 'last_updated', + 'id', 'url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'custom_fields', + 'member_count', 'created', 'last_updated', ] @@ -1108,8 +1107,8 @@ class PowerPanelSerializer(NetBoxModelSerializer): class Meta: model = PowerPanel fields = [ - 'id', 'url', 'display', 'site', 'location', 'name', 'tags', 'custom_fields', 'powerfeed_count', - 'created', 'last_updated', + 'id', 'url', 'display', 'site', 'location', 'name', 'description', 'comments', 'tags', 'custom_fields', + 'powerfeed_count', 'created', 'last_updated', ] @@ -1142,7 +1141,7 @@ class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect model = PowerFeed fields = [ 'id', 'url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage', - 'amperage', 'max_utilization', 'comments', 'mark_connected', 'cable', 'cable_end', 'link_peers', - 'link_peers_type', 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', - 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', + 'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', + 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'description', + 'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied', ] diff --git a/netbox/dcim/forms/bulk_edit.py b/netbox/dcim/forms/bulk_edit.py index e3b69dc81..1e58dd2f7 100644 --- a/netbox/dcim/forms/bulk_edit.py +++ b/netbox/dcim/forms/bulk_edit.py @@ -127,22 +127,26 @@ class SiteBulkEditForm(NetBoxModelBulkEditForm): required=False, label='Contact E-mail' ) - description = forms.CharField( - max_length=100, - required=False - ) time_zone = TimeZoneFormField( choices=add_blank_choice(TimeZoneFormField().choices), required=False, widget=StaticSelect() ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Site fieldsets = ( (None, ('status', 'region', 'group', 'tenant', 'asns', 'time_zone', 'description')), ) nullable_fields = ( - 'region', 'group', 'tenant', 'asns', 'description', 'time_zone', + 'region', 'group', 'tenant', 'asns', 'time_zone', 'description', 'comments', ) @@ -285,10 +289,6 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): required=False, min_value=1 ) - comments = CommentField( - widget=SmallTextarea, - label='Comments' - ) weight = forms.DecimalField( min_value=0, required=False @@ -299,10 +299,18 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): initial='', widget=StaticSelect() ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Rack fieldsets = ( - ('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag')), + ('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag', 'description')), ('Location', ('region', 'site_group', 'site', 'location')), ('Hardware', ( 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', @@ -310,8 +318,8 @@ class RackBulkEditForm(NetBoxModelBulkEditForm): ('Weight', ('weight', 'weight_unit')), ) nullable_fields = ( - 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'comments', - 'weight', 'weight_unit' + 'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'weight', + 'weight_unit', 'description', 'comments', ) @@ -328,14 +336,19 @@ class RackReservationBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = RackReservation fieldsets = ( (None, ('user', 'tenant', 'description')), ) + nullable_fields = ('comments',) class ManufacturerBulkEditForm(NetBoxModelBulkEditForm): @@ -383,13 +396,21 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm): initial='', widget=StaticSelect() ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = DeviceType fieldsets = ( - ('Device Type', ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow')), + ('Device Type', ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow', 'description')), ('Weight', ('weight', 'weight_unit')), ) - nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit') + nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit', 'description', 'comments') class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): @@ -410,13 +431,21 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm): initial='', widget=StaticSelect() ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = ModuleType fieldsets = ( - ('Module Type', ('manufacturer', 'part_number')), + ('Module Type', ('manufacturer', 'part_number', 'description')), ('Weight', ('weight', 'weight_unit')), ) - nullable_fields = ('part_number', 'weight', 'weight_unit') + nullable_fields = ('part_number', 'weight', 'weight_unit', 'description', 'comments') class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm): @@ -512,15 +541,23 @@ class DeviceBulkEditForm(NetBoxModelBulkEditForm): required=False, label='Serial Number' ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Device fieldsets = ( - ('Device', ('device_role', 'status', 'tenant', 'platform')), + ('Device', ('device_role', 'status', 'tenant', 'platform', 'description')), ('Location', ('site', 'location')), ('Hardware', ('manufacturer', 'device_type', 'airflow', 'serial')), ) nullable_fields = ( - 'location', 'tenant', 'platform', 'serial', 'airflow', + 'location', 'tenant', 'platform', 'serial', 'airflow', 'description', 'comments', ) @@ -541,12 +578,20 @@ class ModuleBulkEditForm(NetBoxModelBulkEditForm): required=False, label='Serial Number' ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Module fieldsets = ( - (None, ('manufacturer', 'module_type', 'serial')), + (None, ('manufacturer', 'module_type', 'serial', 'description')), ) - nullable_fields = ('serial',) + nullable_fields = ('serial', 'description', 'comments') class CableBulkEditForm(NetBoxModelBulkEditForm): @@ -583,14 +628,22 @@ class CableBulkEditForm(NetBoxModelBulkEditForm): initial='', widget=StaticSelect() ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Cable fieldsets = ( - (None, ('type', 'status', 'tenant', 'label')), + (None, ('type', 'status', 'tenant', 'label', 'description')), ('Attributes', ('color', 'length', 'length_unit')), ) nullable_fields = ( - 'type', 'status', 'tenant', 'label', 'color', 'length', + 'type', 'status', 'tenant', 'label', 'color', 'length', 'description', 'comments', ) @@ -599,12 +652,20 @@ class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm): max_length=30, required=False ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = VirtualChassis fieldsets = ( - (None, ('domain',)), + (None, ('domain', 'description')), ) - nullable_fields = ('domain',) + nullable_fields = ('domain', 'description', 'comments') class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): @@ -637,12 +698,20 @@ class PowerPanelBulkEditForm(NetBoxModelBulkEditForm): 'site_id': '$site' } ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = PowerPanel fieldsets = ( - (None, ('region', 'site_group', 'site', 'location')), + (None, ('region', 'site_group', 'site', 'location', 'description')), ) - nullable_fields = ('location',) + nullable_fields = ('location', 'description', 'comments') class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): @@ -691,6 +760,10 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): required=False, widget=BulkEditNullBooleanSelect ) + description = forms.CharField( + max_length=200, + required=False + ) comments = CommentField( widget=SmallTextarea, label='Comments' @@ -698,10 +771,10 @@ class PowerFeedBulkEditForm(NetBoxModelBulkEditForm): model = PowerFeed fieldsets = ( - (None, ('power_panel', 'rack', 'status', 'type', 'mark_connected')), + (None, ('power_panel', 'rack', 'status', 'type', 'mark_connected', 'description')), ('Power', ('supply', 'phase', 'voltage', 'amperage', 'max_utilization')) ) - nullable_fields = ('location', 'comments') + nullable_fields = ('location', 'description', 'comments') # diff --git a/netbox/dcim/forms/bulk_import.py b/netbox/dcim/forms/bulk_import.py index 13e788e75..4c90c9c02 100644 --- a/netbox/dcim/forms/bulk_import.py +++ b/netbox/dcim/forms/bulk_import.py @@ -196,7 +196,8 @@ class RackCSVForm(NetBoxModelCSVForm): model = Rack fields = ( 'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'asset_tag', - 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'comments', + 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', + 'description', 'comments', ) def __init__(self, data=None, *args, **kwargs): @@ -240,7 +241,7 @@ class RackReservationCSVForm(NetBoxModelCSVForm): class Meta: model = RackReservation - fields = ('site', 'location', 'rack', 'units', 'tenant', 'description') + fields = ('site', 'location', 'rack', 'units', 'tenant', 'description', 'comments') def __init__(self, data=None, *args, **kwargs): super().__init__(data, *args, **kwargs) @@ -387,7 +388,7 @@ class DeviceCSVForm(BaseDeviceCSVForm): fields = [ 'name', 'device_role', 'tenant', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'status', 'site', 'location', 'rack', 'position', 'face', 'airflow', 'virtual_chassis', 'vc_position', 'vc_priority', - 'cluster', 'comments', + 'cluster', 'description', 'comments', ] def __init__(self, data=None, *args, **kwargs): @@ -424,7 +425,7 @@ class ModuleCSVForm(NetBoxModelCSVForm): class Meta: model = Module fields = ( - 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'comments', + 'device', 'module_bay', 'module_type', 'serial', 'asset_tag', 'description', 'comments', ) def __init__(self, data=None, *args, **kwargs): @@ -927,7 +928,7 @@ class CableCSVForm(NetBoxModelCSVForm): model = Cable fields = [ 'side_a_device', 'side_a_type', 'side_a_name', 'side_b_device', 'side_b_type', 'side_b_name', 'type', - 'status', 'tenant', 'label', 'color', 'length', 'length_unit', + 'status', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', 'comments', ] help_texts = { 'color': mark_safe('RGB color in hexadecimal (e.g. 00ff00)'), @@ -984,7 +985,7 @@ class VirtualChassisCSVForm(NetBoxModelCSVForm): class Meta: model = VirtualChassis - fields = ('name', 'domain', 'master') + fields = ('name', 'domain', 'master', 'description') # @@ -1005,7 +1006,7 @@ class PowerPanelCSVForm(NetBoxModelCSVForm): class Meta: model = PowerPanel - fields = ('site', 'location', 'name') + fields = ('site', 'location', 'name', 'description', 'comments') def __init__(self, data=None, *args, **kwargs): super().__init__(data, *args, **kwargs) @@ -1061,7 +1062,7 @@ class PowerFeedCSVForm(NetBoxModelCSVForm): model = PowerFeed fields = ( 'site', 'power_panel', 'location', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', 'phase', - 'voltage', 'amperage', 'max_utilization', 'comments', + 'voltage', 'amperage', 'max_utilization', 'description', 'comments', ) def __init__(self, data=None, *args, **kwargs): diff --git a/netbox/dcim/forms/model_forms.py b/netbox/dcim/forms/model_forms.py index 0da2f3430..539c48709 100644 --- a/netbox/dcim/forms/model_forms.py +++ b/netbox/dcim/forms/model_forms.py @@ -278,7 +278,7 @@ class RackForm(TenancyForm, NetBoxModelForm): fields = [ 'region', 'site_group', 'site', 'location', 'name', 'facility_id', 'tenant_group', 'tenant', 'status', 'role', 'serial', 'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', - 'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'comments', 'tags', + 'outer_unit', 'mounting_depth', 'weight', 'weight_unit', 'description', 'comments', 'tags', ] help_texts = { 'site': "The site at which the rack exists", @@ -342,6 +342,7 @@ class RackReservationForm(TenancyForm, NetBoxModelForm): ), widget=StaticSelect() ) + comments = CommentField() fieldsets = ( ('Reservation', ('region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'description', 'tags')), @@ -352,7 +353,7 @@ class RackReservationForm(TenancyForm, NetBoxModelForm): model = RackReservation fields = [ 'region', 'site_group', 'site', 'location', 'rack', 'units', 'user', 'tenant_group', 'tenant', - 'description', 'tags', + 'description', 'comments', 'tags', ] @@ -383,10 +384,10 @@ class DeviceTypeForm(NetBoxModelForm): fieldsets = ( ('Device Type', ( - 'manufacturer', 'model', 'slug', 'part_number', 'tags', + 'manufacturer', 'model', 'slug', 'description', 'tags', )), ('Chassis', ( - 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', + 'u_height', 'is_full_depth', 'part_number', 'subdevice_role', 'airflow', )), ('Attributes', ('weight', 'weight_unit')), ('Images', ('front_image', 'rear_image')), @@ -396,7 +397,7 @@ class DeviceTypeForm(NetBoxModelForm): model = DeviceType fields = [ 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', - 'weight', 'weight_unit', 'front_image', 'rear_image', 'comments', 'tags', + 'weight', 'weight_unit', 'front_image', 'rear_image', 'description', 'comments', 'tags', ] widgets = { 'airflow': StaticSelect(), @@ -418,15 +419,14 @@ class ModuleTypeForm(NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Module Type', ( - 'manufacturer', 'model', 'part_number', 'tags', 'weight', 'weight_unit' - )), + ('Module Type', ('manufacturer', 'model', 'part_number', 'description', 'tags')), + ('Weight', ('weight', 'weight_unit')) ) class Meta: model = ModuleType fields = [ - 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'comments', 'tags', + 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'description', 'comments', 'tags', ] widgets = { @@ -591,7 +591,7 @@ class DeviceForm(TenancyForm, NetBoxModelForm): 'name', 'device_role', 'device_type', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'rack', 'location', 'position', 'face', 'status', 'airflow', 'platform', 'primary_ip4', 'primary_ip6', 'cluster_group', 'cluster', 'tenant_group', 'tenant', 'virtual_chassis', 'vc_position', 'vc_priority', - 'comments', 'tags', 'local_context_data' + 'description', 'comments', 'tags', 'local_context_data' ] help_texts = { 'device_role': "The function this device serves", @@ -705,7 +705,7 @@ class ModuleForm(NetBoxModelForm): fieldsets = ( ('Module', ( - 'device', 'module_bay', 'manufacturer', 'module_type', 'tags', + 'device', 'module_bay', 'manufacturer', 'module_type', 'description', 'tags', )), ('Hardware', ( 'serial', 'asset_tag', 'replicate_components', 'adopt_components', @@ -716,7 +716,7 @@ class ModuleForm(NetBoxModelForm): model = Module fields = [ 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', 'tags', - 'replicate_components', 'adopt_components', 'comments', + 'replicate_components', 'adopt_components', 'description', 'comments', ] def __init__(self, *args, **kwargs): @@ -793,11 +793,13 @@ class ModuleForm(NetBoxModelForm): class CableForm(TenancyForm, NetBoxModelForm): + comments = CommentField() class Meta: model = Cable fields = [ - 'type', 'status', 'tenant_group', 'tenant', 'label', 'color', 'length', 'length_unit', 'tags', + 'type', 'status', 'tenant_group', 'tenant', 'label', 'color', 'length', 'length_unit', 'description', + 'comments', 'tags', ] widgets = { 'status': StaticSelect, @@ -840,15 +842,16 @@ class PowerPanelForm(NetBoxModelForm): 'site_id': '$site' } ) + comments = CommentField() fieldsets = ( - ('Power Panel', ('region', 'site_group', 'site', 'location', 'name', 'tags')), + ('Power Panel', ('region', 'site_group', 'site', 'location', 'name', 'description', 'tags')), ) class Meta: model = PowerPanel fields = [ - 'region', 'site_group', 'site', 'location', 'name', 'tags', + 'region', 'site_group', 'site', 'location', 'name', 'description', 'comments', 'tags', ] @@ -894,7 +897,7 @@ class PowerFeedForm(NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Power Panel', ('region', 'site', 'power_panel')), + ('Power Panel', ('region', 'site', 'power_panel', 'description')), ('Power Feed', ('rack', 'name', 'status', 'type', 'mark_connected', 'tags')), ('Characteristics', ('supply', 'voltage', 'amperage', 'phase', 'max_utilization')), ) @@ -903,7 +906,7 @@ class PowerFeedForm(NetBoxModelForm): model = PowerFeed fields = [ 'region', 'site_group', 'site', 'power_panel', 'rack', 'name', 'status', 'type', 'mark_connected', 'supply', - 'phase', 'voltage', 'amperage', 'max_utilization', 'comments', 'tags', + 'phase', 'voltage', 'amperage', 'max_utilization', 'description', 'comments', 'tags', ] widgets = { 'status': StaticSelect(), @@ -922,11 +925,12 @@ class VirtualChassisForm(NetBoxModelForm): queryset=Device.objects.all(), required=False, ) + comments = CommentField() class Meta: model = VirtualChassis fields = [ - 'name', 'domain', 'master', 'tags', + 'name', 'domain', 'master', 'description', 'comments', 'tags', ] widgets = { 'master': SelectWithPK(), diff --git a/netbox/dcim/forms/object_import.py b/netbox/dcim/forms/object_import.py index 023aba8f1..82ee093dd 100644 --- a/netbox/dcim/forms/object_import.py +++ b/netbox/dcim/forms/object_import.py @@ -30,7 +30,7 @@ class DeviceTypeImportForm(BootstrapMixin, forms.ModelForm): model = DeviceType fields = [ 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', - 'comments', + 'description', 'comments', ] @@ -42,7 +42,7 @@ class ModuleTypeImportForm(BootstrapMixin, forms.ModelForm): class Meta: model = ModuleType - fields = ['manufacturer', 'model', 'part_number', 'comments'] + fields = ['manufacturer', 'model', 'part_number', 'description', 'comments'] # diff --git a/netbox/dcim/migrations/0165_standardize_description_comments.py b/netbox/dcim/migrations/0165_standardize_description_comments.py new file mode 100644 index 000000000..f17f1d321 --- /dev/null +++ b/netbox/dcim/migrations/0165_standardize_description_comments.py @@ -0,0 +1,78 @@ +# Generated by Django 4.1.2 on 2022-11-03 18:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('dcim', '0164_rack_mounting_depth'), + ] + + operations = [ + migrations.AddField( + model_name='cable', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='cable', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='device', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='devicetype', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='module', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='moduletype', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='powerfeed', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='powerpanel', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='powerpanel', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='rack', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='rackreservation', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='virtualchassis', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='virtualchassis', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + ] diff --git a/netbox/dcim/models/cables.py b/netbox/dcim/models/cables.py index fad3e8bd6..c51b59f94 100644 --- a/netbox/dcim/models/cables.py +++ b/netbox/dcim/models/cables.py @@ -12,8 +12,8 @@ from django.urls import reverse from dcim.choices import * from dcim.constants import * from dcim.fields import PathField -from dcim.utils import decompile_path_node, object_to_path_node, path_node_to_object -from netbox.models import NetBoxModel +from dcim.utils import decompile_path_node, object_to_path_node +from netbox.models import PrimaryModel from utilities.fields import ColorField from utilities.querysets import RestrictedQuerySet from utilities.utils import to_meters @@ -34,7 +34,7 @@ trace_paths = Signal() # Cables # -class Cable(NetBoxModel): +class Cable(PrimaryModel): """ A physical connection between two endpoints. """ diff --git a/netbox/dcim/models/devices.py b/netbox/dcim/models/devices.py index 3710bf7f4..78282f893 100644 --- a/netbox/dcim/models/devices.py +++ b/netbox/dcim/models/devices.py @@ -18,7 +18,7 @@ from dcim.constants import * from extras.models import ConfigContextModel from extras.querysets import ConfigContextModelQuerySet from netbox.config import ConfigItem -from netbox.models import OrganizationalModel, NetBoxModel +from netbox.models import OrganizationalModel, PrimaryModel from utilities.choices import ColorChoices from utilities.fields import ColorField, NaturalOrderingField from .device_components import * @@ -54,7 +54,7 @@ class Manufacturer(OrganizationalModel): return reverse('dcim:manufacturer', args=[self.pk]) -class DeviceType(NetBoxModel, WeightMixin): +class DeviceType(PrimaryModel, WeightMixin): """ A DeviceType represents a particular make (Manufacturer) and model of device. It specifies rack height and depth, as well as high-level functional role(s). @@ -117,9 +117,6 @@ class DeviceType(NetBoxModel, WeightMixin): upload_to='devicetype-images', blank=True ) - comments = models.TextField( - blank=True - ) clone_fields = ( 'manufacturer', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit', @@ -298,7 +295,7 @@ class DeviceType(NetBoxModel, WeightMixin): return self.subdevice_role == SubdeviceRoleChoices.ROLE_CHILD -class ModuleType(NetBoxModel, WeightMixin): +class ModuleType(PrimaryModel, WeightMixin): """ A ModuleType represents a hardware element that can be installed within a device and which houses additional components; for example, a line card within a chassis-based switch such as the Cisco Catalyst 6500. Like a @@ -318,9 +315,6 @@ class ModuleType(NetBoxModel, WeightMixin): blank=True, help_text='Discrete part number (optional)' ) - comments = models.TextField( - blank=True - ) # Generic relations images = GenericRelation( @@ -443,7 +437,7 @@ class Platform(OrganizationalModel): return reverse('dcim:platform', args=[self.pk]) -class Device(NetBoxModel, ConfigContextModel): +class Device(PrimaryModel, ConfigContextModel): """ A Device represents a piece of physical hardware mounted within a Rack. Each Device is assigned a DeviceType, DeviceRole, and (optionally) a Platform. Device names are not required, however if one is set it must be unique. @@ -587,9 +581,6 @@ class Device(NetBoxModel, ConfigContextModel): null=True, validators=[MaxValueValidator(255)] ) - comments = models.TextField( - blank=True - ) # Generic relations contacts = GenericRelation( @@ -906,7 +897,7 @@ class Device(NetBoxModel, ConfigContextModel): return round(total_weight / 1000, 2) -class Module(NetBoxModel, ConfigContextModel): +class Module(PrimaryModel, ConfigContextModel): """ A Module represents a field-installable component within a Device which may itself hold multiple device components (for example, a line card within a chassis switch). Modules are instantiated from ModuleTypes. @@ -939,9 +930,6 @@ class Module(NetBoxModel, ConfigContextModel): verbose_name='Asset tag', help_text='A unique tag used to identify this device' ) - comments = models.TextField( - blank=True - ) clone_fields = ('device', 'module_type') @@ -1019,7 +1007,7 @@ class Module(NetBoxModel, ConfigContextModel): # Virtual chassis # -class VirtualChassis(NetBoxModel): +class VirtualChassis(PrimaryModel): """ A collection of Devices which operate with a shared control plane (e.g. a switch stack). """ diff --git a/netbox/dcim/models/power.py b/netbox/dcim/models/power.py index 39f0f37ef..e79cf4c44 100644 --- a/netbox/dcim/models/power.py +++ b/netbox/dcim/models/power.py @@ -6,9 +6,8 @@ from django.db import models from django.urls import reverse from dcim.choices import * -from dcim.constants import * from netbox.config import ConfigItem -from netbox.models import NetBoxModel +from netbox.models import PrimaryModel from utilities.validators import ExclusionValidator from .device_components import CabledObjectModel, PathEndpoint @@ -22,7 +21,7 @@ __all__ = ( # Power # -class PowerPanel(NetBoxModel): +class PowerPanel(PrimaryModel): """ A distribution point for electrical power; e.g. a data center RPP. """ @@ -77,7 +76,7 @@ class PowerPanel(NetBoxModel): ) -class PowerFeed(NetBoxModel, PathEndpoint, CabledObjectModel): +class PowerFeed(PrimaryModel, PathEndpoint, CabledObjectModel): """ An electrical circuit delivered from a PowerPanel. """ @@ -132,9 +131,6 @@ class PowerFeed(NetBoxModel, PathEndpoint, CabledObjectModel): default=0, editable=False ) - comments = models.TextField( - blank=True - ) clone_fields = ( 'power_panel', 'rack', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage', diff --git a/netbox/dcim/models/racks.py b/netbox/dcim/models/racks.py index e61765e69..e37fc8dc3 100644 --- a/netbox/dcim/models/racks.py +++ b/netbox/dcim/models/racks.py @@ -14,7 +14,7 @@ from django.urls import reverse from dcim.choices import * from dcim.constants import * from dcim.svg import RackElevationSVG -from netbox.models import OrganizationalModel, NetBoxModel +from netbox.models import OrganizationalModel, PrimaryModel from utilities.choices import ColorChoices from utilities.fields import ColorField, NaturalOrderingField from utilities.utils import array_to_string, drange @@ -46,7 +46,7 @@ class RackRole(OrganizationalModel): return reverse('dcim:rackrole', args=[self.pk]) -class Rack(NetBoxModel, WeightMixin): +class Rack(PrimaryModel, WeightMixin): """ Devices are housed within Racks. Each rack has a defined height measured in rack units, and a front and rear face. Each Rack is assigned to a Site and (optionally) a Location. @@ -157,9 +157,6 @@ class Rack(NetBoxModel, WeightMixin): 'distance between the front and rear rails.' ) ) - comments = models.TextField( - blank=True - ) # Generic relations vlan_groups = GenericRelation( @@ -463,7 +460,7 @@ class Rack(NetBoxModel, WeightMixin): return round(total_weight / 1000, 2) -class RackReservation(NetBoxModel): +class RackReservation(PrimaryModel): """ One or more reserved units within a Rack. """ diff --git a/netbox/dcim/models/sites.py b/netbox/dcim/models/sites.py index c352b69de..c760119fb 100644 --- a/netbox/dcim/models/sites.py +++ b/netbox/dcim/models/sites.py @@ -6,7 +6,7 @@ from timezone_field import TimeZoneField from dcim.choices import * from dcim.constants import * -from netbox.models import NestedGroupModel, NetBoxModel +from netbox.models import NestedGroupModel, PrimaryModel from utilities.fields import NaturalOrderingField __all__ = ( @@ -131,7 +131,7 @@ class SiteGroup(NestedGroupModel): # Sites # -class Site(NetBoxModel): +class Site(PrimaryModel): """ A Site represents a geographic location within a network; typically a building or campus. The optional facility field can be used to include an external designation, such as a data center name (e.g. Equinix SV6). @@ -188,10 +188,6 @@ class Site(NetBoxModel): time_zone = TimeZoneField( blank=True ) - description = models.CharField( - max_length=200, - blank=True - ) physical_address = models.CharField( max_length=200, blank=True @@ -214,9 +210,6 @@ class Site(NetBoxModel): null=True, help_text='GPS coordinate (longitude)' ) - comments = models.TextField( - blank=True - ) # Generic relations vlan_groups = GenericRelation( diff --git a/netbox/dcim/tables/cables.py b/netbox/dcim/tables/cables.py index e5410e42a..6e9d49719 100644 --- a/netbox/dcim/tables/cables.py +++ b/netbox/dcim/tables/cables.py @@ -111,6 +111,7 @@ class CableTable(TenancyColumnsMixin, NetBoxTable): order_by=('_abs_length', 'length_unit') ) color = columns.ColorColumn() + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='dcim:cable_list' ) @@ -120,7 +121,7 @@ class CableTable(TenancyColumnsMixin, NetBoxTable): fields = ( 'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'device_a', 'device_b', 'rack_a', 'rack_b', 'location_a', 'location_b', 'site_a', 'site_b', 'status', 'type', 'tenant', 'tenant_group', 'color', - 'length', 'tags', 'created', 'last_updated', + 'length', 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'id', 'label', 'a_terminations', 'b_terminations', 'status', 'type', diff --git a/netbox/dcim/tables/devices.py b/netbox/dcim/tables/devices.py index 3b129c963..45a210080 100644 --- a/netbox/dcim/tables/devices.py +++ b/netbox/dcim/tables/devices.py @@ -1,21 +1,5 @@ import django_tables2 as tables -from dcim.models import ( - ConsolePort, - ConsoleServerPort, - Device, - DeviceBay, - DeviceRole, - FrontPort, - Interface, - InventoryItem, - InventoryItemRole, - ModuleBay, - Platform, - PowerOutlet, - PowerPort, - RearPort, - VirtualChassis, -) +from dcim import models from django_tables2.utils import Accessor from tenancy.tables import ContactsColumnMixin, TenancyColumnsMixin @@ -106,7 +90,7 @@ class DeviceRoleTable(NetBoxTable): ) class Meta(NetBoxTable.Meta): - model = DeviceRole + model = models.DeviceRole fields = ( 'pk', 'id', 'name', 'device_count', 'vm_count', 'color', 'vm_role', 'description', 'slug', 'tags', 'actions', 'created', 'last_updated', @@ -137,7 +121,7 @@ class PlatformTable(NetBoxTable): ) class Meta(NetBoxTable.Meta): - model = Platform + model = models.Platform fields = ( 'pk', 'id', 'name', 'manufacturer', 'device_count', 'vm_count', 'slug', 'napalm_driver', 'napalm_args', 'description', 'tags', 'actions', 'created', 'last_updated', @@ -220,12 +204,12 @@ class DeviceTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): ) class Meta(NetBoxTable.Meta): - model = Device + model = models.Device fields = ( 'pk', 'id', 'name', 'status', 'tenant', 'tenant_group', 'device_role', 'manufacturer', 'device_type', 'platform', 'serial', 'asset_tag', 'region', 'site_group', 'site', 'location', 'rack', 'position', 'face', 'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'cluster', 'virtual_chassis', 'vc_position', - 'vc_priority', 'comments', 'contacts', 'tags', 'created', 'last_updated', + 'vc_priority', 'description', 'comments', 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'status', 'tenant', 'site', 'location', 'rack', 'device_role', 'manufacturer', 'device_type', @@ -252,7 +236,7 @@ class DeviceImportTable(TenancyColumnsMixin, NetBoxTable): ) class Meta(NetBoxTable.Meta): - model = Device + model = models.Device fields = ('id', 'name', 'status', 'tenant', 'tenant_group', 'site', 'rack', 'position', 'device_role', 'device_type') empty_text = False @@ -326,7 +310,7 @@ class ConsolePortTable(ModularDeviceComponentTable, PathEndpointTable): ) class Meta(DeviceComponentTable.Meta): - model = ConsolePort + model = models.ConsolePort fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', 'last_updated', @@ -345,7 +329,7 @@ class DeviceConsolePortTable(ConsolePortTable): ) class Meta(DeviceComponentTable.Meta): - model = ConsolePort + model = models.ConsolePort fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions' @@ -368,7 +352,7 @@ class ConsoleServerPortTable(ModularDeviceComponentTable, PathEndpointTable): ) class Meta(DeviceComponentTable.Meta): - model = ConsoleServerPort + model = models.ConsoleServerPort fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', 'last_updated', @@ -388,7 +372,7 @@ class DeviceConsoleServerPortTable(ConsoleServerPortTable): ) class Meta(DeviceComponentTable.Meta): - model = ConsoleServerPort + model = models.ConsoleServerPort fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'speed', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions', @@ -411,7 +395,7 @@ class PowerPortTable(ModularDeviceComponentTable, PathEndpointTable): ) class Meta(DeviceComponentTable.Meta): - model = PowerPort + model = models.PowerPort fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'mark_connected', 'maximum_draw', 'allocated_draw', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', @@ -432,7 +416,7 @@ class DevicePowerPortTable(PowerPortTable): ) class Meta(DeviceComponentTable.Meta): - model = PowerPort + model = models.PowerPort fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions', @@ -460,7 +444,7 @@ class PowerOutletTable(ModularDeviceComponentTable, PathEndpointTable): ) class Meta(DeviceComponentTable.Meta): - model = PowerOutlet + model = models.PowerOutlet fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'description', 'power_port', 'feed_leg', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'created', @@ -480,7 +464,7 @@ class DevicePowerOutletTable(PowerOutletTable): ) class Meta(DeviceComponentTable.Meta): - model = PowerOutlet + model = models.PowerOutlet fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'power_port', 'feed_leg', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'tags', 'actions', @@ -544,7 +528,7 @@ class InterfaceTable(ModularDeviceComponentTable, BaseInterfaceTable, PathEndpoi ) class Meta(DeviceComponentTable.Meta): - model = Interface + model = models.Interface fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'enabled', 'type', 'mgmt_only', 'mtu', 'speed', 'duplex', 'mode', 'mac_address', 'wwn', 'poe_mode', 'poe_type', 'rf_role', 'rf_channel', @@ -578,7 +562,7 @@ class DeviceInterfaceTable(InterfaceTable): ) class Meta(DeviceComponentTable.Meta): - model = Interface + model = models.Interface fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'enabled', 'type', 'parent', 'bridge', 'lag', 'mgmt_only', 'mtu', 'mode', 'mac_address', 'wwn', 'rf_role', 'rf_channel', 'rf_channel_frequency', @@ -617,7 +601,7 @@ class FrontPortTable(ModularDeviceComponentTable, CableTerminationTable): ) class Meta(DeviceComponentTable.Meta): - model = FrontPort + model = models.FrontPort fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', @@ -640,7 +624,7 @@ class DeviceFrontPortTable(FrontPortTable): ) class Meta(DeviceComponentTable.Meta): - model = FrontPort + model = models.FrontPort fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'actions', @@ -666,7 +650,7 @@ class RearPortTable(ModularDeviceComponentTable, CableTerminationTable): ) class Meta(DeviceComponentTable.Meta): - model = RearPort + model = models.RearPort fields = ( 'pk', 'id', 'name', 'device', 'module_bay', 'module', 'label', 'type', 'color', 'positions', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'created', 'last_updated', @@ -686,7 +670,7 @@ class DeviceRearPortTable(RearPortTable): ) class Meta(DeviceComponentTable.Meta): - model = RearPort + model = models.RearPort fields = ( 'pk', 'id', 'name', 'module_bay', 'module', 'label', 'type', 'positions', 'description', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'tags', 'actions', @@ -727,7 +711,7 @@ class DeviceBayTable(DeviceComponentTable): ) class Meta(DeviceComponentTable.Meta): - model = DeviceBay + model = models.DeviceBay fields = ( 'pk', 'id', 'name', 'device', 'label', 'status', 'device_role', 'device_type', 'installed_device', 'description', 'tags', 'created', 'last_updated', @@ -748,7 +732,7 @@ class DeviceDeviceBayTable(DeviceBayTable): ) class Meta(DeviceComponentTable.Meta): - model = DeviceBay + model = models.DeviceBay fields = ( 'pk', 'id', 'name', 'label', 'status', 'installed_device', 'description', 'tags', 'actions', ) @@ -777,7 +761,7 @@ class ModuleBayTable(DeviceComponentTable): ) class Meta(DeviceComponentTable.Meta): - model = ModuleBay + model = models.ModuleBay fields = ( 'pk', 'id', 'name', 'device', 'label', 'position', 'installed_module', 'module_serial', 'module_asset_tag', 'description', 'tags', @@ -791,7 +775,7 @@ class DeviceModuleBayTable(ModuleBayTable): ) class Meta(DeviceComponentTable.Meta): - model = ModuleBay + model = models.ModuleBay fields = ( 'pk', 'id', 'name', 'label', 'position', 'installed_module', 'module_serial', 'module_asset_tag', 'description', 'tags', 'actions', @@ -821,7 +805,7 @@ class InventoryItemTable(DeviceComponentTable): cable = None # Override DeviceComponentTable class Meta(NetBoxTable.Meta): - model = InventoryItem + model = models.InventoryItem fields = ( 'pk', 'id', 'name', 'device', 'component', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'description', 'discovered', 'tags', 'created', 'last_updated', @@ -840,7 +824,7 @@ class DeviceInventoryItemTable(InventoryItemTable): ) class Meta(NetBoxTable.Meta): - model = InventoryItem + model = models.InventoryItem fields = ( 'pk', 'id', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial', 'asset_tag', 'component', 'description', 'discovered', 'tags', 'actions', @@ -865,7 +849,7 @@ class InventoryItemRoleTable(NetBoxTable): ) class Meta(NetBoxTable.Meta): - model = InventoryItemRole + model = models.InventoryItemRole fields = ( 'pk', 'id', 'name', 'inventoryitem_count', 'color', 'description', 'slug', 'tags', 'actions', ) @@ -888,11 +872,15 @@ class VirtualChassisTable(NetBoxTable): url_params={'virtual_chassis_id': 'pk'}, verbose_name='Members' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='dcim:virtualchassis_list' ) class Meta(NetBoxTable.Meta): - model = VirtualChassis - fields = ('pk', 'id', 'name', 'domain', 'master', 'member_count', 'tags', 'created', 'last_updated',) + model = models.VirtualChassis + fields = ( + 'pk', 'id', 'name', 'domain', 'master', 'member_count', 'description', 'comments', 'tags', 'created', + 'last_updated', + ) default_columns = ('pk', 'name', 'domain', 'master', 'member_count') diff --git a/netbox/dcim/tables/devicetypes.py b/netbox/dcim/tables/devicetypes.py index 19b04c70d..a52d41b70 100644 --- a/netbox/dcim/tables/devicetypes.py +++ b/netbox/dcim/tables/devicetypes.py @@ -1,19 +1,6 @@ import django_tables2 as tables -from dcim.models import ( - ConsolePortTemplate, - ConsoleServerPortTemplate, - DeviceBayTemplate, - DeviceType, - FrontPortTemplate, - InterfaceTemplate, - InventoryItemTemplate, - Manufacturer, - ModuleBayTemplate, - PowerOutletTemplate, - PowerPortTemplate, - RearPortTemplate, -) +from dcim import models from netbox.tables import NetBoxTable, columns from tenancy.tables import ContactsColumnMixin from .template_code import MODULAR_COMPONENT_TEMPLATE_BUTTONS, DEVICE_WEIGHT @@ -59,7 +46,7 @@ class ManufacturerTable(ContactsColumnMixin, NetBoxTable): ) class Meta(NetBoxTable.Meta): - model = Manufacturer + model = models.Manufacturer fields = ( 'pk', 'id', 'name', 'devicetype_count', 'inventoryitem_count', 'platform_count', 'description', 'slug', 'contacts', 'actions', 'created', 'last_updated', @@ -100,15 +87,12 @@ class DeviceTypeTable(NetBoxTable): template_code=DEVICE_WEIGHT, order_by=('_abs_weight', 'weight_unit') ) - u_height = columns.TemplateColumn( - template_code='{{ value|floatformat }}' - ) class Meta(NetBoxTable.Meta): - model = DeviceType + model = models.DeviceType fields = ( 'pk', 'id', 'model', 'manufacturer', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', - 'airflow', 'weight', 'comments', 'instance_count', 'tags', 'created', 'last_updated', + 'airflow', 'weight', 'description', 'comments', 'instance_count', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'model', 'manufacturer', 'part_number', 'u_height', 'is_full_depth', 'instance_count', @@ -138,7 +122,7 @@ class ConsolePortTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = ConsolePortTemplate + model = models.ConsolePortTemplate fields = ('pk', 'name', 'label', 'type', 'description', 'actions') empty_text = "None" @@ -150,7 +134,7 @@ class ConsoleServerPortTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = ConsoleServerPortTemplate + model = models.ConsoleServerPortTemplate fields = ('pk', 'name', 'label', 'type', 'description', 'actions') empty_text = "None" @@ -162,7 +146,7 @@ class PowerPortTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = PowerPortTemplate + model = models.PowerPortTemplate fields = ('pk', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw', 'description', 'actions') empty_text = "None" @@ -174,7 +158,7 @@ class PowerOutletTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = PowerOutletTemplate + model = models.PowerOutletTemplate fields = ('pk', 'name', 'label', 'type', 'power_port', 'feed_leg', 'description', 'actions') empty_text = "None" @@ -189,7 +173,7 @@ class InterfaceTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = InterfaceTemplate + model = models.InterfaceTemplate fields = ('pk', 'name', 'label', 'mgmt_only', 'type', 'description', 'poe_mode', 'poe_type', 'actions') empty_text = "None" @@ -205,7 +189,7 @@ class FrontPortTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = FrontPortTemplate + model = models.FrontPortTemplate fields = ('pk', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description', 'actions') empty_text = "None" @@ -218,7 +202,7 @@ class RearPortTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = RearPortTemplate + model = models.RearPortTemplate fields = ('pk', 'name', 'label', 'type', 'color', 'positions', 'description', 'actions') empty_text = "None" @@ -229,7 +213,7 @@ class ModuleBayTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = ModuleBayTemplate + model = models.ModuleBayTemplate fields = ('pk', 'name', 'label', 'position', 'description', 'actions') empty_text = "None" @@ -240,7 +224,7 @@ class DeviceBayTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = DeviceBayTemplate + model = models.DeviceBayTemplate fields = ('pk', 'name', 'label', 'description', 'actions') empty_text = "None" @@ -260,7 +244,7 @@ class InventoryItemTemplateTable(ComponentTemplateTable): ) class Meta(ComponentTemplateTable.Meta): - model = InventoryItemTemplate + model = models.InventoryItemTemplate fields = ( 'pk', 'name', 'label', 'parent', 'role', 'manufacturer', 'part_id', 'component', 'description', 'actions', ) diff --git a/netbox/dcim/tables/modules.py b/netbox/dcim/tables/modules.py index b644e6ba6..9df26eb73 100644 --- a/netbox/dcim/tables/modules.py +++ b/netbox/dcim/tables/modules.py @@ -35,7 +35,7 @@ class ModuleTypeTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = ModuleType fields = ( - 'pk', 'id', 'model', 'manufacturer', 'part_number', 'weight', 'comments', 'tags', + 'pk', 'id', 'model', 'manufacturer', 'part_number', 'weight', 'description', 'comments', 'tags', ) default_columns = ( 'pk', 'model', 'manufacturer', 'part_number', @@ -64,8 +64,8 @@ class ModuleTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Module fields = ( - 'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', 'comments', - 'tags', + 'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', 'description', + 'comments', 'tags', ) default_columns = ( 'pk', 'id', 'device', 'module_bay', 'manufacturer', 'module_type', 'serial', 'asset_tag', diff --git a/netbox/dcim/tables/power.py b/netbox/dcim/tables/power.py index 04012ea4a..feff29e12 100644 --- a/netbox/dcim/tables/power.py +++ b/netbox/dcim/tables/power.py @@ -31,6 +31,7 @@ class PowerPanelTable(ContactsColumnMixin, NetBoxTable): url_params={'power_panel_id': 'pk'}, verbose_name='Feeds' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='dcim:powerpanel_list' ) @@ -38,7 +39,8 @@ class PowerPanelTable(ContactsColumnMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = PowerPanel fields = ( - 'pk', 'id', 'name', 'site', 'location', 'powerfeed_count', 'contacts', 'tags', 'created', 'last_updated', + 'pk', 'id', 'name', 'site', 'location', 'powerfeed_count', 'contacts', 'description', 'comments', 'tags', + 'created', 'last_updated', ) default_columns = ('pk', 'name', 'site', 'location', 'powerfeed_count') @@ -77,7 +79,7 @@ class PowerFeedTable(CableTerminationTable): fields = ( 'pk', 'id', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase', 'max_utilization', 'mark_connected', 'cable', 'cable_color', 'link_peer', 'connection', 'available_power', - 'comments', 'tags', 'created', 'last_updated', + 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'power_panel', 'rack', 'status', 'type', 'supply', 'voltage', 'amperage', 'phase', 'cable', diff --git a/netbox/dcim/tables/racks.py b/netbox/dcim/tables/racks.py index 1a355cc2a..b360002d2 100644 --- a/netbox/dcim/tables/racks.py +++ b/netbox/dcim/tables/racks.py @@ -90,8 +90,8 @@ class RackTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): fields = ( 'pk', 'id', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'tenant_group', 'role', 'serial', 'asset_tag', 'type', 'u_height', 'width', 'outer_width', 'outer_depth', 'mounting_depth', 'weight', - 'comments', 'device_count', 'get_utilization', 'get_power_utilization', 'contacts', 'tags', 'created', - 'last_updated', + 'comments', 'device_count', 'get_utilization', 'get_power_utilization', 'description', 'contacts', 'tags', + 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'site', 'location', 'status', 'facility_id', 'tenant', 'role', 'u_height', 'device_count', @@ -123,6 +123,7 @@ class RackReservationTable(TenancyColumnsMixin, NetBoxTable): orderable=False, verbose_name='Units' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='dcim:rackreservation_list' ) @@ -130,7 +131,7 @@ class RackReservationTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = RackReservation fields = ( - 'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'user', 'created', 'tenant', 'tenant_group', 'description', 'tags', - 'actions', 'created', 'last_updated', + 'pk', 'id', 'reservation', 'site', 'location', 'rack', 'unit_list', 'user', 'created', 'tenant', + 'tenant_group', 'description', 'comments', 'tags', 'actions', 'created', 'last_updated', ) default_columns = ('pk', 'reservation', 'site', 'rack', 'unit_list', 'user', 'description') diff --git a/netbox/ipam/api/serializers.py b/netbox/ipam/api/serializers.py index e04849c13..6ec062aee 100644 --- a/netbox/ipam/api/serializers.py +++ b/netbox/ipam/api/serializers.py @@ -31,8 +31,8 @@ class ASNSerializer(NetBoxModelSerializer): class Meta: model = ASN fields = [ - 'id', 'url', 'display', 'asn', 'rir', 'tenant', 'description', 'site_count', 'provider_count', 'tags', - 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'display', 'asn', 'rir', 'tenant', 'description', 'comments', 'tags', 'custom_fields', + 'created', 'last_updated', 'site_count', 'provider_count', ] @@ -61,8 +61,9 @@ class VRFSerializer(NetBoxModelSerializer): class Meta: model = VRF fields = [ - 'id', 'url', 'display', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'import_targets', - 'export_targets', 'tags', 'custom_fields', 'created', 'last_updated', 'ipaddress_count', 'prefix_count', + 'id', 'url', 'display', 'name', 'rd', 'tenant', 'enforce_unique', 'description', 'comments', + 'import_targets', 'export_targets', 'tags', 'custom_fields', 'created', 'last_updated', 'ipaddress_count', + 'prefix_count', ] @@ -77,7 +78,8 @@ class RouteTargetSerializer(NetBoxModelSerializer): class Meta: model = RouteTarget fields = [ - 'id', 'url', 'display', 'name', 'tenant', 'description', 'tags', 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'display', 'name', 'tenant', 'description', 'comments', 'tags', 'custom_fields', 'created', + 'last_updated', ] @@ -106,8 +108,8 @@ class AggregateSerializer(NetBoxModelSerializer): class Meta: model = Aggregate fields = [ - 'id', 'url', 'display', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description', 'tags', - 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'display', 'family', 'prefix', 'rir', 'tenant', 'date_added', 'description', 'comments', + 'tags', 'custom_fields', 'created', 'last_updated', ] read_only_fields = ['family'] @@ -123,8 +125,8 @@ class FHRPGroupSerializer(NetBoxModelSerializer): class Meta: model = FHRPGroup fields = [ - 'id', 'name', 'url', 'display', 'protocol', 'group_id', 'auth_type', 'auth_key', 'description', 'ip_addresses', - 'tags', 'custom_fields', 'created', 'last_updated', + 'id', 'name', 'url', 'display', 'protocol', 'group_id', 'auth_type', 'auth_key', 'description', 'comments', + 'tags', 'custom_fields', 'created', 'last_updated', 'ip_addresses', ] @@ -215,7 +217,7 @@ class VLANSerializer(NetBoxModelSerializer): model = VLAN fields = [ 'id', 'url', 'display', 'site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', - 'l2vpn_termination', 'tags', 'custom_fields', 'created', 'last_updated', 'prefix_count', + 'comments', 'l2vpn_termination', 'tags', 'custom_fields', 'created', 'last_updated', 'prefix_count', ] @@ -273,7 +275,8 @@ class PrefixSerializer(NetBoxModelSerializer): model = Prefix fields = [ 'id', 'url', 'display', 'family', 'prefix', 'site', 'vrf', 'tenant', 'vlan', 'status', 'role', 'is_pool', - 'mark_utilized', 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'children', '_depth', + 'mark_utilized', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'children', + '_depth', ] read_only_fields = ['family'] @@ -342,7 +345,7 @@ class IPRangeSerializer(NetBoxModelSerializer): model = IPRange fields = [ 'id', 'url', 'display', 'family', 'start_address', 'end_address', 'size', 'vrf', 'tenant', 'status', 'role', - 'description', 'tags', 'custom_fields', 'created', 'last_updated', 'children', + 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'children', ] read_only_fields = ['family'] @@ -371,8 +374,8 @@ class IPAddressSerializer(NetBoxModelSerializer): model = IPAddress fields = [ 'id', 'url', 'display', 'family', 'address', 'vrf', 'tenant', 'status', 'role', 'assigned_object_type', - 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside', 'dns_name', 'description', 'tags', - 'custom_fields', 'created', 'last_updated', + 'assigned_object_id', 'assigned_object', 'nat_inside', 'nat_outside', 'dns_name', 'description', 'comments', + 'tags', 'custom_fields', 'created', 'last_updated', ] @swagger_serializer_method(serializer_or_field=serializers.JSONField) @@ -415,8 +418,8 @@ class ServiceTemplateSerializer(NetBoxModelSerializer): class Meta: model = ServiceTemplate fields = [ - 'id', 'url', 'display', 'name', 'ports', 'protocol', 'description', 'tags', 'custom_fields', 'created', - 'last_updated', + 'id', 'url', 'display', 'name', 'ports', 'protocol', 'description', 'comments', 'tags', 'custom_fields', + 'created', 'last_updated', ] @@ -436,7 +439,7 @@ class ServiceSerializer(NetBoxModelSerializer): model = Service fields = [ 'id', 'url', 'display', 'device', 'virtual_machine', 'name', 'ports', 'protocol', 'ipaddresses', - 'description', 'tags', 'custom_fields', 'created', 'last_updated', + 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] # @@ -465,7 +468,7 @@ class L2VPNSerializer(NetBoxModelSerializer): model = L2VPN fields = [ 'id', 'url', 'display', 'identifier', 'name', 'slug', 'type', 'import_targets', 'export_targets', - 'description', 'tenant', 'tags', 'custom_fields', 'created', 'last_updated' + 'description', 'comments', 'tenant', 'tags', 'custom_fields', 'created', 'last_updated' ] diff --git a/netbox/ipam/forms/bulk_edit.py b/netbox/ipam/forms/bulk_edit.py index 67bcf83fb..ed1d1d9e9 100644 --- a/netbox/ipam/forms/bulk_edit.py +++ b/netbox/ipam/forms/bulk_edit.py @@ -8,8 +8,8 @@ from ipam.models import ASN from netbox.forms import NetBoxModelBulkEditForm from tenancy.models import Tenant from utilities.forms import ( - add_blank_choice, BulkEditNullBooleanSelect, DynamicModelChoiceField, NumericArrayField, StaticSelect, - DynamicModelMultipleChoiceField, + add_blank_choice, BulkEditNullBooleanSelect, CommentField, DynamicModelChoiceField, NumericArrayField, + SmallTextarea, StaticSelect, DynamicModelMultipleChoiceField, ) __all__ = ( @@ -43,15 +43,19 @@ class VRFBulkEditForm(NetBoxModelBulkEditForm): label='Enforce unique space' ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = VRF fieldsets = ( (None, ('tenant', 'enforce_unique', 'description')), ) - nullable_fields = ('tenant', 'description') + nullable_fields = ('tenant', 'description', 'comments') class RouteTargetBulkEditForm(NetBoxModelBulkEditForm): @@ -63,12 +67,16 @@ class RouteTargetBulkEditForm(NetBoxModelBulkEditForm): max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = RouteTarget fieldsets = ( (None, ('tenant', 'description')), ) - nullable_fields = ('tenant', 'description') + nullable_fields = ('tenant', 'description', 'comments') class RIRBulkEditForm(NetBoxModelBulkEditForm): @@ -103,15 +111,19 @@ class ASNBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = ASN fieldsets = ( (None, ('sites', 'rir', 'tenant', 'description')), ) - nullable_fields = ('date_added', 'description') + nullable_fields = ('date_added', 'description', 'comments') class AggregateBulkEditForm(NetBoxModelBulkEditForm): @@ -128,15 +140,19 @@ class AggregateBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Aggregate fieldsets = ( (None, ('rir', 'tenant', 'date_added', 'description')), ) - nullable_fields = ('date_added', 'description') + nullable_fields = ('date_added', 'description', 'comments') class RoleBulkEditForm(NetBoxModelBulkEditForm): @@ -206,9 +222,13 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm): label='Treat as 100% utilized' ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Prefix fieldsets = ( @@ -217,7 +237,7 @@ class PrefixBulkEditForm(NetBoxModelBulkEditForm): ('Addressing', ('vrf', 'prefix_length', 'is_pool', 'mark_utilized')), ) nullable_fields = ( - 'site', 'vrf', 'tenant', 'role', 'description', + 'site', 'vrf', 'tenant', 'role', 'description', 'comments', ) @@ -241,16 +261,20 @@ class IPRangeBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = IPRange fieldsets = ( (None, ('status', 'role', 'vrf', 'tenant', 'description')), ) nullable_fields = ( - 'vrf', 'tenant', 'role', 'description', + 'vrf', 'tenant', 'role', 'description', 'comments', ) @@ -285,9 +309,13 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): label='DNS name' ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = IPAddress fieldsets = ( @@ -295,7 +323,7 @@ class IPAddressBulkEditForm(NetBoxModelBulkEditForm): ('Addressing', ('vrf', 'mask_length', 'dns_name')), ) nullable_fields = ( - 'vrf', 'role', 'tenant', 'dns_name', 'description', + 'vrf', 'role', 'tenant', 'dns_name', 'description', 'comments', ) @@ -329,13 +357,17 @@ class FHRPGroupBulkEditForm(NetBoxModelBulkEditForm): max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = FHRPGroup fieldsets = ( (None, ('protocol', 'group_id', 'name', 'description')), ('Authentication', ('auth_type', 'auth_key')), ) - nullable_fields = ('auth_type', 'auth_key', 'name', 'description') + nullable_fields = ('auth_type', 'auth_key', 'name', 'description', 'comments') class VLANGroupBulkEditForm(NetBoxModelBulkEditForm): @@ -405,9 +437,13 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = VLAN fieldsets = ( @@ -415,7 +451,7 @@ class VLANBulkEditForm(NetBoxModelBulkEditForm): ('Site & Group', ('region', 'site_group', 'site', 'group')), ) nullable_fields = ( - 'site', 'group', 'tenant', 'role', 'description', + 'site', 'group', 'tenant', 'role', 'description', 'comments', ) @@ -433,15 +469,19 @@ class ServiceTemplateBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = ServiceTemplate fieldsets = ( (None, ('protocol', 'ports', 'description')), ) - nullable_fields = ('description',) + nullable_fields = ('description', 'comments') class ServiceBulkEditForm(ServiceTemplateBulkEditForm): @@ -459,15 +499,19 @@ class L2VPNBulkEditForm(NetBoxModelBulkEditForm): required=False ) description = forms.CharField( - max_length=100, + max_length=200, required=False ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = L2VPN fieldsets = ( - (None, ('type', 'description', 'tenant')), + (None, ('type', 'tenant', 'description')), ) - nullable_fields = ('tenant', 'description',) + nullable_fields = ('tenant', 'description', 'comments') class L2VPNTerminationBulkEditForm(NetBoxModelBulkEditForm): diff --git a/netbox/ipam/forms/bulk_import.py b/netbox/ipam/forms/bulk_import.py index 3aead6151..3a31b6757 100644 --- a/netbox/ipam/forms/bulk_import.py +++ b/netbox/ipam/forms/bulk_import.py @@ -41,7 +41,7 @@ class VRFCSVForm(NetBoxModelCSVForm): class Meta: model = VRF - fields = ('name', 'rd', 'tenant', 'enforce_unique', 'description') + fields = ('name', 'rd', 'tenant', 'enforce_unique', 'description', 'comments') class RouteTargetCSVForm(NetBoxModelCSVForm): @@ -54,7 +54,7 @@ class RouteTargetCSVForm(NetBoxModelCSVForm): class Meta: model = RouteTarget - fields = ('name', 'description', 'tenant') + fields = ('name', 'tenant', 'description', 'comments') class RIRCSVForm(NetBoxModelCSVForm): @@ -83,7 +83,7 @@ class AggregateCSVForm(NetBoxModelCSVForm): class Meta: model = Aggregate - fields = ('prefix', 'rir', 'tenant', 'date_added', 'description') + fields = ('prefix', 'rir', 'tenant', 'date_added', 'description', 'comments') class ASNCSVForm(NetBoxModelCSVForm): @@ -101,7 +101,7 @@ class ASNCSVForm(NetBoxModelCSVForm): class Meta: model = ASN - fields = ('asn', 'rir', 'tenant', 'description') + fields = ('asn', 'rir', 'tenant', 'description', 'comments') help_texts = {} @@ -159,7 +159,7 @@ class PrefixCSVForm(NetBoxModelCSVForm): model = Prefix fields = ( 'prefix', 'vrf', 'tenant', 'site', 'vlan_group', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', - 'description', + 'description', 'comments', ) def __init__(self, data=None, *args, **kwargs): @@ -204,7 +204,7 @@ class IPRangeCSVForm(NetBoxModelCSVForm): class Meta: model = IPRange fields = ( - 'start_address', 'end_address', 'vrf', 'tenant', 'status', 'role', 'description', + 'start_address', 'end_address', 'vrf', 'tenant', 'status', 'role', 'description', 'comments', ) @@ -257,7 +257,7 @@ class IPAddressCSVForm(NetBoxModelCSVForm): model = IPAddress fields = [ 'address', 'vrf', 'tenant', 'status', 'role', 'device', 'virtual_machine', 'interface', 'is_primary', - 'dns_name', 'description', + 'dns_name', 'description', 'comments', ] def __init__(self, data=None, *args, **kwargs): @@ -326,7 +326,7 @@ class FHRPGroupCSVForm(NetBoxModelCSVForm): class Meta: model = FHRPGroup - fields = ('protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'description') + fields = ('protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'description', 'comments') class VLANGroupCSVForm(NetBoxModelCSVForm): @@ -389,7 +389,7 @@ class VLANCSVForm(NetBoxModelCSVForm): class Meta: model = VLAN - fields = ('site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description') + fields = ('site', 'group', 'vid', 'name', 'tenant', 'status', 'role', 'description', 'comments') help_texts = { 'vid': 'Numeric VLAN ID (1-4094)', 'name': 'VLAN name', @@ -404,7 +404,7 @@ class ServiceTemplateCSVForm(NetBoxModelCSVForm): class Meta: model = ServiceTemplate - fields = ('name', 'protocol', 'ports', 'description') + fields = ('name', 'protocol', 'ports', 'description', 'comments') class ServiceCSVForm(NetBoxModelCSVForm): @@ -427,7 +427,7 @@ class ServiceCSVForm(NetBoxModelCSVForm): class Meta: model = Service - fields = ('device', 'virtual_machine', 'name', 'protocol', 'ports', 'description') + fields = ('device', 'virtual_machine', 'name', 'protocol', 'ports', 'description', 'comments') class L2VPNCSVForm(NetBoxModelCSVForm): @@ -443,7 +443,7 @@ class L2VPNCSVForm(NetBoxModelCSVForm): class Meta: model = L2VPN - fields = ('identifier', 'name', 'slug', 'type', 'description') + fields = ('identifier', 'name', 'slug', 'type', 'description', 'comments') class L2VPNTerminationCSVForm(NetBoxModelCSVForm): diff --git a/netbox/ipam/forms/model_forms.py b/netbox/ipam/forms/model_forms.py index 061462e71..9a5abc082 100644 --- a/netbox/ipam/forms/model_forms.py +++ b/netbox/ipam/forms/model_forms.py @@ -11,7 +11,7 @@ from netbox.forms import NetBoxModelForm from tenancy.forms import TenancyForm from utilities.exceptions import PermissionsViolation from utilities.forms import ( - add_blank_choice, BootstrapMixin, ContentTypeChoiceField, DatePicker, DynamicModelChoiceField, + add_blank_choice, BootstrapMixin, CommentField, ContentTypeChoiceField, DatePicker, DynamicModelChoiceField, DynamicModelMultipleChoiceField, NumericArrayField, SlugField, StaticSelect, StaticSelectMultiple, ) from virtualization.models import Cluster, ClusterGroup, VirtualMachine, VMInterface @@ -49,6 +49,7 @@ class VRFForm(TenancyForm, NetBoxModelForm): queryset=RouteTarget.objects.all(), required=False ) + comments = CommentField() fieldsets = ( ('VRF', ('name', 'rd', 'enforce_unique', 'description', 'tags')), @@ -59,8 +60,8 @@ class VRFForm(TenancyForm, NetBoxModelForm): class Meta: model = VRF fields = [ - 'name', 'rd', 'enforce_unique', 'description', 'import_targets', 'export_targets', 'tenant_group', 'tenant', - 'tags', + 'name', 'rd', 'enforce_unique', 'import_targets', 'export_targets', 'tenant_group', 'tenant', 'description', + 'comments', 'tags', ] labels = { 'rd': "RD", @@ -75,11 +76,12 @@ class RouteTargetForm(TenancyForm, NetBoxModelForm): ('Route Target', ('name', 'description', 'tags')), ('Tenancy', ('tenant_group', 'tenant')), ) + comments = CommentField() class Meta: model = RouteTarget fields = [ - 'name', 'description', 'tenant_group', 'tenant', 'tags', + 'name', 'tenant_group', 'tenant', 'description', 'comments', 'tags', ] @@ -104,6 +106,7 @@ class AggregateForm(TenancyForm, NetBoxModelForm): queryset=RIR.objects.all(), label='RIR' ) + comments = CommentField() fieldsets = ( ('Aggregate', ('prefix', 'rir', 'date_added', 'description', 'tags')), @@ -113,7 +116,7 @@ class AggregateForm(TenancyForm, NetBoxModelForm): class Meta: model = Aggregate fields = [ - 'prefix', 'rir', 'date_added', 'description', 'tenant_group', 'tenant', 'tags', + 'prefix', 'rir', 'date_added', 'tenant_group', 'tenant', 'description', 'comments', 'tags', ] help_texts = { 'prefix': "IPv4 or IPv6 network", @@ -134,6 +137,7 @@ class ASNForm(TenancyForm, NetBoxModelForm): label='Sites', required=False ) + comments = CommentField() fieldsets = ( ('ASN', ('asn', 'rir', 'sites', 'description', 'tags')), @@ -143,7 +147,7 @@ class ASNForm(TenancyForm, NetBoxModelForm): class Meta: model = ASN fields = [ - 'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'tags' + 'asn', 'rir', 'sites', 'tenant_group', 'tenant', 'description', 'comments', 'tags' ] help_texts = { 'asn': "AS number", @@ -235,6 +239,7 @@ class PrefixForm(TenancyForm, NetBoxModelForm): queryset=Role.objects.all(), required=False ) + comments = CommentField() fieldsets = ( ('Prefix', ('prefix', 'status', 'vrf', 'role', 'is_pool', 'mark_utilized', 'description', 'tags')), @@ -245,8 +250,8 @@ class PrefixForm(TenancyForm, NetBoxModelForm): class Meta: model = Prefix fields = [ - 'prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'description', - 'tenant_group', 'tenant', 'tags', + 'prefix', 'vrf', 'site', 'vlan', 'status', 'role', 'is_pool', 'mark_utilized', 'tenant_group', 'tenant', + 'description', 'comments', 'tags', ] widgets = { 'status': StaticSelect(), @@ -263,6 +268,7 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): queryset=Role.objects.all(), required=False ) + comments = CommentField() fieldsets = ( ('IP Range', ('vrf', 'start_address', 'end_address', 'role', 'status', 'description', 'tags')), @@ -272,7 +278,8 @@ class IPRangeForm(TenancyForm, NetBoxModelForm): class Meta: model = IPRange fields = [ - 'vrf', 'start_address', 'end_address', 'status', 'role', 'description', 'tenant_group', 'tenant', 'tags', + 'vrf', 'start_address', 'end_address', 'status', 'role', 'tenant_group', 'tenant', 'description', + 'comments', 'tags', ] widgets = { 'status': StaticSelect(), @@ -394,13 +401,14 @@ class IPAddressForm(TenancyForm, NetBoxModelForm): required=False, label='Make this the primary IP for the device/VM' ) + comments = CommentField() class Meta: model = IPAddress fields = [ - 'address', 'vrf', 'status', 'role', 'dns_name', 'description', 'primary_for_parent', 'nat_site', 'nat_rack', - 'nat_device', 'nat_cluster', 'nat_virtual_machine', 'nat_vrf', 'nat_inside', 'tenant_group', 'tenant', - 'tags', + 'address', 'vrf', 'status', 'role', 'dns_name', 'primary_for_parent', 'nat_site', 'nat_rack', 'nat_device', + 'nat_cluster', 'nat_virtual_machine', 'nat_vrf', 'nat_inside', 'tenant_group', 'tenant', 'description', + 'comments', 'tags', ] widgets = { 'status': StaticSelect(), @@ -535,6 +543,7 @@ class FHRPGroupForm(NetBoxModelForm): required=False, label='Status' ) + comments = CommentField() fieldsets = ( ('FHRP Group', ('protocol', 'group_id', 'name', 'description', 'tags')), @@ -545,7 +554,8 @@ class FHRPGroupForm(NetBoxModelForm): class Meta: model = FHRPGroup fields = ( - 'protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'description', 'ip_vrf', 'ip_address', 'ip_status', 'tags', + 'protocol', 'group_id', 'auth_type', 'auth_key', 'name', 'ip_vrf', 'ip_address', 'ip_status', 'description', + 'comments', 'tags', ) def save(self, *args, **kwargs): @@ -767,11 +777,13 @@ class VLANForm(TenancyForm, NetBoxModelForm): queryset=Role.objects.all(), required=False ) + comments = CommentField() class Meta: model = VLAN fields = [ - 'site', 'group', 'vid', 'name', 'status', 'role', 'description', 'tenant_group', 'tenant', 'tags', + 'site', 'group', 'vid', 'name', 'status', 'role', 'tenant_group', 'tenant', 'description', 'comments', + 'tags', ] help_texts = { 'site': "Leave blank if this VLAN spans multiple sites", @@ -794,6 +806,7 @@ class ServiceTemplateForm(NetBoxModelForm): ), help_text="Comma-separated list of one or more port numbers. A range may be specified using a hyphen." ) + comments = CommentField() fieldsets = ( ('Service Template', ( @@ -803,7 +816,7 @@ class ServiceTemplateForm(NetBoxModelForm): class Meta: model = ServiceTemplate - fields = ('name', 'protocol', 'ports', 'description', 'tags') + fields = ('name', 'protocol', 'ports', 'description', 'comments', 'tags') widgets = { 'protocol': StaticSelect(), } @@ -834,11 +847,12 @@ class ServiceForm(NetBoxModelForm): 'virtual_machine_id': '$virtual_machine', } ) + comments = CommentField() class Meta: model = Service fields = [ - 'device', 'virtual_machine', 'name', 'protocol', 'ports', 'ipaddresses', 'description', 'tags', + 'device', 'virtual_machine', 'name', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', ] help_texts = { 'ipaddresses': "IP address assignment is optional. If no IPs are selected, the service is assumed to be " @@ -899,6 +913,7 @@ class L2VPNForm(TenancyForm, NetBoxModelForm): queryset=RouteTarget.objects.all(), required=False ) + comments = CommentField() fieldsets = ( ('L2VPN', ('name', 'slug', 'type', 'identifier', 'description', 'tags')), @@ -909,7 +924,8 @@ class L2VPNForm(TenancyForm, NetBoxModelForm): class Meta: model = L2VPN fields = ( - 'name', 'slug', 'type', 'identifier', 'description', 'import_targets', 'export_targets', 'tenant', 'tags' + 'name', 'slug', 'type', 'identifier', 'import_targets', 'export_targets', 'tenant', 'description', + 'comments', 'tags' ) widgets = { 'type': StaticSelect(), diff --git a/netbox/ipam/migrations/0063_standardize_description_comments.py b/netbox/ipam/migrations/0063_standardize_description_comments.py new file mode 100644 index 000000000..3a4959d14 --- /dev/null +++ b/netbox/ipam/migrations/0063_standardize_description_comments.py @@ -0,0 +1,73 @@ +# Generated by Django 4.1.2 on 2022-11-03 18:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('ipam', '0062_unique_constraints'), + ] + + operations = [ + migrations.AddField( + model_name='aggregate', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='asn', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='fhrpgroup', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='ipaddress', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='iprange', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='l2vpn', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='prefix', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='routetarget', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='service', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='servicetemplate', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='vlan', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='vrf', + name='comments', + field=models.TextField(blank=True), + ), + ] diff --git a/netbox/ipam/models/fhrp.py b/netbox/ipam/models/fhrp.py index 633affa41..759a6e1d3 100644 --- a/netbox/ipam/models/fhrp.py +++ b/netbox/ipam/models/fhrp.py @@ -4,7 +4,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator from django.db import models from django.urls import reverse -from netbox.models import ChangeLoggedModel, NetBoxModel +from netbox.models import ChangeLoggedModel, PrimaryModel from netbox.models.features import WebhooksMixin from ipam.choices import * from ipam.constants import * @@ -15,7 +15,7 @@ __all__ = ( ) -class FHRPGroup(NetBoxModel): +class FHRPGroup(PrimaryModel): """ A grouping of next hope resolution protocol (FHRP) peers. (For instance, VRRP or HSRP.) """ @@ -41,10 +41,6 @@ class FHRPGroup(NetBoxModel): blank=True, verbose_name='Authentication key' ) - description = models.CharField( - max_length=200, - blank=True - ) ip_addresses = GenericRelation( to='ipam.IPAddress', content_type_field='assigned_object_type', diff --git a/netbox/ipam/models/ip.py b/netbox/ipam/models/ip.py index 75f90ff54..bf9bd6d7f 100644 --- a/netbox/ipam/models/ip.py +++ b/netbox/ipam/models/ip.py @@ -9,7 +9,7 @@ from django.utils.functional import cached_property from dcim.fields import ASNField from dcim.models import Device -from netbox.models import OrganizationalModel, NetBoxModel +from netbox.models import OrganizationalModel, PrimaryModel from ipam.choices import * from ipam.constants import * from ipam.fields import IPNetworkField, IPAddressField @@ -76,7 +76,7 @@ class RIR(OrganizationalModel): return reverse('ipam:rir', args=[self.pk]) -class ASN(NetBoxModel): +class ASN(PrimaryModel): """ An autonomous system (AS) number is typically used to represent an independent routing domain. A site can have one or more ASNs assigned to it. @@ -86,10 +86,6 @@ class ASN(NetBoxModel): verbose_name='ASN', help_text='32-bit autonomous system number' ) - description = models.CharField( - max_length=200, - blank=True - ) rir = models.ForeignKey( to='ipam.RIR', on_delete=models.PROTECT, @@ -139,7 +135,7 @@ class ASN(NetBoxModel): return self.asn -class Aggregate(GetAvailablePrefixesMixin, NetBoxModel): +class Aggregate(GetAvailablePrefixesMixin, PrimaryModel): """ An aggregate exists at the root level of the IP address space hierarchy in NetBox. Aggregates are used to organize the hierarchy and track the overall utilization of available address space. Each Aggregate is assigned to a RIR. @@ -162,10 +158,6 @@ class Aggregate(GetAvailablePrefixesMixin, NetBoxModel): blank=True, null=True ) - description = models.CharField( - max_length=200, - blank=True - ) clone_fields = ( 'rir', 'tenant', 'date_added', 'description', @@ -264,7 +256,7 @@ class Role(OrganizationalModel): return reverse('ipam:role', args=[self.pk]) -class Prefix(GetAvailablePrefixesMixin, NetBoxModel): +class Prefix(GetAvailablePrefixesMixin, PrimaryModel): """ A Prefix represents an IPv4 or IPv6 network, including mask length. Prefixes can optionally be assigned to Sites and VRFs. A Prefix must be assigned a status and may optionally be assigned a used-define Role. A Prefix can also be @@ -327,10 +319,6 @@ class Prefix(GetAvailablePrefixesMixin, NetBoxModel): default=False, help_text="Treat as 100% utilized" ) - description = models.CharField( - max_length=200, - blank=True - ) # Cached depth & child counts _depth = models.PositiveSmallIntegerField( @@ -545,7 +533,7 @@ class Prefix(GetAvailablePrefixesMixin, NetBoxModel): return min(utilization, 100) -class IPRange(NetBoxModel): +class IPRange(PrimaryModel): """ A range of IP addresses, defined by start and end addresses. """ @@ -587,10 +575,6 @@ class IPRange(NetBoxModel): null=True, help_text='The primary function of this range' ) - description = models.CharField( - max_length=200, - blank=True - ) clone_fields = ( 'vrf', 'tenant', 'status', 'role', 'description', @@ -740,7 +724,7 @@ class IPRange(NetBoxModel): return int(float(child_count) / self.size * 100) -class IPAddress(NetBoxModel): +class IPAddress(PrimaryModel): """ An IPAddress represents an individual IPv4 or IPv6 address and its mask. The mask length should match what is configured in the real world. (Typically, only loopback interfaces are configured with /32 or /128 masks.) Like @@ -813,10 +797,6 @@ class IPAddress(NetBoxModel): verbose_name='DNS Name', help_text='Hostname or FQDN (not case-sensitive)' ) - description = models.CharField( - max_length=200, - blank=True - ) objects = IPAddressManager() diff --git a/netbox/ipam/models/l2vpn.py b/netbox/ipam/models/l2vpn.py index a457f334b..f3f7a1d55 100644 --- a/netbox/ipam/models/l2vpn.py +++ b/netbox/ipam/models/l2vpn.py @@ -8,7 +8,7 @@ from django.utils.functional import cached_property from ipam.choices import L2VPNTypeChoices from ipam.constants import L2VPN_ASSIGNMENT_MODELS -from netbox.models import NetBoxModel +from netbox.models import NetBoxModel, PrimaryModel __all__ = ( 'L2VPN', @@ -16,7 +16,7 @@ __all__ = ( ) -class L2VPN(NetBoxModel): +class L2VPN(PrimaryModel): name = models.CharField( max_length=100, unique=True @@ -43,10 +43,6 @@ class L2VPN(NetBoxModel): related_name='exporting_l2vpns', blank=True ) - description = models.CharField( - max_length=200, - blank=True - ) tenant = models.ForeignKey( to='tenancy.Tenant', on_delete=models.PROTECT, diff --git a/netbox/ipam/models/services.py b/netbox/ipam/models/services.py index b566db375..690abf045 100644 --- a/netbox/ipam/models/services.py +++ b/netbox/ipam/models/services.py @@ -6,7 +6,7 @@ from django.urls import reverse from ipam.choices import * from ipam.constants import * -from netbox.models import NetBoxModel +from netbox.models import PrimaryModel from utilities.utils import array_to_string @@ -30,10 +30,6 @@ class ServiceBase(models.Model): ), verbose_name='Port numbers' ) - description = models.CharField( - max_length=200, - blank=True - ) class Meta: abstract = True @@ -46,7 +42,7 @@ class ServiceBase(models.Model): return array_to_string(self.ports) -class ServiceTemplate(ServiceBase, NetBoxModel): +class ServiceTemplate(ServiceBase, PrimaryModel): """ A template for a Service to be applied to a device or virtual machine. """ @@ -62,7 +58,7 @@ class ServiceTemplate(ServiceBase, NetBoxModel): return reverse('ipam:servicetemplate', args=[self.pk]) -class Service(ServiceBase, NetBoxModel): +class Service(ServiceBase, PrimaryModel): """ A Service represents a layer-four service (e.g. HTTP or SSH) running on a Device or VirtualMachine. A Service may optionally be tied to one or more specific IPAddresses belonging to its parent. diff --git a/netbox/ipam/models/vlans.py b/netbox/ipam/models/vlans.py index e3a4b973b..4f5d513cf 100644 --- a/netbox/ipam/models/vlans.py +++ b/netbox/ipam/models/vlans.py @@ -8,12 +8,10 @@ from django.urls import reverse from dcim.models import Interface from ipam.choices import * from ipam.constants import * -from ipam.models import L2VPNTermination from ipam.querysets import VLANQuerySet -from netbox.models import OrganizationalModel, NetBoxModel +from netbox.models import OrganizationalModel, PrimaryModel from virtualization.models import VMInterface - __all__ = ( 'VLAN', 'VLANGroup', @@ -63,10 +61,6 @@ class VLANGroup(OrganizationalModel): ), help_text='Highest permissible ID of a child VLAN' ) - description = models.CharField( - max_length=200, - blank=True - ) class Meta: ordering = ('name', 'pk') # Name may be non-unique @@ -120,7 +114,7 @@ class VLANGroup(OrganizationalModel): return None -class VLAN(NetBoxModel): +class VLAN(PrimaryModel): """ A VLAN is a distinct layer two forwarding domain identified by a 12-bit integer (1-4094). Each VLAN must be assigned to a Site, however VLAN IDs need not be unique within a Site. A VLAN may optionally be assigned to a VLANGroup, @@ -172,10 +166,6 @@ class VLAN(NetBoxModel): blank=True, null=True ) - description = models.CharField( - max_length=200, - blank=True - ) l2vpn_terminations = GenericRelation( to='ipam.L2VPNTermination', diff --git a/netbox/ipam/models/vrfs.py b/netbox/ipam/models/vrfs.py index a926bec3e..0f3c9793c 100644 --- a/netbox/ipam/models/vrfs.py +++ b/netbox/ipam/models/vrfs.py @@ -2,7 +2,7 @@ from django.db import models from django.urls import reverse from ipam.constants import * -from netbox.models import NetBoxModel +from netbox.models import PrimaryModel __all__ = ( @@ -11,7 +11,7 @@ __all__ = ( ) -class VRF(NetBoxModel): +class VRF(PrimaryModel): """ A virtual routing and forwarding (VRF) table represents a discrete layer three forwarding domain (e.g. a routing table). Prefixes and IPAddresses can optionally be assigned to VRFs. (Prefixes and IPAddresses not assigned to a VRF @@ -40,10 +40,6 @@ class VRF(NetBoxModel): verbose_name='Enforce unique space', help_text='Prevent duplicate prefixes/IP addresses within this VRF' ) - description = models.CharField( - max_length=200, - blank=True - ) import_targets = models.ManyToManyField( to='ipam.RouteTarget', related_name='importing_vrfs', @@ -73,7 +69,7 @@ class VRF(NetBoxModel): return reverse('ipam:vrf', args=[self.pk]) -class RouteTarget(NetBoxModel): +class RouteTarget(PrimaryModel): """ A BGP extended community used to control the redistribution of routes among VRFs, as defined in RFC 4364. """ @@ -82,10 +78,6 @@ class RouteTarget(NetBoxModel): unique=True, help_text='Route target value (formatted in accordance with RFC 4360)' ) - description = models.CharField( - max_length=200, - blank=True - ) tenant = models.ForeignKey( to='tenancy.Tenant', on_delete=models.PROTECT, diff --git a/netbox/ipam/tables/fhrp.py b/netbox/ipam/tables/fhrp.py index beffdd232..89aa16e65 100644 --- a/netbox/ipam/tables/fhrp.py +++ b/netbox/ipam/tables/fhrp.py @@ -20,7 +20,6 @@ class FHRPGroupTable(NetBoxTable): group_id = tables.Column( linkify=True ) - comments = columns.MarkdownColumn() ip_addresses = tables.TemplateColumn( template_code=IPADDRESSES, orderable=False, @@ -29,6 +28,7 @@ class FHRPGroupTable(NetBoxTable): member_count = tables.Column( verbose_name='Members' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:fhrpgroup_list' ) @@ -36,7 +36,7 @@ class FHRPGroupTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = FHRPGroup fields = ( - 'pk', 'group_id', 'protocol', 'name', 'auth_type', 'auth_key', 'description', 'ip_addresses', + 'pk', 'group_id', 'protocol', 'name', 'auth_type', 'auth_key', 'description', 'comments', 'ip_addresses', 'member_count', 'tags', 'created', 'last_updated', ) default_columns = ( diff --git a/netbox/ipam/tables/ip.py b/netbox/ipam/tables/ip.py index 44f40b8a1..f83831d2d 100644 --- a/netbox/ipam/tables/ip.py +++ b/netbox/ipam/tables/ip.py @@ -120,6 +120,7 @@ class ASNTable(TenancyColumnsMixin, NetBoxTable): linkify_item=True, verbose_name='Sites' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:asn_list' ) @@ -127,8 +128,8 @@ class ASNTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = ASN fields = ( - 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description', 'sites', 'tags', - 'created', 'last_updated', 'actions', + 'pk', 'asn', 'asn_asdot', 'rir', 'site_count', 'provider_count', 'tenant', 'tenant_group', 'description', + 'comments', 'sites', 'tags', 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'asn', 'rir', 'site_count', 'provider_count', 'sites', 'description', 'tenant') @@ -153,6 +154,7 @@ class AggregateTable(TenancyColumnsMixin, NetBoxTable): accessor='get_utilization', orderable=False ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:aggregate_list' ) @@ -160,8 +162,8 @@ class AggregateTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = Aggregate fields = ( - 'pk', 'id', 'prefix', 'rir', 'tenant', 'tenant_group', 'child_count', 'utilization', 'date_added', 'description', 'tags', - 'created', 'last_updated', + 'pk', 'id', 'prefix', 'rir', 'tenant', 'tenant_group', 'child_count', 'utilization', 'date_added', + 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'prefix', 'rir', 'tenant', 'child_count', 'utilization', 'date_added', 'description') @@ -278,6 +280,7 @@ class PrefixTable(TenancyColumnsMixin, NetBoxTable): accessor='get_utilization', orderable=False ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:prefix_list' ) @@ -285,8 +288,9 @@ class PrefixTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = Prefix fields = ( - 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'tenant_group', 'site', - 'vlan_group', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', 'tags', 'created', 'last_updated', + 'pk', 'id', 'prefix', 'prefix_flat', 'status', 'children', 'vrf', 'utilization', 'tenant', 'tenant_group', + 'site', 'vlan_group', 'vlan', 'role', 'is_pool', 'mark_utilized', 'description', 'comments', 'tags', + 'created', 'last_updated', ) default_columns = ( 'pk', 'prefix', 'status', 'children', 'vrf', 'utilization', 'tenant', 'site', 'vlan', 'role', 'description', @@ -317,6 +321,7 @@ class IPRangeTable(TenancyColumnsMixin, NetBoxTable): accessor='utilization', orderable=False ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:iprange_list' ) @@ -324,8 +329,8 @@ class IPRangeTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = IPRange fields = ( - 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'description', - 'utilization', 'tags', 'created', 'last_updated', + 'pk', 'id', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'tenant_group', + 'utilization', 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'start_address', 'end_address', 'size', 'vrf', 'status', 'role', 'tenant', 'description', @@ -378,6 +383,7 @@ class IPAddressTable(TenancyColumnsMixin, NetBoxTable): linkify=lambda record: record.assigned_object.get_absolute_url(), verbose_name='Assigned' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:ipaddress_list' ) @@ -385,8 +391,8 @@ class IPAddressTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = IPAddress fields = ( - 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'nat_inside', 'nat_outside', 'assigned', 'dns_name', 'description', - 'tags', 'created', 'last_updated', + 'pk', 'id', 'address', 'vrf', 'status', 'role', 'tenant', 'tenant_group', 'nat_inside', 'nat_outside', + 'assigned', 'dns_name', 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'address', 'vrf', 'status', 'role', 'tenant', 'assigned', 'dns_name', 'description', diff --git a/netbox/ipam/tables/l2vpn.py b/netbox/ipam/tables/l2vpn.py index 4a6af7c9b..2ece2c434 100644 --- a/netbox/ipam/tables/l2vpn.py +++ b/netbox/ipam/tables/l2vpn.py @@ -29,12 +29,16 @@ class L2VPNTable(TenancyColumnsMixin, NetBoxTable): template_code=L2VPN_TARGETS, orderable=False ) + comments = columns.MarkdownColumn() + tags = columns.TagColumn( + url_name='ipam:prefix_list' + ) class Meta(NetBoxTable.Meta): model = L2VPN fields = ( - 'pk', 'name', 'slug', 'identifier', 'type', 'description', 'import_targets', 'export_targets', 'tenant', 'tenant_group', - 'actions', + 'pk', 'name', 'slug', 'identifier', 'type', 'import_targets', 'export_targets', 'tenant', 'tenant_group', + 'description', 'comments', 'tags', 'created', 'last_updated', 'actions', ) default_columns = ('pk', 'name', 'identifier', 'type', 'description', 'actions') diff --git a/netbox/ipam/tables/services.py b/netbox/ipam/tables/services.py index 58d0a9aff..826ac98d5 100644 --- a/netbox/ipam/tables/services.py +++ b/netbox/ipam/tables/services.py @@ -17,13 +17,16 @@ class ServiceTemplateTable(NetBoxTable): accessor=tables.A('port_list'), order_by=tables.A('ports'), ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:servicetemplate_list' ) class Meta(NetBoxTable.Meta): model = ServiceTemplate - fields = ('pk', 'id', 'name', 'protocol', 'ports', 'description', 'tags') + fields = ( + 'pk', 'id', 'name', 'protocol', 'ports', 'description', 'comments', 'tags', 'created', 'last_updated', + ) default_columns = ('pk', 'name', 'protocol', 'ports', 'description') @@ -39,6 +42,7 @@ class ServiceTable(NetBoxTable): accessor=tables.A('port_list'), order_by=tables.A('ports'), ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:service_list' ) @@ -46,7 +50,7 @@ class ServiceTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Service fields = ( - 'pk', 'id', 'name', 'parent', 'protocol', 'ports', 'ipaddresses', 'description', 'tags', 'created', - 'last_updated', + 'pk', 'id', 'name', 'parent', 'protocol', 'ports', 'ipaddresses', 'description', 'comments', 'tags', + 'created', 'last_updated', ) default_columns = ('pk', 'name', 'parent', 'protocol', 'ports', 'description') diff --git a/netbox/ipam/tables/vlans.py b/netbox/ipam/tables/vlans.py index f183f8a7b..6fa2cd2da 100644 --- a/netbox/ipam/tables/vlans.py +++ b/netbox/ipam/tables/vlans.py @@ -121,6 +121,7 @@ class VLANTable(TenancyColumnsMixin, NetBoxTable): orderable=False, verbose_name='Prefixes' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:vlan_list' ) @@ -129,7 +130,7 @@ class VLANTable(TenancyColumnsMixin, NetBoxTable): model = VLAN fields = ( 'pk', 'id', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'tenant_group', 'status', 'role', - 'description', 'tags', 'l2vpn', 'created', 'last_updated', + 'description', 'comments', 'tags', 'l2vpn', 'created', 'last_updated', ) default_columns = ('pk', 'vid', 'name', 'site', 'group', 'prefixes', 'tenant', 'status', 'role', 'description') row_attrs = { diff --git a/netbox/ipam/tables/vrfs.py b/netbox/ipam/tables/vrfs.py index 69807410b..635af48d0 100644 --- a/netbox/ipam/tables/vrfs.py +++ b/netbox/ipam/tables/vrfs.py @@ -38,6 +38,7 @@ class VRFTable(TenancyColumnsMixin, NetBoxTable): template_code=VRF_TARGETS, orderable=False ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:vrf_list' ) @@ -45,8 +46,8 @@ class VRFTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = VRF fields = ( - 'pk', 'id', 'name', 'rd', 'tenant', 'tenant_group', 'enforce_unique', 'description', 'import_targets', 'export_targets', - 'tags', 'created', 'last_updated', + 'pk', 'id', 'name', 'rd', 'tenant', 'tenant_group', 'enforce_unique', 'import_targets', 'export_targets', + 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'rd', 'tenant', 'description') @@ -59,11 +60,14 @@ class RouteTargetTable(TenancyColumnsMixin, NetBoxTable): name = tables.Column( linkify=True ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='ipam:vrf_list' ) class Meta(NetBoxTable.Meta): model = RouteTarget - fields = ('pk', 'id', 'name', 'tenant', 'tenant_group', 'description', 'tags', 'created', 'last_updated',) + fields = ( + 'pk', 'id', 'name', 'tenant', 'tenant_group', 'description', 'comments', 'tags', 'created', 'last_updated', + ) default_columns = ('pk', 'name', 'tenant', 'description') diff --git a/netbox/netbox/models/__init__.py b/netbox/netbox/models/__init__.py index 38a6fcc9f..661470ee0 100644 --- a/netbox/netbox/models/__init__.py +++ b/netbox/netbox/models/__init__.py @@ -10,8 +10,9 @@ from netbox.models.features import * __all__ = ( 'ChangeLoggedModel', 'NestedGroupModel', - 'OrganizationalModel', 'NetBoxModel', + 'OrganizationalModel', + 'PrimaryModel', ) @@ -58,7 +59,7 @@ class ChangeLoggedModel(ChangeLoggingMixin, CustomValidationMixin, models.Model) class NetBoxModel(CloningMixin, NetBoxFeatureSet, models.Model): """ - Primary models represent real objects within the infrastructure being modeled. + Base model for most object types. Suitable for use by plugins. """ objects = RestrictedQuerySet.as_manager() @@ -66,6 +67,22 @@ class NetBoxModel(CloningMixin, NetBoxFeatureSet, models.Model): abstract = True +class PrimaryModel(NetBoxModel): + """ + Primary models represent real objects within the infrastructure being modeled. + """ + description = models.CharField( + max_length=200, + blank=True + ) + comments = models.TextField( + blank=True + ) + + class Meta: + abstract = True + + class NestedGroupModel(NetBoxFeatureSet, MPTTModel): """ Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest diff --git a/netbox/templates/circuits/provider.html b/netbox/templates/circuits/provider.html index 0fc18a368..51f911350 100644 --- a/netbox/templates/circuits/provider.html +++ b/netbox/templates/circuits/provider.html @@ -33,6 +33,10 @@ Account {{ object.account|placeholder }} + + Description + {{ object.description|placeholder }} + Circuits diff --git a/netbox/templates/dcim/cable.html b/netbox/templates/dcim/cable.html index e032d7034..bd0f27106 100644 --- a/netbox/templates/dcim/cable.html +++ b/netbox/templates/dcim/cable.html @@ -32,6 +32,10 @@ Label {{ object.label|placeholder }} + + Description + {{ object.description|placeholder }} + Color @@ -57,6 +61,7 @@ {% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/dcim/cable_edit.html b/netbox/templates/dcim/cable_edit.html index 29bb60d70..1c747b44b 100644 --- a/netbox/templates/dcim/cable_edit.html +++ b/netbox/templates/dcim/cable_edit.html @@ -80,6 +80,7 @@ {% render_field form.tenant_group %} {% render_field form.tenant %} {% render_field form.label %} + {% render_field form.description %} {% render_field form.color %}
@@ -92,16 +93,22 @@
{% render_field form.tags %} - {% if form.custom_fields %} -
-
-
Custom Fields
-
- {% render_custom_fields form %} -
- {% endif %}
+
+
Comments
+
+ {% render_field form.comments %} +
+
+ {% if form.custom_fields %} +
+
Custom Fields
+
+ {% render_custom_fields form %} +
+
+ {% endif %}
diff --git a/netbox/templates/dcim/device.html b/netbox/templates/dcim/device.html index b0cd76de4..046600d08 100644 --- a/netbox/templates/dcim/device.html +++ b/netbox/templates/dcim/device.html @@ -94,7 +94,11 @@ - Airflow + Description + {{ object.description|placeholder }} + + + Airflow {{ object.get_airflow_display|placeholder }} diff --git a/netbox/templates/dcim/device_edit.html b/netbox/templates/dcim/device_edit.html index 38125e83c..b814e65ef 100644 --- a/netbox/templates/dcim/device_edit.html +++ b/netbox/templates/dcim/device_edit.html @@ -10,6 +10,7 @@
{% render_field form.name %} {% render_field form.device_role %} + {% render_field form.description %} {% render_field form.tags %} diff --git a/netbox/templates/dcim/devicetype.html b/netbox/templates/dcim/devicetype.html index 458c74ac1..930390a56 100644 --- a/netbox/templates/dcim/devicetype.html +++ b/netbox/templates/dcim/devicetype.html @@ -27,6 +27,10 @@ Part Number {{ object.part_number|placeholder }} + + Description + {{ object.description|placeholder }} + Height (U) {{ object.u_height|floatformat }} diff --git a/netbox/templates/dcim/module.html b/netbox/templates/dcim/module.html index f2dac38f2..139ac2eb8 100644 --- a/netbox/templates/dcim/module.html +++ b/netbox/templates/dcim/module.html @@ -62,6 +62,10 @@ Module Type {{ object.module_type|linkify }} + + Description + {{ object.description|placeholder }} + Serial Number {{ object.serial|placeholder }} diff --git a/netbox/templates/dcim/moduletype.html b/netbox/templates/dcim/moduletype.html index 8128e64be..fd0148c2f 100644 --- a/netbox/templates/dcim/moduletype.html +++ b/netbox/templates/dcim/moduletype.html @@ -22,6 +22,10 @@ Part Number {{ object.part_number|placeholder }} + + Description + {{ object.description|placeholder }} + Weight diff --git a/netbox/templates/dcim/powerfeed.html b/netbox/templates/dcim/powerfeed.html index 54ac96bab..6387c111d 100644 --- a/netbox/templates/dcim/powerfeed.html +++ b/netbox/templates/dcim/powerfeed.html @@ -38,6 +38,10 @@ Status {% badge object.get_status_display bg_color=object.get_status_color %} + + Description + {{ object.description|placeholder }} + Connected Device diff --git a/netbox/templates/dcim/powerpanel.html b/netbox/templates/dcim/powerpanel.html index b7fe8eb39..16bd82cc0 100644 --- a/netbox/templates/dcim/powerpanel.html +++ b/netbox/templates/dcim/powerpanel.html @@ -14,26 +14,29 @@ {% block content %}
-
-
- Power Panel -
-
- - - - - - - - - -
Site{{ object.site|linkify }}
Location{{ object.location|linkify|placeholder }}
-
-
- {% include 'inc/panels/tags.html' %} - {% plugin_left_page object %} +
+
Power Panel
+
+ + + + + + + + + + + + + +
Site{{ object.site|linkify }}
Location{{ object.location|linkify|placeholder }}
Description{{ object.description|placeholder }}
+
+ {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} + {% plugin_left_page object %} +
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/contacts.html' %} diff --git a/netbox/templates/dcim/rack.html b/netbox/templates/dcim/rack.html index 7118f09ef..185634e8a 100644 --- a/netbox/templates/dcim/rack.html +++ b/netbox/templates/dcim/rack.html @@ -78,6 +78,10 @@ Role {{ object.role|linkify|placeholder }} + + Description + {{ object.description|placeholder }} + Serial Number {{ object.serial|placeholder }} diff --git a/netbox/templates/dcim/rack_edit.html b/netbox/templates/dcim/rack_edit.html index a0af20c68..d214bbee8 100644 --- a/netbox/templates/dcim/rack_edit.html +++ b/netbox/templates/dcim/rack_edit.html @@ -13,6 +13,7 @@ {% render_field form.name %} {% render_field form.status %} {% render_field form.role %} + {% render_field form.description %} {% render_field form.tags %}
diff --git a/netbox/templates/dcim/rackreservation.html b/netbox/templates/dcim/rackreservation.html index ebdd1d845..52472e297 100644 --- a/netbox/templates/dcim/rackreservation.html +++ b/netbox/templates/dcim/rackreservation.html @@ -73,6 +73,7 @@
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/dcim/virtualchassis.html b/netbox/templates/dcim/virtualchassis.html index 1ff9f2e9a..d0fba3ca2 100644 --- a/netbox/templates/dcim/virtualchassis.html +++ b/netbox/templates/dcim/virtualchassis.html @@ -27,11 +27,15 @@ Master {{ object.master|linkify }} + + Description + {{ object.description|placeholder }} +
- {% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/custom_fields.html' %} {% plugin_left_page object %}
@@ -73,6 +77,7 @@
{% endif %} + {% include 'inc/panels/comments.html' %} {% plugin_right_page object %} diff --git a/netbox/templates/dcim/virtualchassis_edit.html b/netbox/templates/dcim/virtualchassis_edit.html index 87917f2a2..f98a9fe64 100644 --- a/netbox/templates/dcim/virtualchassis_edit.html +++ b/netbox/templates/dcim/virtualchassis_edit.html @@ -17,12 +17,18 @@ {% render_field vc_form.name %} {% render_field vc_form.domain %} + {% render_field vc_form.description %} {% render_field vc_form.master %} {% render_field vc_form.tags %} +
+
Comments
+ {% render_field vc_form.comments %} +
+ {% if vc_form.custom_fields %} -
+
Custom Fields
diff --git a/netbox/templates/ipam/aggregate.html b/netbox/templates/ipam/aggregate.html index f3eff9df1..b95341b16 100644 --- a/netbox/templates/ipam/aggregate.html +++ b/netbox/templates/ipam/aggregate.html @@ -51,6 +51,7 @@
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/ipam/asn.html b/netbox/templates/ipam/asn.html index 7afe981e6..3af5177cc 100644 --- a/netbox/templates/ipam/asn.html +++ b/netbox/templates/ipam/asn.html @@ -67,6 +67,7 @@
{% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' with tags=object.tags.all url='ipam:asn_list' %} + {% include 'inc/panels/comments.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/ipam/fhrpgroup.html b/netbox/templates/ipam/fhrpgroup.html index 89fc7083c..a74ddac70 100644 --- a/netbox/templates/ipam/fhrpgroup.html +++ b/netbox/templates/ipam/fhrpgroup.html @@ -42,6 +42,7 @@ {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/ipam/fhrpgroup_edit.html b/netbox/templates/ipam/fhrpgroup_edit.html index 02816b440..bf86e6c41 100644 --- a/netbox/templates/ipam/fhrpgroup_edit.html +++ b/netbox/templates/ipam/fhrpgroup_edit.html @@ -13,7 +13,7 @@ {% render_field form.tags %}
-
+
Authentication
@@ -22,7 +22,7 @@
{% if not form.instance.pk %} -
+
Virtual IP Address
@@ -32,6 +32,13 @@
{% endif %} +
+
+
Comments
+
+ {% render_field form.comments %} +
+ {% if form.custom_fields %}
Custom Fields
diff --git a/netbox/templates/ipam/ipaddress.html b/netbox/templates/ipam/ipaddress.html index 7f77e8137..4a110c2e6 100644 --- a/netbox/templates/ipam/ipaddress.html +++ b/netbox/templates/ipam/ipaddress.html @@ -108,6 +108,7 @@
{% include 'inc/panels/tags.html' %} {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/ipam/ipaddress_edit.html b/netbox/templates/ipam/ipaddress_edit.html index f4b21397a..b9a988009 100644 --- a/netbox/templates/ipam/ipaddress_edit.html +++ b/netbox/templates/ipam/ipaddress_edit.html @@ -138,6 +138,13 @@
+
+
+
Comments
+
+ {% render_field form.comments %} +
+ {% if form.custom_fields %}
diff --git a/netbox/templates/ipam/iprange.html b/netbox/templates/ipam/iprange.html index c78b5a132..6ba9e4bea 100644 --- a/netbox/templates/ipam/iprange.html +++ b/netbox/templates/ipam/iprange.html @@ -70,9 +70,10 @@ {% plugin_left_page object %}
- {% include 'inc/panels/tags.html' %} - {% include 'inc/panels/custom_fields.html' %} - {% plugin_right_page object %} + {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/comments.html' %} + {% plugin_right_page object %}
diff --git a/netbox/templates/ipam/l2vpn.html b/netbox/templates/ipam/l2vpn.html index c19363d33..4ffda2c98 100644 --- a/netbox/templates/ipam/l2vpn.html +++ b/netbox/templates/ipam/l2vpn.html @@ -39,6 +39,7 @@
{% include 'inc/panels/contacts.html' %} {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/ipam/prefix.html b/netbox/templates/ipam/prefix.html index b15aa60bb..a0baf3325 100644 --- a/netbox/templates/ipam/prefix.html +++ b/netbox/templates/ipam/prefix.html @@ -155,6 +155,7 @@ {% include 'inc/panels/custom_fields.html' %} {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_right_page object %} diff --git a/netbox/templates/ipam/routetarget.html b/netbox/templates/ipam/routetarget.html index e093aee61..ea7a98c97 100644 --- a/netbox/templates/ipam/routetarget.html +++ b/netbox/templates/ipam/routetarget.html @@ -26,6 +26,7 @@ {% include 'inc/panels/tags.html' %} {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/ipam/service.html b/netbox/templates/ipam/service.html index 47ae70dc9..fdc4be342 100644 --- a/netbox/templates/ipam/service.html +++ b/netbox/templates/ipam/service.html @@ -58,9 +58,10 @@ {% plugin_left_page object %}
- {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/tags.html' %} - {% plugin_right_page object %} + {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} + {% plugin_right_page object %}
diff --git a/netbox/templates/ipam/service_create.html b/netbox/templates/ipam/service_create.html index 022821bcf..5c47dd2f8 100644 --- a/netbox/templates/ipam/service_create.html +++ b/netbox/templates/ipam/service_create.html @@ -65,6 +65,13 @@ {% render_field form.tags %}
+
+
+
Comments
+
+ {% render_field form.comments %} +
+ {% if form.custom_fields %}
Custom Fields
diff --git a/netbox/templates/ipam/service_edit.html b/netbox/templates/ipam/service_edit.html index f3e34a7d1..709d816c1 100644 --- a/netbox/templates/ipam/service_edit.html +++ b/netbox/templates/ipam/service_edit.html @@ -52,6 +52,13 @@ {% render_field form.tags %}
+
+
+
Comments
+
+ {% render_field form.comments %} +
+ {% if form.custom_fields %}
Custom Fields
diff --git a/netbox/templates/ipam/servicetemplate.html b/netbox/templates/ipam/servicetemplate.html index 6e2aacb34..afb4163b9 100644 --- a/netbox/templates/ipam/servicetemplate.html +++ b/netbox/templates/ipam/servicetemplate.html @@ -31,12 +31,13 @@
{% plugin_left_page object %} - -
- {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/tags.html' %} - {% plugin_right_page object %} -
+ +
+ {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} + {% plugin_right_page object %} +
diff --git a/netbox/templates/ipam/vlan.html b/netbox/templates/ipam/vlan.html index 53bb75b8f..c0f68bae2 100644 --- a/netbox/templates/ipam/vlan.html +++ b/netbox/templates/ipam/vlan.html @@ -74,9 +74,10 @@ {% plugin_left_page object %}
- {% include 'inc/panels/custom_fields.html' %} - {% include 'inc/panels/tags.html' %} - {% plugin_right_page object %} + {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} + {% plugin_right_page object %}
diff --git a/netbox/templates/ipam/vlan_edit.html b/netbox/templates/ipam/vlan_edit.html index 5aa577942..f4432efe3 100644 --- a/netbox/templates/ipam/vlan_edit.html +++ b/netbox/templates/ipam/vlan_edit.html @@ -55,6 +55,13 @@ {% endwith %}
+
+
+
Comments
+
+ {% render_field form.comments %} +
+ {% if form.custom_fields %}
diff --git a/netbox/templates/ipam/vrf.html b/netbox/templates/ipam/vrf.html index 831338600..b53862f9e 100644 --- a/netbox/templates/ipam/vrf.html +++ b/netbox/templates/ipam/vrf.html @@ -55,6 +55,7 @@
{% include 'inc/panels/tags.html' %} {% include 'inc/panels/custom_fields.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_right_page object %}
diff --git a/netbox/templates/tenancy/contact.html b/netbox/templates/tenancy/contact.html index 8e71628e9..d92226137 100644 --- a/netbox/templates/tenancy/contact.html +++ b/netbox/templates/tenancy/contact.html @@ -63,6 +63,10 @@ {% endif %} + + Description + {{ object.description|placeholder }} + Assignments {{ assignment_count }} diff --git a/netbox/templates/virtualization/cluster.html b/netbox/templates/virtualization/cluster.html index bc02424cc..510c5a48e 100644 --- a/netbox/templates/virtualization/cluster.html +++ b/netbox/templates/virtualization/cluster.html @@ -23,6 +23,10 @@ Status {% badge object.get_status_display bg_color=object.get_status_color %} + + Description + {{ object.description|placeholder }} + Group {{ object.group|linkify|placeholder }} diff --git a/netbox/templates/virtualization/virtualmachine.html b/netbox/templates/virtualization/virtualmachine.html index c0e2ebd07..9d95b02ea 100644 --- a/netbox/templates/virtualization/virtualmachine.html +++ b/netbox/templates/virtualization/virtualmachine.html @@ -29,6 +29,10 @@ Platform {{ object.platform|linkify|placeholder }} + + Description + {{ object.description|placeholder }} + Tenant diff --git a/netbox/templates/wireless/wirelesslan.html b/netbox/templates/wireless/wirelesslan.html index 9250ef7ef..19e8b930d 100644 --- a/netbox/templates/wireless/wirelesslan.html +++ b/netbox/templates/wireless/wirelesslan.html @@ -39,6 +39,7 @@
{% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/wireless/wirelesslink.html b/netbox/templates/wireless/wirelesslink.html index d1a93e40d..be98979c1 100644 --- a/netbox/templates/wireless/wirelesslink.html +++ b/netbox/templates/wireless/wirelesslink.html @@ -40,6 +40,7 @@
{% include 'inc/panels/tags.html' %} + {% include 'inc/panels/comments.html' %} {% plugin_left_page object %}
diff --git a/netbox/templates/wireless/wirelesslink_edit.html b/netbox/templates/wireless/wirelesslink_edit.html index 034d147de..462ae5148 100644 --- a/netbox/templates/wireless/wirelesslink_edit.html +++ b/netbox/templates/wireless/wirelesslink_edit.html @@ -22,6 +22,12 @@
+
+
+
Comments
+
+ {% render_field form.comments %} +
{% if form.custom_fields %}
diff --git a/netbox/tenancy/api/serializers.py b/netbox/tenancy/api/serializers.py index d2c6801c6..c8ef77117 100644 --- a/netbox/tenancy/api/serializers.py +++ b/netbox/tenancy/api/serializers.py @@ -85,8 +85,8 @@ class ContactSerializer(NetBoxModelSerializer): class Meta: model = Contact fields = [ - 'id', 'url', 'display', 'group', 'name', 'title', 'phone', 'email', 'address', 'link', 'comments', 'tags', - 'custom_fields', 'created', 'last_updated', + 'id', 'url', 'display', 'group', 'name', 'title', 'phone', 'email', 'address', 'link', 'description', + 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] diff --git a/netbox/tenancy/forms/bulk_edit.py b/netbox/tenancy/forms/bulk_edit.py index 4c1f03757..183a8e851 100644 --- a/netbox/tenancy/forms/bulk_edit.py +++ b/netbox/tenancy/forms/bulk_edit.py @@ -2,7 +2,7 @@ from django import forms from netbox.forms import NetBoxModelBulkEditForm from tenancy.models import * -from utilities.forms import DynamicModelChoiceField +from utilities.forms import CommentField, DynamicModelChoiceField, SmallTextarea __all__ = ( 'ContactBulkEditForm', @@ -101,9 +101,17 @@ class ContactBulkEditForm(NetBoxModelBulkEditForm): link = forms.URLField( required=False ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = Contact fieldsets = ( - (None, ('group', 'title', 'phone', 'email', 'address', 'link')), + (None, ('group', 'title', 'phone', 'email', 'address', 'link', 'description')), ) - nullable_fields = ('group', 'title', 'phone', 'email', 'address', 'link', 'comments') + nullable_fields = ('group', 'title', 'phone', 'email', 'address', 'link', 'description', 'comments') diff --git a/netbox/tenancy/forms/bulk_import.py b/netbox/tenancy/forms/bulk_import.py index d617a27b5..a465230c5 100644 --- a/netbox/tenancy/forms/bulk_import.py +++ b/netbox/tenancy/forms/bulk_import.py @@ -79,4 +79,4 @@ class ContactCSVForm(NetBoxModelCSVForm): class Meta: model = Contact - fields = ('name', 'title', 'phone', 'email', 'address', 'link', 'group', 'comments') + fields = ('name', 'title', 'phone', 'email', 'address', 'link', 'group', 'description', 'comments') diff --git a/netbox/tenancy/forms/model_forms.py b/netbox/tenancy/forms/model_forms.py index 80af04928..b466c94b2 100644 --- a/netbox/tenancy/forms/model_forms.py +++ b/netbox/tenancy/forms/model_forms.py @@ -103,13 +103,13 @@ class ContactForm(NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Contact', ('group', 'name', 'title', 'phone', 'email', 'address', 'link', 'tags')), + ('Contact', ('group', 'name', 'title', 'phone', 'email', 'address', 'link', 'description', 'tags')), ) class Meta: model = Contact fields = ( - 'group', 'name', 'title', 'phone', 'email', 'address', 'link', 'comments', 'tags', + 'group', 'name', 'title', 'phone', 'email', 'address', 'link', 'description', 'comments', 'tags', ) widgets = { 'address': SmallTextarea(attrs={'rows': 3}), diff --git a/netbox/tenancy/migrations/0009_standardize_description_comments.py b/netbox/tenancy/migrations/0009_standardize_description_comments.py new file mode 100644 index 000000000..af93b055c --- /dev/null +++ b/netbox/tenancy/migrations/0009_standardize_description_comments.py @@ -0,0 +1,18 @@ +# Generated by Django 4.1.2 on 2022-11-03 18:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('tenancy', '0008_unique_constraints'), + ] + + operations = [ + migrations.AddField( + model_name='contact', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + ] diff --git a/netbox/tenancy/models/contacts.py b/netbox/tenancy/models/contacts.py index ba937c167..4fa8d87cb 100644 --- a/netbox/tenancy/models/contacts.py +++ b/netbox/tenancy/models/contacts.py @@ -2,9 +2,8 @@ from django.contrib.contenttypes.fields import GenericForeignKey from django.contrib.contenttypes.models import ContentType from django.db import models from django.urls import reverse -from mptt.models import TreeForeignKey -from netbox.models import ChangeLoggedModel, NestedGroupModel, OrganizationalModel, NetBoxModel +from netbox.models import ChangeLoggedModel, NestedGroupModel, OrganizationalModel, PrimaryModel from netbox.models.features import WebhooksMixin from tenancy.choices import * @@ -41,7 +40,7 @@ class ContactRole(OrganizationalModel): return reverse('tenancy:contactrole', args=[self.pk]) -class Contact(NetBoxModel): +class Contact(PrimaryModel): """ Contact information for a particular object(s) in NetBox. """ @@ -73,9 +72,6 @@ class Contact(NetBoxModel): link = models.URLField( blank=True ) - comments = models.TextField( - blank=True - ) clone_fields = ( 'group', 'name', 'title', 'phone', 'email', 'address', 'link', diff --git a/netbox/tenancy/models/tenants.py b/netbox/tenancy/models/tenants.py index b76efcbf9..4c0c11e2a 100644 --- a/netbox/tenancy/models/tenants.py +++ b/netbox/tenancy/models/tenants.py @@ -1,9 +1,8 @@ from django.contrib.contenttypes.fields import GenericRelation from django.db import models from django.urls import reverse -from mptt.models import TreeForeignKey -from netbox.models import NestedGroupModel, NetBoxModel +from netbox.models import NestedGroupModel, PrimaryModel __all__ = ( 'Tenant', @@ -31,7 +30,7 @@ class TenantGroup(NestedGroupModel): return reverse('tenancy:tenantgroup', args=[self.pk]) -class Tenant(NetBoxModel): +class Tenant(PrimaryModel): """ A Tenant represents an organization served by the NetBox owner. This is typically a customer or an internal department. @@ -51,13 +50,6 @@ class Tenant(NetBoxModel): blank=True, null=True ) - description = models.CharField( - max_length=200, - blank=True - ) - comments = models.TextField( - blank=True - ) # Generic relations contacts = GenericRelation( diff --git a/netbox/tenancy/tables/contacts.py b/netbox/tenancy/tables/contacts.py index 234dc2ad7..b66a1182f 100644 --- a/netbox/tenancy/tables/contacts.py +++ b/netbox/tenancy/tables/contacts.py @@ -65,8 +65,8 @@ class ContactTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = Contact fields = ( - 'pk', 'name', 'group', 'title', 'phone', 'email', 'address', 'link', 'comments', 'assignment_count', 'tags', - 'created', 'last_updated', + 'pk', 'name', 'group', 'title', 'phone', 'email', 'address', 'link', 'description', 'comments', + 'assignment_count', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'group', 'assignment_count', 'title', 'phone', 'email') diff --git a/netbox/virtualization/api/serializers.py b/netbox/virtualization/api/serializers.py index b88bc7712..bb4418b43 100644 --- a/netbox/virtualization/api/serializers.py +++ b/netbox/virtualization/api/serializers.py @@ -58,8 +58,8 @@ class ClusterSerializer(NetBoxModelSerializer): class Meta: model = Cluster fields = [ - 'id', 'url', 'display', 'name', 'type', 'group', 'status', 'tenant', 'site', 'comments', 'tags', - 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count', + 'id', 'url', 'display', 'name', 'type', 'group', 'status', 'tenant', 'site', 'description', 'comments', + 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count', ] @@ -84,8 +84,8 @@ class VirtualMachineSerializer(NetBoxModelSerializer): model = VirtualMachine fields = [ 'id', 'url', 'display', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'platform', - 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'comments', 'local_context_data', - 'tags', 'custom_fields', 'created', 'last_updated', + 'primary_ip', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments', + 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', ] validators = [] diff --git a/netbox/virtualization/forms/bulk_edit.py b/netbox/virtualization/forms/bulk_edit.py index b2429744b..a94b2da1c 100644 --- a/netbox/virtualization/forms/bulk_edit.py +++ b/netbox/virtualization/forms/bulk_edit.py @@ -84,6 +84,10 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm): 'group_id': '$site_group', } ) + description = forms.CharField( + max_length=200, + required=False + ) comments = CommentField( widget=SmallTextarea, label='Comments' @@ -91,11 +95,11 @@ class ClusterBulkEditForm(NetBoxModelBulkEditForm): model = Cluster fieldsets = ( - (None, ('type', 'group', 'status', 'tenant',)), - ('Site', ('region', 'site_group', 'site',)), + (None, ('type', 'group', 'status', 'tenant', 'description')), + ('Site', ('region', 'site_group', 'site')), ) nullable_fields = ( - 'group', 'site', 'comments', 'tenant', + 'group', 'site', 'tenant', 'description', 'comments', ) @@ -153,6 +157,10 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): required=False, label='Disk (GB)' ) + description = forms.CharField( + max_length=200, + required=False + ) comments = CommentField( widget=SmallTextarea, label='Comments' @@ -160,11 +168,11 @@ class VirtualMachineBulkEditForm(NetBoxModelBulkEditForm): model = VirtualMachine fieldsets = ( - (None, ('site', 'cluster', 'device', 'status', 'role', 'tenant', 'platform')), + (None, ('site', 'cluster', 'device', 'status', 'role', 'tenant', 'platform', 'description')), ('Resources', ('vcpus', 'memory', 'disk')) ) nullable_fields = ( - 'site', 'cluster', 'device', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'comments', + 'site', 'cluster', 'device', 'role', 'tenant', 'platform', 'vcpus', 'memory', 'disk', 'description', 'comments', ) diff --git a/netbox/virtualization/forms/bulk_import.py b/netbox/virtualization/forms/bulk_import.py index 2d7ee52e2..d140197dd 100644 --- a/netbox/virtualization/forms/bulk_import.py +++ b/netbox/virtualization/forms/bulk_import.py @@ -63,7 +63,7 @@ class ClusterCSVForm(NetBoxModelCSVForm): class Meta: model = Cluster - fields = ('name', 'type', 'group', 'status', 'site', 'comments') + fields = ('name', 'type', 'group', 'status', 'site', 'description', 'comments') class VirtualMachineCSVForm(NetBoxModelCSVForm): @@ -114,7 +114,7 @@ class VirtualMachineCSVForm(NetBoxModelCSVForm): model = VirtualMachine fields = ( 'name', 'status', 'role', 'site', 'cluster', 'device', 'tenant', 'platform', 'vcpus', 'memory', 'disk', - 'comments', + 'description', 'comments', ) diff --git a/netbox/virtualization/forms/model_forms.py b/netbox/virtualization/forms/model_forms.py index 5438002b4..3f598d061 100644 --- a/netbox/virtualization/forms/model_forms.py +++ b/netbox/virtualization/forms/model_forms.py @@ -90,7 +90,7 @@ class ClusterForm(TenancyForm, NetBoxModelForm): comments = CommentField() fieldsets = ( - ('Cluster', ('name', 'type', 'group', 'status', 'tags')), + ('Cluster', ('name', 'type', 'group', 'status', 'description', 'tags')), ('Site', ('region', 'site_group', 'site')), ('Tenancy', ('tenant_group', 'tenant')), ) @@ -98,7 +98,8 @@ class ClusterForm(TenancyForm, NetBoxModelForm): class Meta: model = Cluster fields = ( - 'name', 'type', 'group', 'status', 'tenant', 'region', 'site_group', 'site', 'comments', 'tags', + 'name', 'type', 'group', 'status', 'tenant', 'region', 'site_group', 'site', 'description', 'comments', + 'tags', ) widgets = { 'status': StaticSelect(), @@ -220,9 +221,10 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): required=False, label='' ) + comments = CommentField() fieldsets = ( - ('Virtual Machine', ('name', 'role', 'status', 'tags')), + ('Virtual Machine', ('name', 'role', 'status', 'description', 'tags')), ('Site/Cluster', ('site', 'cluster_group', 'cluster', 'device')), ('Tenancy', ('tenant_group', 'tenant')), ('Management', ('platform', 'primary_ip4', 'primary_ip6')), @@ -234,7 +236,7 @@ class VirtualMachineForm(TenancyForm, NetBoxModelForm): model = VirtualMachine fields = [ 'name', 'status', 'site', 'cluster_group', 'cluster', 'device', 'role', 'tenant_group', 'tenant', - 'platform', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'comments', 'tags', + 'platform', 'primary_ip4', 'primary_ip6', 'vcpus', 'memory', 'disk', 'description', 'comments', 'tags', 'local_context_data', ] help_texts = { diff --git a/netbox/virtualization/migrations/0034_standardize_description_comments.py b/netbox/virtualization/migrations/0034_standardize_description_comments.py new file mode 100644 index 000000000..8517adeca --- /dev/null +++ b/netbox/virtualization/migrations/0034_standardize_description_comments.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.2 on 2022-11-03 18:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('virtualization', '0033_unique_constraints'), + ] + + operations = [ + migrations.AddField( + model_name='cluster', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + migrations.AddField( + model_name='virtualmachine', + name='description', + field=models.CharField(blank=True, max_length=200), + ), + ] diff --git a/netbox/virtualization/models.py b/netbox/virtualization/models.py index b859d25fe..b5129d581 100644 --- a/netbox/virtualization/models.py +++ b/netbox/virtualization/models.py @@ -10,7 +10,7 @@ from dcim.models import BaseInterface, Device from extras.models import ConfigContextModel from extras.querysets import ConfigContextModelQuerySet from netbox.config import get_config -from netbox.models import OrganizationalModel, NetBoxModel +from netbox.models import NetBoxModel, OrganizationalModel, PrimaryModel from utilities.fields import NaturalOrderingField from utilities.ordering import naturalize_interface from utilities.query_functions import CollateAsChar @@ -64,7 +64,7 @@ class ClusterGroup(OrganizationalModel): # Clusters # -class Cluster(NetBoxModel): +class Cluster(PrimaryModel): """ A cluster of VirtualMachines. Each Cluster may optionally be associated with one or more Devices. """ @@ -102,9 +102,6 @@ class Cluster(NetBoxModel): blank=True, null=True ) - comments = models.TextField( - blank=True - ) # Generic relations vlan_groups = GenericRelation( @@ -165,7 +162,7 @@ class Cluster(NetBoxModel): # Virtual machines # -class VirtualMachine(NetBoxModel, ConfigContextModel): +class VirtualMachine(PrimaryModel, ConfigContextModel): """ A virtual machine which runs inside a Cluster. """ @@ -262,9 +259,6 @@ class VirtualMachine(NetBoxModel, ConfigContextModel): null=True, verbose_name='Disk (GB)' ) - comments = models.TextField( - blank=True - ) # Generic relation contacts = GenericRelation( diff --git a/netbox/virtualization/tables/clusters.py b/netbox/virtualization/tables/clusters.py index ae4c610d7..a3e67373d 100644 --- a/netbox/virtualization/tables/clusters.py +++ b/netbox/virtualization/tables/clusters.py @@ -86,7 +86,7 @@ class ClusterTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = Cluster fields = ( - 'pk', 'id', 'name', 'type', 'group', 'status', 'tenant', 'tenant_group', 'site', 'comments', 'device_count', - 'vm_count', 'contacts', 'tags', 'created', 'last_updated', + 'pk', 'id', 'name', 'type', 'group', 'status', 'tenant', 'tenant_group', 'site', 'description', 'comments', + 'device_count', 'vm_count', 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'name', 'type', 'group', 'status', 'tenant', 'site', 'device_count', 'vm_count') diff --git a/netbox/virtualization/tables/virtualmachines.py b/netbox/virtualization/tables/virtualmachines.py index 29baff4cb..b1d44ad02 100644 --- a/netbox/virtualization/tables/virtualmachines.py +++ b/netbox/virtualization/tables/virtualmachines.py @@ -75,8 +75,8 @@ class VirtualMachineTable(TenancyColumnsMixin, ContactsColumnMixin, NetBoxTable) model = VirtualMachine fields = ( 'pk', 'id', 'name', 'status', 'site', 'cluster', 'device', 'role', 'tenant', 'tenant_group', 'platform', - 'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'comments', 'contacts', 'tags', - 'created', 'last_updated', + 'vcpus', 'memory', 'disk', 'primary_ip4', 'primary_ip6', 'primary_ip', 'description', 'comments', + 'contacts', 'tags', 'created', 'last_updated', ) default_columns = ( 'pk', 'name', 'status', 'site', 'cluster', 'role', 'tenant', 'vcpus', 'memory', 'disk', 'primary_ip', diff --git a/netbox/wireless/api/serializers.py b/netbox/wireless/api/serializers.py index d65511765..109c3a341 100644 --- a/netbox/wireless/api/serializers.py +++ b/netbox/wireless/api/serializers.py @@ -42,7 +42,7 @@ class WirelessLANSerializer(NetBoxModelSerializer): model = WirelessLAN fields = [ 'id', 'url', 'display', 'ssid', 'description', 'group', 'vlan', 'tenant', 'auth_type', 'auth_cipher', - 'auth_psk', 'description', 'tags', 'custom_fields', 'created', 'last_updated', + 'auth_psk', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] @@ -59,5 +59,5 @@ class WirelessLinkSerializer(NetBoxModelSerializer): model = WirelessLink fields = [ 'id', 'url', 'display', 'interface_a', 'interface_b', 'ssid', 'status', 'tenant', 'auth_type', - 'auth_cipher', 'auth_psk', 'description', 'tags', 'custom_fields', 'created', 'last_updated', + 'auth_cipher', 'auth_psk', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', ] diff --git a/netbox/wireless/forms/bulk_edit.py b/netbox/wireless/forms/bulk_edit.py index 639a1ed1b..543e7e0b3 100644 --- a/netbox/wireless/forms/bulk_edit.py +++ b/netbox/wireless/forms/bulk_edit.py @@ -4,7 +4,7 @@ from dcim.choices import LinkStatusChoices from ipam.models import VLAN from netbox.forms import NetBoxModelBulkEditForm from tenancy.models import Tenant -from utilities.forms import add_blank_choice, DynamicModelChoiceField +from utilities.forms import add_blank_choice, CommentField, DynamicModelChoiceField, SmallTextarea from wireless.choices import * from wireless.constants import SSID_MAX_LENGTH from wireless.models import * @@ -52,9 +52,6 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): queryset=Tenant.objects.all(), required=False ) - description = forms.CharField( - required=False - ) auth_type = forms.ChoiceField( choices=add_blank_choice(WirelessAuthTypeChoices), required=False @@ -67,6 +64,14 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): required=False, label='Pre-shared key' ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = WirelessLAN fieldsets = ( @@ -74,7 +79,7 @@ class WirelessLANBulkEditForm(NetBoxModelBulkEditForm): ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')), ) nullable_fields = ( - 'ssid', 'group', 'vlan', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', + 'ssid', 'group', 'vlan', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'comments', ) @@ -92,9 +97,6 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): queryset=Tenant.objects.all(), required=False ) - description = forms.CharField( - required=False - ) auth_type = forms.ChoiceField( choices=add_blank_choice(WirelessAuthTypeChoices), required=False @@ -107,6 +109,14 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): required=False, label='Pre-shared key' ) + description = forms.CharField( + max_length=200, + required=False + ) + comments = CommentField( + widget=SmallTextarea, + label='Comments' + ) model = WirelessLink fieldsets = ( @@ -114,5 +124,5 @@ class WirelessLinkBulkEditForm(NetBoxModelBulkEditForm): ('Authentication', ('auth_type', 'auth_cipher', 'auth_psk')) ) nullable_fields = ( - 'ssid', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', + 'ssid', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'comments', ) diff --git a/netbox/wireless/forms/bulk_import.py b/netbox/wireless/forms/bulk_import.py index 6a1ca4f36..03ac997a3 100644 --- a/netbox/wireless/forms/bulk_import.py +++ b/netbox/wireless/forms/bulk_import.py @@ -60,7 +60,9 @@ class WirelessLANCSVForm(NetBoxModelCSVForm): class Meta: model = WirelessLAN - fields = ('ssid', 'group', 'vlan', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk') + fields = ( + 'ssid', 'group', 'vlan', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk', 'description', 'comments', + ) class WirelessLinkCSVForm(NetBoxModelCSVForm): @@ -94,5 +96,6 @@ class WirelessLinkCSVForm(NetBoxModelCSVForm): class Meta: model = WirelessLink fields = ( - 'interface_a', 'interface_b', 'ssid', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', + 'interface_a', 'interface_b', 'ssid', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk', 'description', + 'comments', ) diff --git a/netbox/wireless/forms/model_forms.py b/netbox/wireless/forms/model_forms.py index 386484193..d57c74575 100644 --- a/netbox/wireless/forms/model_forms.py +++ b/netbox/wireless/forms/model_forms.py @@ -2,7 +2,7 @@ from dcim.models import Device, Interface, Location, Region, Site, SiteGroup from ipam.models import VLAN, VLANGroup from netbox.forms import NetBoxModelForm from tenancy.forms import TenancyForm -from utilities.forms import DynamicModelChoiceField, SlugField, StaticSelect +from utilities.forms import CommentField, DynamicModelChoiceField, SlugField, StaticSelect from wireless.models import * __all__ = ( @@ -82,6 +82,7 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm): 'group_id': '$vlan_group', } ) + comments = CommentField() fieldsets = ( ('Wireless LAN', ('ssid', 'group', 'description', 'tags')), @@ -93,8 +94,8 @@ class WirelessLANForm(TenancyForm, NetBoxModelForm): class Meta: model = WirelessLAN fields = [ - 'ssid', 'group', 'description', 'region', 'site_group', 'site', 'vlan_group', 'vlan', 'tenant_group', - 'tenant', 'auth_type', 'auth_cipher', 'auth_psk', 'tags', + 'ssid', 'group', 'region', 'site_group', 'site', 'vlan_group', 'vlan', 'tenant_group', 'tenant', + 'auth_type', 'auth_cipher', 'auth_psk', 'description', 'comments', 'tags', ] widgets = { 'auth_type': StaticSelect, @@ -183,6 +184,7 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): disabled_indicator='_occupied', label='Interface' ) + comments = CommentField() fieldsets = ( ('Side A', ('site_a', 'location_a', 'device_a', 'interface_a')), @@ -196,7 +198,8 @@ class WirelessLinkForm(TenancyForm, NetBoxModelForm): model = WirelessLink fields = [ 'site_a', 'location_a', 'device_a', 'interface_a', 'site_b', 'location_b', 'device_b', 'interface_b', - 'status', 'ssid', 'tenant_group', 'tenant', 'description', 'auth_type', 'auth_cipher', 'auth_psk', 'tags', + 'status', 'ssid', 'tenant_group', 'tenant', 'auth_type', 'auth_cipher', 'auth_psk', 'description', + 'comments', 'tags', ] widgets = { 'status': StaticSelect, diff --git a/netbox/wireless/migrations/0007_standardize_description_comments.py b/netbox/wireless/migrations/0007_standardize_description_comments.py new file mode 100644 index 000000000..e6e1ce8dd --- /dev/null +++ b/netbox/wireless/migrations/0007_standardize_description_comments.py @@ -0,0 +1,23 @@ +# Generated by Django 4.1.2 on 2022-11-03 18:24 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('wireless', '0006_unique_constraints'), + ] + + operations = [ + migrations.AddField( + model_name='wirelesslan', + name='comments', + field=models.TextField(blank=True), + ), + migrations.AddField( + model_name='wirelesslink', + name='comments', + field=models.TextField(blank=True), + ), + ] diff --git a/netbox/wireless/models.py b/netbox/wireless/models.py index ee2744e40..96764b53c 100644 --- a/netbox/wireless/models.py +++ b/netbox/wireless/models.py @@ -2,11 +2,11 @@ from django.apps import apps from django.core.exceptions import ValidationError from django.db import models from django.urls import reverse -from mptt.models import MPTTModel, TreeForeignKey +from mptt.models import MPTTModel from dcim.choices import LinkStatusChoices from dcim.constants import WIRELESS_IFACE_TYPES -from netbox.models import NestedGroupModel, NetBoxModel +from netbox.models import NestedGroupModel, PrimaryModel from .choices import * from .constants import * @@ -69,7 +69,7 @@ class WirelessLANGroup(NestedGroupModel): return reverse('wireless:wirelesslangroup', args=[self.pk]) -class WirelessLAN(WirelessAuthenticationBase, NetBoxModel): +class WirelessLAN(WirelessAuthenticationBase, PrimaryModel): """ A wireless network formed among an arbitrary number of access point and clients. """ @@ -98,10 +98,6 @@ class WirelessLAN(WirelessAuthenticationBase, NetBoxModel): blank=True, null=True ) - description = models.CharField( - max_length=200, - blank=True - ) clone_fields = ('ssid', 'group', 'tenant', 'description') @@ -122,7 +118,7 @@ def get_wireless_interface_types(): return {'type__in': WIRELESS_IFACE_TYPES} -class WirelessLink(WirelessAuthenticationBase, NetBoxModel): +class WirelessLink(WirelessAuthenticationBase, PrimaryModel): """ A point-to-point connection between two wireless Interfaces. """ @@ -157,10 +153,6 @@ class WirelessLink(WirelessAuthenticationBase, NetBoxModel): blank=True, null=True ) - description = models.CharField( - max_length=200, - blank=True - ) # Cache the associated device for the A and B interfaces. This enables filtering of WirelessLinks by their # associated Devices. diff --git a/netbox/wireless/tables/wirelesslan.py b/netbox/wireless/tables/wirelesslan.py index af0cdae88..4aa5cc1fd 100644 --- a/netbox/wireless/tables/wirelesslan.py +++ b/netbox/wireless/tables/wirelesslan.py @@ -21,6 +21,7 @@ class WirelessLANGroupTable(NetBoxTable): url_params={'group_id': 'pk'}, verbose_name='Wireless LANs' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='wireless:wirelesslangroup_list' ) @@ -28,7 +29,8 @@ class WirelessLANGroupTable(NetBoxTable): class Meta(NetBoxTable.Meta): model = WirelessLANGroup fields = ( - 'pk', 'name', 'wirelesslan_count', 'description', 'slug', 'tags', 'created', 'last_updated', 'actions', + 'pk', 'name', 'wirelesslan_count', 'slug', 'description', 'comments', 'tags', 'created', 'last_updated', + 'actions', ) default_columns = ('pk', 'name', 'wirelesslan_count', 'description') @@ -43,6 +45,7 @@ class WirelessLANTable(TenancyColumnsMixin, NetBoxTable): interface_count = tables.Column( verbose_name='Interfaces' ) + comments = columns.MarkdownColumn() tags = columns.TagColumn( url_name='wireless:wirelesslan_list' ) @@ -50,8 +53,8 @@ class WirelessLANTable(TenancyColumnsMixin, NetBoxTable): class Meta(NetBoxTable.Meta): model = WirelessLAN fields = ( - 'pk', 'ssid', 'group', 'tenant', 'tenant_group', 'description', 'vlan', 'interface_count', 'auth_type', - 'auth_cipher', 'auth_psk', 'tags', 'created', 'last_updated', + 'pk', 'ssid', 'group', 'tenant', 'tenant_group', 'vlan', 'interface_count', 'auth_type', 'auth_cipher', + 'auth_psk', 'description', 'comments', 'tags', 'created', 'last_updated', ) default_columns = ('pk', 'ssid', 'group', 'description', 'vlan', 'auth_type', 'interface_count')