Standardize description & comments fields on primary models

This commit is contained in:
jeremystretch 2022-11-03 14:46:14 -04:00
parent e2f5ee661a
commit faf485d4d4
25 changed files with 354 additions and 173 deletions

View File

@ -69,18 +69,69 @@ A new `PluginMenu` class has been introduced, which enables a plugin to inject a
* circuits.provider * circuits.provider
* Removed the `asn`, `noc_contact`, `admin_contact`, and `portal_url` fields * 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 * dcim.DeviceType
* Added a `description` field
* Added optional `weight` and `weight_unit` fields * Added optional `weight` and `weight_unit` fields
* dcim.Module
* Added a `description` field
* dcim.ModuleType * dcim.ModuleType
* Added a `description` field
* Added optional `weight` and `weight_unit` fields * Added optional `weight` and `weight_unit` fields
* dcim.PowerFeed
* Added a `description` field
* dcim.PowerPanel
* Added `description` and `comments` fields
* dcim.Rack * dcim.Rack
* Added a `description` field
* Added optional `weight` and `weight_unit` fields * Added optional `weight` and `weight_unit` fields
* dcim.RackReservation
* Added a `comments` field
* dcim.VirtualChassis
* Added `description` and `comments` fields
* extras.CustomLink * extras.CustomLink
* Renamed `content_type` field to `content_types` * Renamed `content_type` field to `content_types`
* extras.ExportTemplate * extras.ExportTemplate
* Renamed `content_type` field to `content_types` * Renamed `content_type` field to `content_types`
* ipam.Aggregate
* Added a `comments` field
* ipam.ASN
* Added a `comments` field
* ipam.FHRPGroup * ipam.FHRPGroup
* Added a `comments` field
* Added optional `name` 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 ### GraphQL API Changes

View File

@ -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),
),
]

View File

@ -7,7 +7,7 @@ from django.urls import reverse
from circuits.choices import * from circuits.choices import *
from dcim.models import CabledObjectModel from dcim.models import CabledObjectModel
from netbox.models import ( from netbox.models import (
ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, NetBoxModel, TagsMixin, ChangeLoggedModel, CustomFieldsMixin, CustomLinksMixin, OrganizationalModel, PrimaryModel, TagsMixin,
) )
from netbox.models.features import WebhooksMixin from netbox.models.features import WebhooksMixin
@ -27,7 +27,7 @@ class CircuitType(OrganizationalModel):
return reverse('circuits:circuittype', args=[self.pk]) 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 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 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, blank=True,
null=True, null=True,
verbose_name='Commit rate (Kbps)') verbose_name='Commit rate (Kbps)')
description = models.CharField(
max_length=200,
blank=True
)
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
contacts = GenericRelation( contacts = GenericRelation(

View File

@ -2,8 +2,7 @@ from django.contrib.contenttypes.fields import GenericRelation
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from dcim.fields import ASNField from netbox.models import PrimaryModel
from netbox.models import NetBoxModel
__all__ = ( __all__ = (
'ProviderNetwork', '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 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. stores information pertinent to the user's relationship with the Provider.
@ -34,9 +33,6 @@ class Provider(NetBoxModel):
blank=True, blank=True,
verbose_name='Account number' verbose_name='Account number'
) )
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
contacts = GenericRelation( contacts = GenericRelation(
@ -57,7 +53,7 @@ class Provider(NetBoxModel):
return reverse('circuits:provider', args=[self.pk]) 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 This represents a provider network which exists outside of NetBox, the details of which are unknown or
unimportant to the user. unimportant to the user.
@ -75,13 +71,6 @@ class ProviderNetwork(NetBoxModel):
blank=True, blank=True,
verbose_name='Service ID' verbose_name='Service ID'
) )
description = models.CharField(
max_length=200,
blank=True
)
comments = models.TextField(
blank=True
)
class Meta: class Meta:
ordering = ('provider', 'name') ordering = ('provider', 'name')

View File

@ -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),
),
]

View File

