From faf485d4d4fcdce2fb4e645896782f29572d2875 Mon Sep 17 00:00:00 2001 From: jeremystretch Date: Thu, 3 Nov 2022 14:46:14 -0400 Subject: [PATCH] Standardize description & comments fields on primary models --- docs/release-notes/version-3.4.md | 51 ++++++++++++ .../0041_standardize_description_comments.py | 18 +++++ netbox/circuits/models/circuits.py | 11 +-- netbox/circuits/models/providers.py | 17 +--- .../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 +-- .../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/netbox/models/__init__.py | 21 ++++- .../0009_standardize_description_comments.py | 18 +++++ netbox/tenancy/models/contacts.py | 8 +- netbox/tenancy/models/tenants.py | 12 +-- .../0034_standardize_description_comments.py | 23 ++++++ netbox/virtualization/models.py | 12 +-- .../0007_standardize_description_comments.py | 23 ++++++ netbox/wireless/models.py | 16 +--- 25 files changed, 354 insertions(+), 173 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/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/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/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/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/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/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/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.