1
0
mirror of https://github.com/netbox-community/netbox.git synced 2024-05-10 07:54:54 +00:00

Closes #5895: Rename RackGroup to Location

This commit is contained in:
Jeremy Stretch
2021-03-03 13:30:33 -05:00
parent a17018a875
commit fdb3e3f9a4
33 changed files with 536 additions and 488 deletions

View File

@@ -16,21 +16,20 @@ from taggit.managers import TaggableManager
from dcim.choices import *
from dcim.constants import *
from dcim.elevations import RackElevationSVG
from extras.models import ObjectChange, TaggedItem
from extras.models import TaggedItem
from extras.utils import extras_features
from netbox.models import NestedGroupModel, OrganizationalModel, PrimaryModel
from utilities.choices import ColorChoices
from utilities.fields import ColorField, NaturalOrderingField
from utilities.querysets import RestrictedQuerySet
from utilities.mptt import TreeManager
from utilities.utils import array_to_string, serialize_object
from utilities.utils import array_to_string
from .device_components import PowerOutlet, PowerPort
from .devices import Device
from .power import PowerFeed
__all__ = (
'Rack',
'RackGroup',
'Location',
'RackReservation',
'RackRole',
)
@@ -41,11 +40,10 @@ __all__ = (
#
@extras_features('custom_fields', 'export_templates', 'webhooks')
class RackGroup(NestedGroupModel):
class Location(NestedGroupModel):
"""
Racks can be grouped as subsets within a Site. The scope of a group will depend on how Sites are defined. For
example, if a Site spans a corporate campus, a RackGroup might be defined to represent each building within that
campus. If a Site instead represents a single building, a RackGroup might represent a single room or floor.
A Location represents a subgroup of Racks and/or Devices within a Site. A Location may represent a building within a
site, or a room within a building, for example.
"""
name = models.CharField(
max_length=100
@@ -56,7 +54,7 @@ class RackGroup(NestedGroupModel):
site = models.ForeignKey(
to='dcim.Site',
on_delete=models.CASCADE,
related_name='rack_groups'
related_name='locations'
)
parent = TreeForeignKey(
to='self',
@@ -81,7 +79,7 @@ class RackGroup(NestedGroupModel):
]
def get_absolute_url(self):
return "{}?group_id={}".format(reverse('dcim:rack_list'), self.pk)
return "{}?location_id={}".format(reverse('dcim:rack_list'), self.pk)
def to_csv(self):
return (
@@ -95,9 +93,9 @@ class RackGroup(NestedGroupModel):
def clean(self):
super().clean()
# Parent RackGroup (if any) must belong to the same Site
# Parent Location (if any) must belong to the same Site
if self.parent and self.parent.site != self.site:
raise ValidationError(f"Parent rack group ({self.parent}) must belong to the same site ({self.site})")
raise ValidationError(f"Parent location ({self.parent}) must belong to the same site ({self.site})")
@extras_features('custom_fields', 'export_templates', 'webhooks')
@@ -147,7 +145,7 @@ class RackRole(OrganizationalModel):
class Rack(PrimaryModel):
"""
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 RackGroup.
Each Rack is assigned to a Site and (optionally) a Location.
"""
name = models.CharField(
max_length=100
@@ -169,13 +167,12 @@ class Rack(PrimaryModel):
on_delete=models.PROTECT,
related_name='racks'
)
group = models.ForeignKey(
to='dcim.RackGroup',
location = models.ForeignKey(
to='dcim.Location',
on_delete=models.SET_NULL,
related_name='racks',
blank=True,
null=True,
help_text='Assigned group'
null=True
)
tenant = models.ForeignKey(
to='tenancy.Tenant',
@@ -259,20 +256,20 @@ class Rack(PrimaryModel):
objects = RestrictedQuerySet.as_manager()
csv_headers = [
'site', 'group', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'asset_tag', 'width',
'site', 'location', 'name', 'facility_id', 'tenant', 'status', 'role', 'type', 'serial', 'asset_tag', 'width',
'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'comments',
]
clone_fields = [
'site', 'group', 'tenant', 'status', 'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
'site', 'location', 'tenant', 'status', 'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
'outer_depth', 'outer_unit',
]
class Meta:
ordering = ('site', 'group', '_name', 'pk') # (site, group, name) may be non-unique
ordering = ('site', 'location', '_name', 'pk') # (site, location, name) may be non-unique
unique_together = (
# Name and facility_id must be unique *only* within a RackGroup
('group', 'name'),
('group', 'facility_id'),
# Name and facility_id must be unique *only* within a Location
('location', 'name'),
('location', 'facility_id'),
)
def __str__(self):
@@ -284,9 +281,9 @@ class Rack(PrimaryModel):
def clean(self):
super().clean()
# Validate group/site assignment
if self.site and self.group and self.group.site != self.site:
raise ValidationError(f"Assigned rack group must belong to parent site ({self.site}).")
# Validate location/site assignment
if self.site and self.location and self.location.site != self.site:
raise ValidationError(f"Assigned location must belong to parent site ({self.site}).")
# Validate outer dimensions and unit
if (self.outer_width is not None or self.outer_depth is not None) and not self.outer_unit:
@@ -309,17 +306,17 @@ class Rack(PrimaryModel):
min_height
)
})
# Validate that Rack was assigned a group of its same site, if applicable
if self.group:
if self.group.site != self.site:
# Validate that Rack was assigned a Location of its same site, if applicable
if self.location:
if self.location.site != self.site:
raise ValidationError({
'group': "Rack group must be from the same site, {}.".format(self.site)
'location': f"Location must be from the same site, {self.site}."
})
def to_csv(self):
return (
self.site.name,
self.group.name if self.group else None,
self.location.name if self.location else None,
self.name,
self.facility_id,
self.tenant.name if self.tenant else None,
@@ -565,7 +562,7 @@ class RackReservation(PrimaryModel):
objects = RestrictedQuerySet.as_manager()
csv_headers = ['site', 'rack_group', 'rack', 'units', 'tenant', 'user', 'description']
csv_headers = ['site', 'location', 'rack', 'units', 'tenant', 'user', 'description']
class Meta:
ordering = ['created', 'pk']
@@ -606,7 +603,7 @@ class RackReservation(PrimaryModel):
def to_csv(self):
return (
self.rack.site.name,
self.rack.group if self.rack.group else None,
self.rack.location if self.rack.location else None,
self.rack.name,
','.join([str(u) for u in self.units]),
self.tenant.name if self.tenant else None,