@ -12,8 +12,8 @@ from django.urls import reverse
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.fields import PathField from dcim.fields import PathField
from dcim.utils import decompile_path_node, object_to_path_node, path_node_to_object from dcim.utils import decompile_path_node, object_to_path_node
from netbox.models import NetBoxModel from netbox.models import PrimaryModel
from utilities.fields import ColorField from utilities.fields import ColorField
from utilities.querysets import RestrictedQuerySet from utilities.querysets import RestrictedQuerySet
from utilities.utils import to_meters from utilities.utils import to_meters
@ -34,7 +34,7 @@ trace_paths = Signal()
# Cables # Cables
# #
class Cable(NetBoxModel): class Cable(PrimaryModel):
""" """
A physical connection between two endpoints. A physical connection between two endpoints.
""" """

View File

@ -18,7 +18,7 @@ from dcim.constants import *
from extras.models import ConfigContextModel from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet from extras.querysets import ConfigContextModelQuerySet
from netbox.config import ConfigItem from netbox.config import ConfigItem
from netbox.models import OrganizationalModel, NetBoxModel from netbox.models import OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices from utilities.choices import ColorChoices
from utilities.fields import ColorField, NaturalOrderingField from utilities.fields import ColorField, NaturalOrderingField
from .device_components import * from .device_components import *
@ -54,7 +54,7 @@ class Manufacturer(OrganizationalModel):
return reverse('dcim:manufacturer', args=[self.pk]) 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 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). well as high-level functional role(s).
@ -117,9 +117,6 @@ class DeviceType(NetBoxModel, WeightMixin):
upload_to='devicetype-images', upload_to='devicetype-images',
blank=True blank=True
) )
comments = models.TextField(
blank=True
)
clone_fields = ( clone_fields = (
'manufacturer', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit', '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 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 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 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, blank=True,
help_text='Discrete part number (optional)' help_text='Discrete part number (optional)'
) )
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
images = GenericRelation( images = GenericRelation(
@ -443,7 +437,7 @@ class Platform(OrganizationalModel):
return reverse('dcim:platform', args=[self.pk]) 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, 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. 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, null=True,
validators=[MaxValueValidator(255)] validators=[MaxValueValidator(255)]
) )
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
contacts = GenericRelation( contacts = GenericRelation(
@ -906,7 +897,7 @@ class Device(NetBoxModel, ConfigContextModel):
return round(total_weight / 1000, 2) 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 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. (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', verbose_name='Asset tag',
help_text='A unique tag used to identify this device' help_text='A unique tag used to identify this device'
) )
comments = models.TextField(
blank=True
)
clone_fields = ('device', 'module_type') clone_fields = ('device', 'module_type')
@ -1019,7 +1007,7 @@ class Module(NetBoxModel, ConfigContextModel):
# Virtual chassis # Virtual chassis
# #
class VirtualChassis(NetBoxModel): class VirtualChassis(PrimaryModel):
""" """
A collection of Devices which operate with a shared control plane (e.g. a switch stack). A collection of Devices which operate with a shared control plane (e.g. a switch stack).
""" """

View File

@ -6,9 +6,8 @@ from django.db import models
from django.urls import reverse from django.urls import reverse
from dcim.choices import * from dcim.choices import *
from dcim.constants import *
from netbox.config import ConfigItem from netbox.config import ConfigItem
from netbox.models import NetBoxModel from netbox.models import PrimaryModel
from utilities.validators import ExclusionValidator from utilities.validators import ExclusionValidator
from .device_components import CabledObjectModel, PathEndpoint from .device_components import CabledObjectModel, PathEndpoint
@ -22,7 +21,7 @@ __all__ = (
# Power # Power
# #
class PowerPanel(NetBoxModel): class PowerPanel(PrimaryModel):
""" """
A distribution point for electrical power; e.g. a data center RPP. 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. An electrical circuit delivered from a PowerPanel.
""" """
@ -132,9 +131,6 @@ class PowerFeed(NetBoxModel, PathEndpoint, CabledObjectModel):
default=0, default=0,
editable=False editable=False
) )
comments = models.TextField(
blank=True
)
clone_fields = ( clone_fields = (
'power_panel', 'rack', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage', 'power_panel', 'rack', 'status', 'type', 'mark_connected', 'supply', 'phase', 'voltage', 'amperage',

View File

@ -14,7 +14,7 @@ from django.urls import reverse
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from dcim.svg import RackElevationSVG from dcim.svg import RackElevationSVG
from netbox.models import OrganizationalModel, NetBoxModel from netbox.models import OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices from utilities.choices import ColorChoices
from utilities.fields import ColorField, NaturalOrderingField from utilities.fields import ColorField, NaturalOrderingField
from utilities.utils import array_to_string, drange from utilities.utils import array_to_string, drange
@ -46,7 +46,7 @@ class RackRole(OrganizationalModel):
return reverse('dcim:rackrole', args=[self.pk]) 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. 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. 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.' 'distance between the front and rear rails.'
) )
) )
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
vlan_groups = GenericRelation( vlan_groups = GenericRelation(
@ -463,7 +460,7 @@ class Rack(NetBoxModel, WeightMixin):
return round(total_weight / 1000, 2) return round(total_weight / 1000, 2)
class RackReservation(NetBoxModel): class RackReservation(PrimaryModel):
""" """
One or more reserved units within a Rack. One or more reserved units within a Rack.
""" """

View File

@ -6,7 +6,7 @@ from timezone_field import TimeZoneField
from dcim.choices import * from dcim.choices import *
from dcim.constants import * from dcim.constants import *
from netbox.models import NestedGroupModel, NetBoxModel from netbox.models import NestedGroupModel, PrimaryModel
from utilities.fields import NaturalOrderingField from utilities.fields import NaturalOrderingField
__all__ = ( __all__ = (
@ -131,7 +131,7 @@ class SiteGroup(NestedGroupModel):
# Sites # Sites
# #
class Site(NetBoxModel): class Site(PrimaryModel):
""" """
A Site represents a geographic location within a network; typically a building or campus. The optional facility 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). 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( time_zone = TimeZoneField(
blank=True blank=True
) )
description = models.CharField(
max_length=200,
blank=True
)
physical_address = models.CharField( physical_address = models.CharField(
max_length=200, max_length=200,
blank=True blank=True
@ -214,9 +210,6 @@ class Site(NetBoxModel):
null=True, null=True,
help_text='GPS coordinate (longitude)' help_text='GPS coordinate (longitude)'
) )
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
vlan_groups = GenericRelation( vlan_groups = GenericRelation(

View File

@ -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),
),
]

View File

@ -4,7 +4,7 @@ from django.core.validators import MaxValueValidator, MinValueValidator
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from netbox.models import ChangeLoggedModel, NetBoxModel from netbox.models import ChangeLoggedModel, PrimaryModel
from netbox.models.features import WebhooksMixin from netbox.models.features import WebhooksMixin
from ipam.choices import * from ipam.choices import *
from ipam.constants 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.) A grouping of next hope resolution protocol (FHRP) peers. (For instance, VRRP or HSRP.)
""" """
@ -41,10 +41,6 @@ class FHRPGroup(NetBoxModel):
blank=True, blank=True,
verbose_name='Authentication key' verbose_name='Authentication key'
) )
description = models.CharField(
max_length=200,
blank=True
)
ip_addresses = GenericRelation( ip_addresses = GenericRelation(
to='ipam.IPAddress', to='ipam.IPAddress',
content_type_field='assigned_object_type', content_type_field='assigned_object_type',

View File

@ -9,7 +9,7 @@ from django.utils.functional import cached_property
from dcim.fields import ASNField from dcim.fields import ASNField
from dcim.models import Device from dcim.models import Device
from netbox.models import OrganizationalModel, NetBoxModel from netbox.models import OrganizationalModel, PrimaryModel
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.fields import IPNetworkField, IPAddressField from ipam.fields import IPNetworkField, IPAddressField
@ -76,7 +76,7 @@ class RIR(OrganizationalModel):
return reverse('ipam:rir', args=[self.pk]) 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 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. one or more ASNs assigned to it.
@ -86,10 +86,6 @@ class ASN(NetBoxModel):
verbose_name='ASN', verbose_name='ASN',
help_text='32-bit autonomous system number' help_text='32-bit autonomous system number'
) )
description = models.CharField(
max_length=200,
blank=True
)
rir = models.ForeignKey( rir = models.ForeignKey(
to='ipam.RIR', to='ipam.RIR',
on_delete=models.PROTECT, on_delete=models.PROTECT,
@ -139,7 +135,7 @@ class ASN(NetBoxModel):
return self.asn 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 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. 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, blank=True,
null=True null=True
) )
description = models.CharField(
max_length=200,
blank=True
)
clone_fields = ( clone_fields = (
'rir', 'tenant', 'date_added', 'description', 'rir', 'tenant', 'date_added', 'description',
@ -264,7 +256,7 @@ class Role(OrganizationalModel):
return reverse('ipam:role', args=[self.pk]) 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 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 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, default=False,
help_text="Treat as 100% utilized" help_text="Treat as 100% utilized"
) )
description = models.CharField(
max_length=200,
blank=True
)
# Cached depth & child counts # Cached depth & child counts
_depth = models.PositiveSmallIntegerField( _depth = models.PositiveSmallIntegerField(
@ -545,7 +533,7 @@ class Prefix(GetAvailablePrefixesMixin, NetBoxModel):
return min(utilization, 100) return min(utilization, 100)
class IPRange(NetBoxModel): class IPRange(PrimaryModel):
""" """
A range of IP addresses, defined by start and end addresses. A range of IP addresses, defined by start and end addresses.
""" """
@ -587,10 +575,6 @@ class IPRange(NetBoxModel):
null=True, null=True,
help_text='The primary function of this range' help_text='The primary function of this range'
) )
description = models.CharField(
max_length=200,
blank=True
)
clone_fields = ( clone_fields = (
'vrf', 'tenant', 'status', 'role', 'description', 'vrf', 'tenant', 'status', 'role', 'description',
@ -740,7 +724,7 @@ class IPRange(NetBoxModel):
return int(float(child_count) / self.size * 100) 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 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 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', verbose_name='DNS Name',
help_text='Hostname or FQDN (not case-sensitive)' help_text='Hostname or FQDN (not case-sensitive)'
) )
description = models.CharField(
max_length=200,
blank=True
)
objects = IPAddressManager() objects = IPAddressManager()

