Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
81f0992
9654 add weight fields to devices
arthanson Sep 23, 2022
f55cd63
9654 add weight fields to devices
arthanson Sep 23, 2022
36ed75d
9654 add weight fields to devices
arthanson Sep 23, 2022
15ad2ab
9654 add weight fields to devices
arthanson Sep 23, 2022
e21f485
9654 add weight fields to devices
arthanson Sep 23, 2022
d0bed83
9654 add weight fields to devices
arthanson Sep 23, 2022
4f75d1e
9654 add weight fields to devices
arthanson Sep 23, 2022
9675ea6
9654 add weight fields to devices
arthanson Sep 23, 2022
bb16c98
9654 add weight fields to devices
arthanson Sep 23, 2022
6b55d88
9654 add weight fields to devices
arthanson Sep 23, 2022
a869720
9654 add weight fields to devices
arthanson Sep 23, 2022
844a208
9654 add weight fields to devices
arthanson Sep 23, 2022
61903db
9654 add weight fields to devices
arthanson Sep 23, 2022
79ec892
9654 add weight fields to devices
arthanson Sep 23, 2022
4919a14
Merge branch 'feature' into 9654-device-weight
arthanson Sep 27, 2022
b049678
9654 changes from code review
arthanson Sep 27, 2022
f964c3f
9654 change _abs_weight to grams
arthanson Sep 27, 2022
6eafdab
Merge branch 'feature' into 9654-device-weight
jeremystretch Sep 29, 2022
c209beb
Resolve migrations conflict
jeremystretch Sep 29, 2022
2659191
9654 fix merge conflict
arthanson Sep 29, 2022
74995a0
9654 code-review changes
arthanson Sep 29, 2022
e3cc5f9
9654 code-review changes
arthanson Sep 29, 2022
44e8c35
9654 total weight on devices
arthanson Sep 29, 2022
d8d439b
Misc cleanup
jeremystretch Sep 30, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/models/dcim/devicetype.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ Indicates whether this is a parent type (capable of housing child devices), a ch

The default direction in which airflow circulates within the device chassis. This may be configured differently for instantiated devices (e.g. because of different fan modules).

### Weight

The numeric weight of the device, including a unit designation (e.g. 10 kilograms or 20 pounds).

### Front & Rear Images

Users can upload illustrations of the device's front and rear panels. If present, these will be used to render the device in [rack](./rack.md) elevation diagrams.
4 changes: 4 additions & 0 deletions docs/models/dcim/moduletype.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,3 +35,7 @@ The model number assigned to this module type by its manufacturer. Must be uniqu
### Part Number

An alternative part number to uniquely identify the module type.

### Weight

The numeric weight of the module, including a unit designation (e.g. 3 kilograms or 1 pound).
4 changes: 4 additions & 0 deletions docs/models/dcim/rack.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ The height of the rack, measured in units.

The external width and depth of the rack can be tracked to aid in floorplan calculations. These measurements must be designated in either millimeters or inches.

### Weight

The numeric weight of the rack, including a unit designation (e.g. 10 kilograms or 20 pounds).

### Descending Units

If selected, the rack's elevation will display unit 1 at the top of the rack. (Most racks use asceneding numbering, with unit 1 assigned to the bottommost position.)
16 changes: 10 additions & 6 deletions netbox/dcim/api/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,15 +201,17 @@ class RackSerializer(NetBoxModelSerializer):
default=None)
width = ChoiceField(choices=RackWidthChoices, required=False)
outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
device_count = serializers.IntegerField(read_only=True)
powerfeed_count = serializers.IntegerField(read_only=True)

class Meta:
model = Rack
fields = [
'id', 'url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial',
'asset_tag', 'type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit',
'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
'asset_tag', 'type', 'width', 'u_height', 'weight', 'weight_unit', 'desc_units', 'outer_width',
'outer_depth', 'outer_unit', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
'powerfeed_count',
]


Expand Down Expand Up @@ -315,27 +317,29 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
)
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False)
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
device_count = serializers.IntegerField(read_only=True)

class Meta:
model = DeviceType
fields = [
'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
'subdevice_role', 'airflow', 'front_image', 'rear_image', 'comments', 'tags', 'custom_fields', 'created',
'last_updated', 'device_count',
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'comments', 'tags',
'custom_fields', 'created', 'last_updated', 'device_count',
]


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', 'comments', 'tags', 'custom_fields',
'created', 'last_updated',
'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'comments', 'tags',
'custom_fields', 'created', 'last_updated',
]


