mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-09 00:58:16 -06:00
12826 add tests and fixes
This commit is contained in:
parent
fc1ce31b00
commit
811c1bdfaa
@ -3,7 +3,7 @@ from rest_framework import serializers
|
||||
|
||||
from dcim.choices import *
|
||||
from dcim.constants import *
|
||||
from dcim.models import Rack, RackReservation, RackRole
|
||||
from dcim.models import Rack, RackReservation, RackRole, RackType
|
||||
from netbox.api.fields import ChoiceField, RelatedObjectCountField
|
||||
from netbox.api.serializers import NetBoxModelSerializer
|
||||
from netbox.config import ConfigItem
|
||||
@ -41,7 +41,7 @@ class RackTypeSerializer(NetBoxModelSerializer):
|
||||
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
|
||||
|
||||
class Meta:
|
||||
model = Rack
|
||||
model = RackType
|
||||
fields = [
|
||||
'id', 'url', 'display_url', 'display', 'name',
|
||||
'type', 'width', 'u_height', 'starting_unit', 'weight', 'max_weight',
|
||||
|
@ -297,19 +297,9 @@ class RackTypeFilterSet(NetBoxModelFilterSet):
|
||||
width = django_filters.MultipleChoiceFilter(
|
||||
choices=RackWidthChoices
|
||||
)
|
||||
role_id = django_filters.ModelMultipleChoiceFilter(
|
||||
queryset=RackRole.objects.all(),
|
||||
label=_('Role (ID)'),
|
||||
)
|
||||
role = django_filters.ModelMultipleChoiceFilter(
|
||||
field_name='role__slug',
|
||||
queryset=RackRole.objects.all(),
|
||||
to_field_name='slug',
|
||||
label=_('Role (slug)'),
|
||||
)
|
||||
|
||||
class Meta:
|
||||
model = Rack
|
||||
model = RackType
|
||||
fields = (
|
||||
'id', 'name', 'u_height', 'starting_unit', 'desc_units', 'outer_width',
|
||||
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit', 'description',
|
||||
|
@ -241,11 +241,10 @@ class RackRoleFilterForm(NetBoxModelFilterSetForm):
|
||||
|
||||
|
||||
class RackTypeFilterForm(NetBoxModelFilterSetForm):
|
||||
model = Rack
|
||||
model = RackType
|
||||
fieldsets = (
|
||||
FieldSet('q', 'filter_id', 'tag'),
|
||||
FieldSet('role_id', name=_('Function')),
|
||||
FieldSet('type', 'width', 'serial', name=_('Hardware')),
|
||||
FieldSet('type', 'width', name=_('Hardware')),
|
||||
FieldSet('weight', 'max_weight', 'weight_unit', name=_('Weight')),
|
||||
)
|
||||
selector_fields = ('filter_id', 'q',)
|
||||
@ -259,16 +258,6 @@ class RackTypeFilterForm(NetBoxModelFilterSetForm):
|
||||
choices=RackWidthChoices,
|
||||
required=False
|
||||
)
|
||||
role_id = DynamicModelMultipleChoiceField(
|
||||
queryset=RackRole.objects.all(),
|
||||
required=False,
|
||||
null_option='None',
|
||||
label=_('Role')
|
||||
)
|
||||
serial = forms.CharField(
|
||||
label=_('Serial'),
|
||||
required=False
|
||||
)
|
||||
tag = TagFilterField(model)
|
||||
weight = forms.DecimalField(
|
||||
label=_('Weight'),
|
||||
|
@ -120,7 +120,7 @@ class RackType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
|
||||
)
|
||||
|
||||
clone_fields = (
|
||||
'role', 'type', 'width', 'u_height', 'desc_units', 'outer_width',
|
||||
'type', 'width', 'u_height', 'desc_units', 'outer_width',
|
||||
'outer_depth', 'outer_unit', 'mounting_depth', 'weight', 'max_weight', 'weight_unit',
|
||||
)
|
||||
prerequisite_models = (
|
||||
@ -172,21 +172,6 @@ class RackType(ImageAttachmentsMixin, PrimaryModel, WeightMixin):
|
||||
return drange(decimal.Decimal(self.starting_unit), self.u_height + self.starting_unit, 0.5)
|
||||
return drange(self.u_height + decimal.Decimal(0.5) + self.starting_unit - 1, 0.5 + self.starting_unit - 1, -0.5)
|
||||
|
||||
@cached_property
|
||||
def total_weight(self):
|
||||
total_weight = sum(
|
||||
device.device_type._abs_weight
|
||||
for device in self.devices.exclude(device_type___abs_weight__isnull=True).prefetch_related('device_type')
|
||||
)
|
||||
total_weight += sum(
|
||||
module.module_type._abs_weight
|
||||
for module in Module.objects.filter(device__rack=self)
|
||||
.exclude(module_type___abs_weight__isnull=True)
|
||||
.prefetch_related('module_type')
|
||||
)
|
||||
if self._abs_weight:
|
||||
total_weight += self._abs_weight
|
||||
return round(total_weight / 1000, 2)
|
||||
|
||||
#
|
||||
# Racks
|
||||
|
@ -242,6 +242,19 @@ class PowerPortIndex(SearchIndex):
|
||||
display_attrs = ('device', 'label', 'type', 'description')
|
||||
|
||||
|
||||
@register_search
|
||||
class RackTypeIndex(SearchIndex):
|
||||
model = models.RackType
|
||||
fields = (
|
||||
('name', 100),
|
||||
('description', 500),
|
||||
('comments', 5000),
|
||||
)
|
||||
display_attrs = (
|
||||
'site', 'description',
|
||||
)
|
||||
|
||||
|
||||
@register_search
|
||||
class RackIndex(SearchIndex):
|
||||
model = models.Rack
|
||||
|
@ -274,6 +274,36 @@ class RackRoleTest(APIViewTestCases.APIViewTestCase):
|
||||
RackRole.objects.bulk_create(rack_roles)
|
||||
|
||||
|
||||
class RackTypeTest(APIViewTestCases.APIViewTestCase):
|
||||
model = RackType
|
||||
brief_fields = ['description', 'display', 'id', 'name', 'url']
|
||||
bulk_update_data = {
|
||||
'description': 'new description',
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
racks = (
|
||||
RackType(name='Rack 1'),
|
||||
RackType(name='Rack 2'),
|
||||
RackType(name='Rack 3'),
|
||||
)
|
||||
RackType.objects.bulk_create(racks)
|
||||
|
||||
cls.create_data = [
|
||||
{
|
||||
'name': 'Test Rack 4',
|
||||
},
|
||||
{
|
||||
'name': 'Test Rack 5',
|
||||
},
|
||||
{
|
||||
'name': 'Test Rack 6',
|
||||
},
|
||||
]
|
||||
|
||||
|
||||
class RackTest(APIViewTestCases.APIViewTestCase):
|
||||
model = Rack
|
||||
brief_fields = ['description', 'device_count', 'display', 'id', 'name', 'url']
|
||||
|
@ -468,6 +468,121 @@ class RackRoleTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class RackTypeTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
queryset = RackType.objects.all()
|
||||
filterset = RackTypeFilterSet
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
racks = (
|
||||
RackType(
|
||||
name='Rack 1',
|
||||
type=RackTypeChoices.TYPE_2POST,
|
||||
width=RackWidthChoices.WIDTH_19IN,
|
||||
u_height=42,
|
||||
desc_units=False,
|
||||
outer_width=100,
|
||||
outer_depth=100,
|
||||
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
|
||||
weight=10,
|
||||
max_weight=1000,
|
||||
weight_unit=WeightUnitChoices.UNIT_POUND,
|
||||
description='foobar1'
|
||||
),
|
||||
RackType(
|
||||
name='Rack 2',
|
||||
type=RackTypeChoices.TYPE_4POST,
|
||||
width=RackWidthChoices.WIDTH_21IN,
|
||||
u_height=43,
|
||||
desc_units=False,
|
||||
outer_width=200,
|
||||
outer_depth=200,
|
||||
outer_unit=RackDimensionUnitChoices.UNIT_MILLIMETER,
|
||||
weight=20,
|
||||
max_weight=2000,
|
||||
weight_unit=WeightUnitChoices.UNIT_POUND,
|
||||
description='foobar2'
|
||||
),
|
||||
RackType(
|
||||
name='Rack 3',
|
||||
type=RackTypeChoices.TYPE_CABINET,
|
||||
width=RackWidthChoices.WIDTH_23IN,
|
||||
u_height=44,
|
||||
desc_units=True,
|
||||
outer_width=300,
|
||||
outer_depth=300,
|
||||
outer_unit=RackDimensionUnitChoices.UNIT_INCH,
|
||||
weight=30,
|
||||
max_weight=3000,
|
||||
weight_unit=WeightUnitChoices.UNIT_KILOGRAM,
|
||||
description='foobar3'
|
||||
),
|
||||
)
|
||||
RackType.objects.bulk_create(racks)
|
||||
|
||||
def test_q(self):
|
||||
params = {'q': 'foobar1'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||
|
||||
def test_name(self):
|
||||
params = {'name': ['Rack 1', 'Rack 2']}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_description(self):
|
||||
params = {'description': ['foobar1', 'foobar2']}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_type(self):
|
||||
params = {'type': [RackTypeChoices.TYPE_2POST, RackTypeChoices.TYPE_4POST]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_width(self):
|
||||
params = {'width': [RackWidthChoices.WIDTH_19IN, RackWidthChoices.WIDTH_21IN]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_u_height(self):
|
||||
params = {'u_height': [42, 43]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_starting_unit(self):
|
||||
params = {'starting_unit': [1]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
||||
params = {'starting_unit': [2]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 0)
|
||||
|
||||
def test_desc_units(self):
|
||||
params = {'desc_units': 'true'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
||||
params = {'desc_units': 'false'}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_outer_width(self):
|
||||
params = {'outer_width': [100, 200]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_outer_depth(self):
|
||||
params = {'outer_depth': [100, 200]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_outer_unit(self):
|
||||
self.assertEqual(Rack.objects.filter(outer_unit__isnull=False).count(), 3)
|
||||
params = {'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_weight(self):
|
||||
params = {'weight': [10, 20]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_max_weight(self):
|
||||
params = {'max_weight': [1000, 2000]}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
def test_weight_unit(self):
|
||||
params = {'weight_unit': WeightUnitChoices.UNIT_POUND}
|
||||
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
||||
|
||||
|
||||
class RackTestCase(TestCase, ChangeLoggedFilterSetTests):
|
||||
queryset = Rack.objects.all()
|
||||
filterset = RackFilterSet
|
||||
|
@ -74,6 +74,17 @@ class LocationTestCase(TestCase):
|
||||
self.assertEqual(PowerPanel.objects.get(pk=powerpanel1.pk).site, site_b)
|
||||
|
||||
|
||||
class RackTypeTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
RackType.objects.create(
|
||||
name='Rack 1',
|
||||
u_height=42
|
||||
)
|
||||
|
||||
|
||||
class RackTestCase(TestCase):
|
||||
|
||||
@classmethod
|
||||
|
@ -336,6 +336,67 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
}
|
||||
|
||||
|
||||
class RackTypeTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
model = RackType
|
||||
|
||||
@classmethod
|
||||
def setUpTestData(cls):
|
||||
|
||||
racks = (
|
||||
Rack(name='Rack 1'),
|
||||
Rack(name='Rack 2'),
|
||||
Rack(name='Rack 3'),
|
||||
)
|
||||
RackType.objects.bulk_create(racks)
|
||||
|
||||
tags = create_tags('Alpha', 'Bravo', 'Charlie')
|
||||
|
||||
cls.form_data = {
|
||||
'name': 'Rack X',
|
||||
'type': RackTypeChoices.TYPE_CABINET,
|
||||
'width': RackWidthChoices.WIDTH_19IN,
|
||||
'u_height': 48,
|
||||
'desc_units': False,
|
||||
'outer_width': 500,
|
||||
'outer_depth': 500,
|
||||
'outer_unit': RackDimensionUnitChoices.UNIT_MILLIMETER,
|
||||
'starting_unit': 1,
|
||||
'weight': 100,
|
||||
'max_weight': 2000,
|
||||
'weight_unit': WeightUnitChoices.UNIT_POUND,
|
||||
'comments': 'Some comments',
|
||||
'tags': [t.pk for t in tags],
|
||||
}
|
||||
|
||||
cls.csv_data = (
|
||||
"name,width,u_height,weight,max_weight,weight_unit",
|
||||
",Rack 4,19,42,100,2000,kg",
|
||||
"Rack 5,19,42,100,2000,kg",
|
||||
"Rack 6,19,42,100,2000,kg",
|
||||
)
|
||||
|
||||
cls.csv_update_data = (
|
||||
"id,name",
|
||||
f"{racks[0].pk},Rack 7",
|
||||
f"{racks[1].pk},Rack 8",
|
||||
f"{racks[2].pk},Rack 9",
|
||||
)
|
||||
|
||||
cls.bulk_edit_data = {
|
||||
'type': RackTypeChoices.TYPE_4POST,
|
||||
'width': RackWidthChoices.WIDTH_23IN,
|
||||
'u_height': 49,
|
||||
'desc_units': True,
|
||||
'outer_width': 30,
|
||||
'outer_depth': 30,
|
||||
'outer_unit': RackDimensionUnitChoices.UNIT_INCH,
|
||||
'weight': 200,
|
||||
'max_weight': 4000,
|
||||
'weight_unit': WeightUnitChoices.UNIT_POUND,
|
||||
'comments': 'New comments',
|
||||
}
|
||||
|
||||
|
||||
class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
||||
model = Rack
|
||||
|
||||
|
@ -592,7 +592,7 @@ class RackTypeListView(generic.ObjectListView):
|
||||
|
||||
@register_model_view(RackType)
|
||||
class RackTypeView(GetRelatedModelsMixin, generic.ObjectView):
|
||||
queryset = Rack.objects.prefetch_related('role')
|
||||
queryset = RackType.objects.all()
|
||||
|
||||
|
||||
@register_model_view(RackType, 'edit')
|
||||
|
123
netbox/templates/dcim/racktype.html
Normal file
123
netbox/templates/dcim/racktype.html
Normal file
@ -0,0 +1,123 @@
|
||||
{% extends 'dcim/rack/base.html' %}
|
||||
{% load buttons %}
|
||||
{% load helpers %}
|
||||
{% load static %}
|
||||
{% load plugins %}
|
||||
{% load i18n %}
|
||||
{% load mptt %}
|
||||
|
||||
{% block content %}
|
||||
<div class="row">
|
||||
<div class="col col-12 col-xl-5">
|
||||
<div class="card">
|
||||
<h5 class="card-header">{% trans "Rack" %}</h5>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Description" %}</th>
|
||||
<td>{{ object.description|placeholder }}</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
<div class="card">
|
||||
<h5 class="card-header">{% trans "Dimensions" %}</h5>
|
||||
<table class="table table-hover attr-table">
|
||||
<tr>
|
||||
<th scope="row">{% trans "Type" %}</th>
|
||||
<td>
|
||||
{% if object.type %}
|
||||
{{ object.get_type_display }}
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Width" %}</th>
|
||||
<td>{{ object.get_width_display }}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Height" %}</th>
|
||||
<td>{{ object.u_height }}U ({% if object.desc_units %}{% trans "descending" %}{% else %}{% trans "ascending" %}{% endif %})</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Starting Unit" %}</th>
|
||||
<td>
|
||||
{{ object.starting_unit }}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Outer Width" %}</th>
|
||||
<td>
|
||||
{% if object.outer_width %}
|
||||
{{ object.outer_width }} {{ object.get_outer_unit_display }}
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Outer Depth" %}</th>
|
||||
<td>
|
||||
{% if object.outer_depth %}
|
||||
{{ object.outer_depth }} {{ object.get_outer_unit_display }}
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Mounting Depth" %}</th>
|
||||
<td>
|
||||
{% if object.mounting_depth %}
|
||||
{{ object.mounting_depth }} {% trans "Millimeters" %}
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Rack Weight" %}</th>
|
||||
<td>
|
||||
{% if object.weight %}
|
||||
{{ object.weight|floatformat }} {{ object.get_weight_unit_display }}
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">{% trans "Maximum Weight" %}</th>
|
||||
<td>
|
||||
{% if object.max_weight %}
|
||||
{{ object.max_weight }} {{ object.get_weight_unit_display }}
|
||||
{% else %}
|
||||
{{ ''|placeholder }}
|
||||
{% endif %}
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
{% include 'inc/panels/custom_fields.html' %}
|
||||
{% include 'inc/panels/tags.html' %}
|
||||
{% include 'inc/panels/comments.html' %}
|
||||
{% include 'inc/panels/image_attachments.html' %}
|
||||
{% plugin_left_page object %}
|
||||
</div>
|
||||
<div class="col col-12 col-xl-7">
|
||||
<div class="text-end mb-4">
|
||||
<select class="btn btn-outline-secondary no-ts rack-view">
|
||||
<option value="images-and-labels" selected="selected">{% trans "Images and Labels" %}</option>
|
||||
<option value="images-only">{% trans "Images only" %}</option>
|
||||
<option value="labels-only">{% trans "Labels only" %}</option>
|
||||
</select>
|
||||
</div>
|
||||
{% include 'inc/panels/related_objects.html' %}
|
||||
{% plugin_right_page object %}
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col col-md-12">
|
||||
{% plugin_full_width_page object %}
|
||||
</div>
|
||||
</div>
|
||||
{% endblock %}
|
Loading…
Reference in New Issue
Block a user