View File

@ -8,7 +8,7 @@ from django.utils.functional import cached_property
from ipam.choices import L2VPNTypeChoices from ipam.choices import L2VPNTypeChoices
from ipam.constants import L2VPN_ASSIGNMENT_MODELS from ipam.constants import L2VPN_ASSIGNMENT_MODELS
from netbox.models import NetBoxModel from netbox.models import NetBoxModel, PrimaryModel
__all__ = ( __all__ = (
'L2VPN', 'L2VPN',
@ -16,7 +16,7 @@ __all__ = (
) )
class L2VPN(NetBoxModel): class L2VPN(PrimaryModel):
name = models.CharField( name = models.CharField(
max_length=100, max_length=100,
unique=True unique=True
@ -43,10 +43,6 @@ class L2VPN(NetBoxModel):
related_name='exporting_l2vpns', related_name='exporting_l2vpns',
blank=True blank=True
) )
description = models.CharField(
max_length=200,
blank=True
)
tenant = models.ForeignKey( tenant = models.ForeignKey(
to='tenancy.Tenant', to='tenancy.Tenant',
on_delete=models.PROTECT, on_delete=models.PROTECT,

View File

@ -6,7 +6,7 @@ from django.urls import reverse
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from netbox.models import NetBoxModel from netbox.models import PrimaryModel
from utilities.utils import array_to_string from utilities.utils import array_to_string
@ -30,10 +30,6 @@ class ServiceBase(models.Model):
), ),
verbose_name='Port numbers' verbose_name='Port numbers'
) )
description = models.CharField(
max_length=200,
blank=True
)
class Meta: class Meta:
abstract = True abstract = True
@ -46,7 +42,7 @@ class ServiceBase(models.Model):
return array_to_string(self.ports) 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. 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]) 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 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. optionally be tied to one or more specific IPAddresses belonging to its parent.