Expand Down
18 changes: 18 additions & 0 deletions netbox/dcim/choices.py
Original file line number Diff line number Diff line change
Expand Up @@ -1314,6 +1314,24 @@ class CableLengthUnitChoices(ChoiceSet):
)


class WeightUnitChoices(ChoiceSet):

# Metric
UNIT_KILOGRAM = 'kg'
UNIT_GRAM = 'g'

# Imperial
UNIT_POUND = 'lb'
UNIT_OUNCE = 'oz'

CHOICES = (
(UNIT_KILOGRAM, 'Kilograms'),
(UNIT_GRAM, 'Grams'),
(UNIT_POUND, 'Pounds'),
(UNIT_OUNCE, 'Ounces'),
)


#
# CableTerminations
#
Expand Down
6 changes: 3 additions & 3 deletions netbox/dcim/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -320,7 +320,7 @@ class Meta:
model = Rack
fields = [
'id', 'name', 'facility_id', 'asset_tag', 'u_height', 'desc_units', 'outer_width', 'outer_depth',
'outer_unit',
'outer_unit', 'weight', 'weight_unit'
]

def search(self, queryset, name, value):
Expand Down Expand Up @@ -482,7 +482,7 @@ class DeviceTypeFilterSet(NetBoxModelFilterSet):
class Meta:
model = DeviceType
fields = [
'id', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
'id', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit'
]

def search(self, queryset, name, value):
Expand Down Expand Up @@ -576,7 +576,7 @@ class ModuleTypeFilterSet(NetBoxModelFilterSet):

class Meta:
model = ModuleType
fields = ['id', 'model', 'part_number']
fields = ['id', 'model', 'part_number', 'weight', 'weight_unit']

def search(self, queryset, name, value):
if not value.strip():
Expand Down
54 changes: 38 additions & 16 deletions netbox/dcim/forms/bulk_edit.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,15 +285,26 @@ class RackBulkEditForm(NetBoxModelBulkEditForm):
widget=SmallTextarea,
label='Comments'
)
weight = forms.DecimalField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial='',
widget=StaticSelect()
)

model = Rack
fieldsets = (
('Rack', ('status', 'role', 'tenant', 'serial', 'asset_tag')),
('Location', ('region', 'site_group', 'site', 'location')),
('Hardware', ('type', 'width', 'u_height', 'desc_units', 'outer_width', 'outer_depth', 'outer_unit')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = (
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'comments',
'location', 'tenant', 'role', 'serial', 'asset_tag', 'outer_width', 'outer_depth', 'outer_unit', 'comments', 'weight', 'weight_unit'
)


Expand Down Expand Up @@ -355,12 +366,23 @@ class DeviceTypeBulkEditForm(NetBoxModelBulkEditForm):
required=False,
widget=StaticSelect()
)
weight = forms.DecimalField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial='',
widget=StaticSelect()
)

model = DeviceType
fieldsets = (
(None, ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow')),
('Device Type', ('manufacturer', 'part_number', 'u_height', 'is_full_depth', 'airflow')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = ('part_number', 'airflow')
nullable_fields = ('part_number', 'airflow', 'weight', 'weight_unit')


class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
Expand All @@ -371,12 +393,23 @@ class ModuleTypeBulkEditForm(NetBoxModelBulkEditForm):
part_number = forms.CharField(
required=False
)
weight = forms.DecimalField(
min_value=0,
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False,
initial='',
widget=StaticSelect()
)

model = ModuleType
fieldsets = (
(None, ('manufacturer', 'part_number')),
('Module Type', ('manufacturer', 'part_number')),
('Weight', ('weight', 'weight_unit')),
)
nullable_fields = ('part_number',)
nullable_fields = ('part_number', 'weight', 'weight_unit')


class DeviceRoleBulkEditForm(NetBoxModelBulkEditForm):
Expand Down Expand Up @@ -553,17 +586,6 @@ class CableBulkEditForm(NetBoxModelBulkEditForm):
'type', 'status', 'tenant', 'label', 'color', 'length',
)

def clean(self):
super().clean()

# Validate length/unit
length = self.cleaned_data.get('length')
length_unit = self.cleaned_data.get('length_unit')
if length and not length_unit:
raise forms.ValidationError({
'length_unit': "Must specify a unit when setting length"
})


class VirtualChassisBulkEditForm(NetBoxModelBulkEditForm):
domain = forms.CharField(
Expand Down
24 changes: 24 additions & 0 deletions netbox/dcim/forms/filtersets.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte
('Hardware', ('type', 'width', 'serial', 'asset_tag')),
('Tenant', ('tenant_group_id', 'tenant_id')),
('Contacts', ('contact', 'contact_role', 'contact_group')),
('Weight', ('weight', 'weight_unit')),
)
region_id = DynamicModelMultipleChoiceField(
queryset=Region.objects.all(),
Expand Down Expand Up @@ -281,6 +282,13 @@ class RackFilterForm(TenancyFilterForm, ContactModelFilterForm, NetBoxModelFilte
required=False
)
tag = TagFilterField(model)
weight = forms.DecimalField(
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False
)


class RackElevationFilterForm(RackFilterForm):
Expand Down Expand Up @@ -370,6 +378,7 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
'pass_through_ports', 'device_bays', 'module_bays', 'inventory_items',
)),
('Weight', ('weight', 'weight_unit')),
)
manufacturer_id = DynamicModelMultipleChoiceField(
queryset=Manufacturer.objects.all(),
Expand Down Expand Up @@ -465,6 +474,13 @@ class DeviceTypeFilterForm(NetBoxModelFilterSetForm):
)
)
tag = TagFilterField(model)
weight = forms.DecimalField(
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False
)