View File

@ -8,12 +8,10 @@ from django.urls import reverse
from dcim.models import Interface from dcim.models import Interface
from ipam.choices import * from ipam.choices import *
from ipam.constants import * from ipam.constants import *
from ipam.models import L2VPNTermination
from ipam.querysets import VLANQuerySet from ipam.querysets import VLANQuerySet
from netbox.models import OrganizationalModel, NetBoxModel from netbox.models import OrganizationalModel, PrimaryModel
from virtualization.models import VMInterface from virtualization.models import VMInterface
__all__ = ( __all__ = (
'VLAN', 'VLAN',
'VLANGroup', 'VLANGroup',
@ -63,10 +61,6 @@ class VLANGroup(OrganizationalModel):
), ),
help_text='Highest permissible ID of a child VLAN' help_text='Highest permissible ID of a child VLAN'
) )
description = models.CharField(
max_length=200,
blank=True
)
class Meta: class Meta:
ordering = ('name', 'pk') # Name may be non-unique ordering = ('name', 'pk') # Name may be non-unique
@ -120,7 +114,7 @@ class VLANGroup(OrganizationalModel):
return None 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 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, 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, blank=True,
null=True null=True
) )
description = models.CharField(
max_length=200,
blank=True
)
l2vpn_terminations = GenericRelation( l2vpn_terminations = GenericRelation(
to='ipam.L2VPNTermination', to='ipam.L2VPNTermination',

View File

@ -2,7 +2,7 @@ from django.db import models
from django.urls import reverse from django.urls import reverse
from ipam.constants import * from ipam.constants import *
from netbox.models import NetBoxModel from netbox.models import PrimaryModel
__all__ = ( __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 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 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', verbose_name='Enforce unique space',
help_text='Prevent duplicate prefixes/IP addresses within this VRF' help_text='Prevent duplicate prefixes/IP addresses within this VRF'
) )
description = models.CharField(
max_length=200,
blank=True
)
import_targets = models.ManyToManyField( import_targets = models.ManyToManyField(
to='ipam.RouteTarget', to='ipam.RouteTarget',
related_name='importing_vrfs', related_name='importing_vrfs',
@ -73,7 +69,7 @@ class VRF(NetBoxModel):
return reverse('ipam:vrf', args=[self.pk]) 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. 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, unique=True,
help_text='Route target value (formatted in accordance with RFC 4360)' help_text='Route target value (formatted in accordance with RFC 4360)'
) )
description = models.CharField(
max_length=200,
blank=True
)
tenant = models.ForeignKey( tenant = models.ForeignKey(
to='tenancy.Tenant', to='tenancy.Tenant',
on_delete=models.PROTECT, on_delete=models.PROTECT,

View File

@ -10,8 +10,9 @@ from netbox.models.features import *
__all__ = ( __all__ = (
'ChangeLoggedModel', 'ChangeLoggedModel',
'NestedGroupModel', 'NestedGroupModel',
'OrganizationalModel',
'NetBoxModel', 'NetBoxModel',
'OrganizationalModel',
'PrimaryModel',
) )
@ -58,7 +59,7 @@ class ChangeLoggedModel(ChangeLoggingMixin, CustomValidationMixin, models.Model)
class NetBoxModel(CloningMixin, NetBoxFeatureSet, 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() objects = RestrictedQuerySet.as_manager()
@ -66,6 +67,22 @@ class NetBoxModel(CloningMixin, NetBoxFeatureSet, models.Model):
abstract = True 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): class NestedGroupModel(NetBoxFeatureSet, MPTTModel):
""" """
Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest Base model for objects which are used to form a hierarchy (regions, locations, etc.). These models nest

View File

@ -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),
),
]