class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
Expand All @@ -476,6 +492,7 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
'console_ports', 'console_server_ports', 'power_ports', 'power_outlets', 'interfaces',
'pass_through_ports',
)),
('Weight', ('weight', 'weight_unit')),
)
manufacturer_id = DynamicModelMultipleChoiceField(
queryset=Manufacturer.objects.all(),
Expand Down Expand Up @@ -529,6 +546,13 @@ class ModuleTypeFilterForm(NetBoxModelFilterSetForm):
)
)
tag = TagFilterField(model)
weight = forms.DecimalField(
required=False
)
weight_unit = forms.ChoiceField(
choices=add_blank_choice(WeightUnitChoices),
required=False
)


class DeviceRoleFilterForm(NetBoxModelFilterSetForm):
Expand Down
17 changes: 12 additions & 5 deletions netbox/dcim/forms/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,7 +260,7 @@ class Meta:
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', 'comments', 'tags',
'outer_unit', 'weight', 'weight_unit', 'comments', 'tags',
]
help_texts = {
'site': "The site at which the rack exists",
Expand All @@ -273,6 +273,7 @@ class Meta:
'type': StaticSelect(),
'width': StaticSelect(),
'outer_unit': StaticSelect(),
'weight_unit': StaticSelect(),
}


Expand Down Expand Up @@ -363,14 +364,15 @@ class DeviceTypeForm(NetBoxModelForm):
('Chassis', (
'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
)),
('Attributes', ('weight', 'weight_unit')),
('Images', ('front_image', 'rear_image')),
)

class Meta:
model = DeviceType
fields = [
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
'front_image', 'rear_image', 'comments', 'tags',
'weight', 'weight_unit', 'front_image', 'rear_image', 'comments', 'tags',
]
widgets = {
'airflow': StaticSelect(),
Expand All @@ -380,7 +382,8 @@ class Meta:
}),
'rear_image': ClearableFileInput(attrs={
'accept': DEVICETYPE_IMAGE_FORMATS
})
}),
'weight_unit': StaticSelect(),
}


Expand All @@ -392,16 +395,20 @@ class ModuleTypeForm(NetBoxModelForm):

fieldsets = (
('Module Type', (
'manufacturer', 'model', 'part_number', 'tags',
'manufacturer', 'model', 'part_number', 'tags', 'weight', 'weight_unit'
)),
)

class Meta:
model = ModuleType
fields = [
'manufacturer', 'model', 'part_number', 'comments', 'tags',
'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'comments', 'tags',
]

widgets = {
'weight_unit': StaticSelect(),
}


class DeviceRoleForm(NetBoxModelForm):
slug = SlugField()
Expand Down
9 changes: 9 additions & 0 deletions netbox/dcim/graphql/types.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,9 @@ def resolve_subdevice_role(self, info):
def resolve_airflow(self, info):
return self.airflow or None

def resolve_weight_unit(self, info):
return self.weight_unit or None


class FrontPortType(ComponentObjectType, CabledObjectMixin):

Expand Down Expand Up @@ -328,6 +331,9 @@ class Meta:
fields = '__all__'
filterset_class = filtersets.ModuleTypeFilterSet

def resolve_weight_unit(self, info):
return self.weight_unit or None


class PlatformType(OrganizationalObjectType):

Expand Down Expand Up @@ -416,6 +422,9 @@ def resolve_type(self, info):
def resolve_outer_unit(self, info):
return self.outer_unit or None

def resolve_weight_unit(self, info):
return self.weight_unit or None


class RackReservationType(NetBoxObjectType):

Expand Down
Loading