View File

@ -2,9 +2,8 @@ from django.contrib.contenttypes.fields import GenericForeignKey
from django.contrib.contenttypes.models import ContentType from django.contrib.contenttypes.models import ContentType
from django.db import models from django.db import models
from django.urls import reverse 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 netbox.models.features import WebhooksMixin
from tenancy.choices import * from tenancy.choices import *
@ -41,7 +40,7 @@ class ContactRole(OrganizationalModel):
return reverse('tenancy:contactrole', args=[self.pk]) return reverse('tenancy:contactrole', args=[self.pk])
class Contact(NetBoxModel): class Contact(PrimaryModel):
""" """
Contact information for a particular object(s) in NetBox. Contact information for a particular object(s) in NetBox.
""" """
@ -73,9 +72,6 @@ class Contact(NetBoxModel):
link = models.URLField( link = models.URLField(
blank=True blank=True
) )
comments = models.TextField(
blank=True
)
clone_fields = ( clone_fields = (
'group', 'name', 'title', 'phone', 'email', 'address', 'link', 'group', 'name', 'title', 'phone', 'email', 'address', 'link',

View File

@ -1,9 +1,8 @@
from django.contrib.contenttypes.fields import GenericRelation from django.contrib.contenttypes.fields import GenericRelation
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from mptt.models import TreeForeignKey
from netbox.models import NestedGroupModel, NetBoxModel from netbox.models import NestedGroupModel, PrimaryModel
__all__ = ( __all__ = (
'Tenant', 'Tenant',
@ -31,7 +30,7 @@ class TenantGroup(NestedGroupModel):
return reverse('tenancy:tenantgroup', args=[self.pk]) 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 A Tenant represents an organization served by the NetBox owner. This is typically a customer or an internal
department. department.
@ -51,13 +50,6 @@ class Tenant(NetBoxModel):
blank=True, blank=True,
null=True null=True
) )
description = models.CharField(
max_length=200,
blank=True
)
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
contacts = GenericRelation( contacts = GenericRelation(

View File

@ -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),
),
]

View File

@ -10,7 +10,7 @@ from dcim.models import BaseInterface, Device
from extras.models import ConfigContextModel from extras.models import ConfigContextModel
from extras.querysets import ConfigContextModelQuerySet from extras.querysets import ConfigContextModelQuerySet
from netbox.config import get_config 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.fields import NaturalOrderingField
from utilities.ordering import naturalize_interface from utilities.ordering import naturalize_interface
from utilities.query_functions import CollateAsChar from utilities.query_functions import CollateAsChar
@ -64,7 +64,7 @@ class ClusterGroup(OrganizationalModel):
# Clusters # Clusters
# #
class Cluster(NetBoxModel): class Cluster(PrimaryModel):
""" """
A cluster of VirtualMachines. Each Cluster may optionally be associated with one or more Devices. A cluster of VirtualMachines. Each Cluster may optionally be associated with one or more Devices.
""" """
@ -102,9 +102,6 @@ class Cluster(NetBoxModel):
blank=True, blank=True,
null=True null=True
) )
comments = models.TextField(
blank=True
)
# Generic relations # Generic relations
vlan_groups = GenericRelation( vlan_groups = GenericRelation(
@ -165,7 +162,7 @@ class Cluster(NetBoxModel):
# Virtual machines # Virtual machines
# #
class VirtualMachine(NetBoxModel, ConfigContextModel): class VirtualMachine(PrimaryModel, ConfigContextModel):
""" """
A virtual machine which runs inside a Cluster. A virtual machine which runs inside a Cluster.
""" """
@ -262,9 +259,6 @@ class VirtualMachine(NetBoxModel, ConfigContextModel):
null=True, null=True,
verbose_name='Disk (GB)' verbose_name='Disk (GB)'
) )
comments = models.TextField(
blank=True
)
# Generic relation # Generic relation
contacts = GenericRelation( contacts = GenericRelation(

View File

@ -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),
),
]

View File

@ -2,11 +2,11 @@ from django.apps import apps
from django.core.exceptions import ValidationError from django.core.exceptions import ValidationError
from django.db import models from django.db import models
from django.urls import reverse from django.urls import reverse
from mptt.models import MPTTModel, TreeForeignKey from mptt.models import MPTTModel
from dcim.choices import LinkStatusChoices from dcim.choices import LinkStatusChoices
from dcim.constants import WIRELESS_IFACE_TYPES from dcim.constants import WIRELESS_IFACE_TYPES
from netbox.models import NestedGroupModel, NetBoxModel from netbox.models import NestedGroupModel, PrimaryModel
from .choices import * from .choices import *
from .constants import * from .constants import *
@ -69,7 +69,7 @@ class WirelessLANGroup(NestedGroupModel):
return reverse('wireless:wirelesslangroup', args=[self.pk]) 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. A wireless network formed among an arbitrary number of access point and clients.
""" """
@ -98,10 +98,6 @@ class WirelessLAN(WirelessAuthenticationBase, NetBoxModel):
blank=True, blank=True,
null=True null=True
) )
description = models.CharField(
max_length=200,
blank=True
)
clone_fields = ('ssid', 'group', 'tenant', 'description') clone_fields = ('ssid', 'group', 'tenant', 'description')
@ -122,7 +118,7 @@ def get_wireless_interface_types():
return {'type__in': WIRELESS_IFACE_TYPES} return {'type__in': WIRELESS_IFACE_TYPES}
class WirelessLink(WirelessAuthenticationBase, NetBoxModel): class WirelessLink(WirelessAuthenticationBase, PrimaryModel):
""" """
A point-to-point connection between two wireless Interfaces. A point-to-point connection between two wireless Interfaces.
""" """
@ -157,10 +153,6 @@ class WirelessLink(WirelessAuthenticationBase, NetBoxModel):
blank=True, blank=True,
null=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 # Cache the associated device for the A and B interfaces. This enables filtering of WirelessLinks by their
# associated Devices. # associated Devices.