Closes #3682: Add color field to front and rear ports

This commit is contained in:
jeremystretch 2021-06-09 16:51:51 -04:00
parent 8a7473765e
commit b3ed545d6a
12 changed files with 183 additions and 50 deletions

View File

@ -35,6 +35,7 @@ CustomValidator can also be subclassed to enforce more complex logic by overridi
* [#2434](https://github.com/netbox-community/netbox/issues/2434) - Add option to assign IP address upon creating a new interface
* [#3665](https://github.com/netbox-community/netbox/issues/3665) - Enable rendering export templates via REST API
* [#3682](https://github.com/netbox-community/netbox/issues/3682) - Add `color` field to front and rear ports
* [#4609](https://github.com/netbox-community/netbox/issues/4609) - Allow marking prefixes as fully utilized
* [#5806](https://github.com/netbox-community/netbox/issues/5806) - Add kilometer and mile as choices for cable length unit
* [#6154](https://github.com/netbox-community/netbox/issues/6154) - Allow decimal values for cable lengths
@ -54,8 +55,16 @@ CustomValidator can also be subclassed to enforce more complex logic by overridi
* Removed the `display_name` attribute (use `display` instead)
* dcim.DeviceType
* Removed the `display_name` attribute (use `display` instead)
* dcim.FrontPort
* Added `color` field
* dcim.FrontPortTemplate
* Added `color` field
* dcim.Rack
* Removed the `display_name` attribute (use `display` instead)
* dcim.RearPort
* Added `color` field
* dcim.RearPortTemplate
* Added `color` field
* dcim.Site
* `latitude` and `longitude` are now decimal fields rather than strings
* extras.ContentType

View File

@ -384,8 +384,8 @@ class RearPortTemplateSerializer(ValidatedModelSerializer):
class Meta:
model = RearPortTemplate
fields = [
'id', 'url', 'display', 'device_type', 'name', 'label', 'type', 'positions', 'description', 'created',
'last_updated',
'id', 'url', 'display', 'device_type', 'name', 'label', 'type', 'color', 'positions', 'description',
'created', 'last_updated',
]
@ -398,7 +398,7 @@ class FrontPortTemplateSerializer(ValidatedModelSerializer):
class Meta:
model = FrontPortTemplate
fields = [
'id', 'url', 'display', 'device_type', 'name', 'label', 'type', 'rear_port', 'rear_port_position',
'id', 'url', 'display', 'device_type', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position',
'description', 'created', 'last_updated',
]
@ -665,8 +665,9 @@ class RearPortSerializer(PrimaryModelSerializer, CableTerminationSerializer):
class Meta:
model = RearPort
fields = [
'id', 'url', 'display', 'device', 'name', 'label', 'type', 'positions', 'description', 'mark_connected',
'cable', 'cable_peer', 'cable_peer_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
'id', 'url', 'display', 'device', 'name', 'label', 'type', 'color', 'positions', 'description',
'mark_connected', 'cable', 'cable_peer', 'cable_peer_type', 'tags', 'custom_fields', 'created',
'last_updated', '_occupied',
]
@ -691,9 +692,9 @@ class FrontPortSerializer(PrimaryModelSerializer, CableTerminationSerializer):
class Meta:
model = FrontPort
fields = [
'id', 'url', 'display', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description',
'mark_connected', 'cable', 'cable_peer', 'cable_peer_type', 'tags', 'custom_fields', 'created',
'last_updated', '_occupied',
'id', 'url', 'display', 'device', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position',
'description', 'mark_connected', 'cable', 'cable_peer', 'cable_peer_type', 'tags', 'custom_fields',
'created', 'last_updated', '_occupied',
]

View File

@ -538,7 +538,7 @@ class FrontPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponent
class Meta:
model = FrontPortTemplate
fields = ['id', 'name', 'type']
fields = ['id', 'name', 'type', 'color']
class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
@ -549,7 +549,7 @@ class RearPortTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentF
class Meta:
model = RearPortTemplate
fields = ['id', 'name', 'type', 'positions']
fields = ['id', 'name', 'type', 'color', 'positions']
class DeviceBayTemplateFilterSet(ChangeLoggedModelFilterSet, DeviceTypeComponentFilterSet):
@ -1027,7 +1027,7 @@ class FrontPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableT
class Meta:
model = FrontPort
fields = ['id', 'name', 'label', 'type', 'description']
fields = ['id', 'name', 'label', 'type', 'color', 'description']
class RearPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTerminationFilterSet):
@ -1038,7 +1038,7 @@ class RearPortFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet, CableTe
class Meta:
model = RearPort
fields = ['id', 'name', 'label', 'type', 'positions', 'description']
fields = ['id', 'name', 'label', 'type', 'color', 'positions', 'description']
class DeviceBayFilterSet(PrimaryModelFilterSet, DeviceComponentFilterSet):

View File

@ -1610,7 +1610,7 @@ class FrontPortTemplateForm(BootstrapMixin, forms.ModelForm):
class Meta:
model = FrontPortTemplate
fields = [
'device_type', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description',
'device_type', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description',
]
widgets = {
'device_type': forms.HiddenInput(),
@ -1639,7 +1639,7 @@ class FrontPortTemplateCreateForm(ComponentTemplateCreateForm):
help_text='Select one rear port assignment for each front port being created.',
)
field_order = (
'manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'type', 'rear_port_set', 'description',
'manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'type', 'color', 'rear_port_set', 'description',
)
def __init__(self, *args, **kwargs):
@ -1703,6 +1703,11 @@ class FrontPortTemplateBulkEditForm(BootstrapMixin, BulkEditForm):
required=False,
widget=StaticSelect2()
)
color = forms.CharField(
max_length=6, # RGB color code
required=False,
widget=ColorSelect()
)
description = forms.CharField(
required=False
)
@ -1716,7 +1721,7 @@ class RearPortTemplateForm(BootstrapMixin, forms.ModelForm):
class Meta:
model = RearPortTemplate
fields = [
'device_type', 'name', 'label', 'type', 'positions', 'description',
'device_type', 'name', 'label', 'type', 'color', 'positions', 'description',
]
widgets = {
'device_type': forms.HiddenInput(),
@ -1729,13 +1734,20 @@ class RearPortTemplateCreateForm(ComponentTemplateCreateForm):
choices=PortTypeChoices,
widget=StaticSelect2(),
)
color = forms.CharField(
max_length=6, # RGB color code
required=False,
widget=ColorSelect()
)
positions = forms.IntegerField(
min_value=REARPORT_POSITIONS_MIN,
max_value=REARPORT_POSITIONS_MAX,
initial=1,
help_text='The number of front ports which may be mapped to each rear port'
)
field_order = ('manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'type', 'positions', 'description')
field_order = (
'manufacturer', 'device_type', 'name_pattern', 'label_pattern', 'type', 'color', 'positions', 'description',
)
class RearPortTemplateBulkEditForm(BootstrapMixin, BulkEditForm):
@ -1752,6 +1764,11 @@ class RearPortTemplateBulkEditForm(BootstrapMixin, BulkEditForm):
required=False,
widget=StaticSelect2()
)
color = forms.CharField(
max_length=6, # RGB color code
required=False,
widget=ColorSelect()
)
description = forms.CharField(
required=False
)
@ -3427,7 +3444,7 @@ class InterfaceCSVForm(CustomFieldModelCSVForm):
class FrontPortFilterForm(DeviceComponentFilterForm):
field_groups = [
['name', 'label', 'type'],
['name', 'label', 'type', 'color'],
['region_id', 'site_group_id', 'site_id'],
['tag']
]
@ -3437,6 +3454,11 @@ class FrontPortFilterForm(DeviceComponentFilterForm):
required=False,
widget=StaticSelect2Multiple()
)
color = forms.CharField(
max_length=6, # RGB color code
required=False,
widget=ColorSelect()
)
tag = TagFilterField(model)
@ -3449,8 +3471,8 @@ class FrontPortForm(BootstrapMixin, CustomFieldModelForm):
class Meta:
model = FrontPort
fields = [
'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'mark_connected', 'description',
'tags',
'device', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'mark_connected',
'description', 'tags',
]
widgets = {
'device': forms.HiddenInput(),
@ -3475,13 +3497,19 @@ class FrontPortCreateForm(ComponentCreateForm):
choices=PortTypeChoices,
widget=StaticSelect2(),
)
color = forms.CharField(
max_length=6, # RGB color code
required=False,
widget=ColorSelect()
)
rear_port_set = forms.MultipleChoiceField(
choices=[],
label='Rear ports',
help_text='Select one rear port assignment for each front port being created.',
)
field_order = (
'device', 'name_pattern', 'label_pattern', 'type', 'rear_port_set', 'mark_connected', 'description', 'tags',
'device', 'name_pattern', 'label_pattern', 'type', 'color', 'rear_port_set', 'mark_connected', 'description',
'tags',
)
def __init__(self, *args, **kwargs):
@ -3540,7 +3568,7 @@ class FrontPortCreateForm(ComponentCreateForm):
class FrontPortBulkEditForm(
form_from_model(FrontPort, ['label', 'type', 'mark_connected', 'description']),
form_from_model(FrontPort, ['label', 'type', 'color', 'mark_connected', 'description']),
BootstrapMixin,
AddRemoveTagsForm,
CustomFieldBulkEditForm
@ -3572,7 +3600,8 @@ class FrontPortCSVForm(CustomFieldModelCSVForm):
class Meta:
model = FrontPort
fields = (
'device', 'name', 'label', 'type', 'mark_connected', 'rear_port', 'rear_port_position', 'description',
'device', 'name', 'label', 'type', 'color', 'mark_connected', 'rear_port', 'rear_port_position',
'description',
)
help_texts = {
'rear_port_position': 'Mapped position on corresponding rear port',
@ -3608,7 +3637,7 @@ class FrontPortCSVForm(CustomFieldModelCSVForm):
class RearPortFilterForm(DeviceComponentFilterForm):
model = RearPort
field_groups = [
['name', 'label', 'type'],
['name', 'label', 'type', 'color'],
['region_id', 'site_group_id', 'site_id'],
['tag']
]
@ -3617,6 +3646,11 @@ class RearPortFilterForm(DeviceComponentFilterForm):
required=False,
widget=StaticSelect2Multiple()
)
color = forms.CharField(
max_length=6, # RGB color code
required=False,
widget=ColorSelect()
)
tag = TagFilterField(model)
@ -3629,7 +3663,7 @@ class RearPortForm(BootstrapMixin, CustomFieldModelForm):
class Meta:
model = RearPort
fields = [
'device', 'name', 'label', 'type', 'positions', 'mark_connected', 'description', 'tags',
'device', 'name', 'label', 'type', 'color', 'positions', 'mark_connected', 'description', 'tags',
]
widgets = {
'device': forms.HiddenInput(),
@ -3643,6 +3677,11 @@ class RearPortCreateForm(ComponentCreateForm):
choices=PortTypeChoices,
widget=StaticSelect2(),
)
color = forms.CharField(
max_length=6, # RGB color code
required=False,
widget=ColorSelect()
)
positions = forms.IntegerField(
min_value=REARPORT_POSITIONS_MIN,
max_value=REARPORT_POSITIONS_MAX,
@ -3650,12 +3689,13 @@ class RearPortCreateForm(ComponentCreateForm):
help_text='The number of front ports which may be mapped to each rear port'
)
field_order = (
'device', 'name_pattern', 'label_pattern', 'type', 'positions', 'mark_connected', 'description', 'tags',
'device', 'name_pattern', 'label_pattern', 'type', 'color', 'positions', 'mark_connected', 'description',
'tags',
)
class RearPortBulkCreateForm(
form_from_model(RearPort, ['type', 'positions', 'mark_connected']),
form_from_model(RearPort, ['type', 'color', 'positions', 'mark_connected']),
DeviceBulkAddComponentForm
):
model = RearPort
@ -3663,7 +3703,7 @@ class RearPortBulkCreateForm(
class RearPortBulkEditForm(
form_from_model(RearPort, ['label', 'type', 'mark_connected', 'description']),
form_from_model(RearPort, ['label', 'type', 'color', 'mark_connected', 'description']),
BootstrapMixin,
AddRemoveTagsForm,
CustomFieldBulkEditForm
@ -3689,7 +3729,7 @@ class RearPortCSVForm(CustomFieldModelCSVForm):
class Meta:
model = RearPort
fields = ('device', 'name', 'label', 'type', 'mark_connected', 'positions', 'description')
fields = ('device', 'name', 'label', 'type', 'color', 'mark_connected', 'positions', 'description')
help_texts = {
'positions': 'Number of front ports which may be mapped'
}

View File

@ -0,0 +1,32 @@
from django.db import migrations
import utilities.fields
class Migration(migrations.Migration):
dependencies = [
('dcim', '0132_cable_length'),
]
operations = [
migrations.AddField(
model_name='frontport',
name='color',
field=utilities.fields.ColorField(blank=True, max_length=6),
),
migrations.AddField(
model_name='frontporttemplate',
name='color',
field=utilities.fields.ColorField(blank=True, max_length=6),
),
migrations.AddField(
model_name='rearport',
name='color',
field=utilities.fields.ColorField(blank=True, max_length=6),
),
migrations.AddField(
model_name='rearporttemplate',
name='color',
field=utilities.fields.ColorField(blank=True, max_length=6),
),
]

View File

@ -6,7 +6,7 @@ from dcim.choices import *
from dcim.constants import *
from extras.utils import extras_features
from netbox.models import ChangeLoggedModel
from utilities.fields import NaturalOrderingField
from utilities.fields import ColorField, NaturalOrderingField
from utilities.querysets import RestrictedQuerySet
from utilities.ordering import naturalize_interface
from .device_components import (
@ -267,6 +267,9 @@ class FrontPortTemplate(ComponentTemplateModel):
max_length=50,
choices=PortTypeChoices
)
color = ColorField(
blank=True
)
rear_port = models.ForeignKey(
to='dcim.RearPortTemplate',
on_delete=models.CASCADE,
@ -314,6 +317,7 @@ class FrontPortTemplate(ComponentTemplateModel):
name=self.name,
label=self.label,
type=self.type,
color=self.color,
rear_port=rear_port,
rear_port_position=self.rear_port_position
)
@ -328,6 +332,9 @@ class RearPortTemplate(ComponentTemplateModel):
max_length=50,
choices=PortTypeChoices
)
color = ColorField(
blank=True
)
positions = models.PositiveSmallIntegerField(
default=1,
validators=[
@ -346,6 +353,7 @@ class RearPortTemplate(ComponentTemplateModel):
name=self.name,
label=self.label,
type=self.type,
color=self.color,
positions=self.positions
)

View File

@ -12,7 +12,7 @@ from dcim.constants import *
from dcim.fields import MACAddressField
from extras.utils import extras_features
from netbox.models import PrimaryModel
from utilities.fields import NaturalOrderingField
from utilities.fields import ColorField, NaturalOrderingField
from utilities.mptt import TreeManager
from utilities.ordering import naturalize_interface
from utilities.querysets import RestrictedQuerySet
@ -614,6 +614,9 @@ class FrontPort(ComponentModel, CableTermination):
max_length=50,
choices=PortTypeChoices
)
color = ColorField(
blank=True
)
rear_port = models.ForeignKey(
to='dcim.RearPort',
on_delete=models.CASCADE,
@ -663,6 +666,9 @@ class RearPort(ComponentModel, CableTermination):
max_length=50,
choices=PortTypeChoices
)
color = ColorField(
blank=True
)
positions = models.PositiveSmallIntegerField(
default=1,
validators=[

View File

@ -549,6 +549,7 @@ class FrontPortTable(DeviceComponentTable, CableTerminationTable):
'args': [Accessor('device_id')],
}
)
color = ColorColumn()
rear_port_position = tables.Column(
verbose_name='Position'
)
@ -562,10 +563,12 @@ class FrontPortTable(DeviceComponentTable, CableTerminationTable):
class Meta(DeviceComponentTable.Meta):
model = FrontPort
fields = (
'pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'mark_connected',
'cable', 'cable_color', 'cable_peer', 'tags',
'pk', 'device', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description',
'mark_connected', 'cable', 'cable_color', 'cable_peer', 'tags',
)
default_columns = (
'pk', 'device', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description')
class DeviceFrontPortTable(FrontPortTable):
@ -603,6 +606,7 @@ class RearPortTable(DeviceComponentTable, CableTerminationTable):
'args': [Accessor('device_id')],
}
)
color = ColorColumn()
tags = TagColumn(
url_name='dcim:rearport_list'
)
@ -610,10 +614,10 @@ class RearPortTable(DeviceComponentTable, CableTerminationTable):
class Meta(DeviceComponentTable.Meta):
model = RearPort
fields = (
'pk', 'device', 'name', 'label', 'type', 'positions', 'description', 'mark_connected', 'cable',
'pk', 'device', 'name', 'label', 'type', 'color', 'positions', 'description', 'mark_connected', 'cable',
'cable_color', 'cable_peer', 'tags',
)
default_columns = ('pk', 'device', 'name', 'label', 'type', 'description')
default_columns = ('pk', 'device', 'name', 'label', 'type', 'color', 'description')
class DeviceRearPortTable(RearPortTable):

View File

@ -4,7 +4,9 @@ from dcim.models import (
ConsolePortTemplate, ConsoleServerPortTemplate, DeviceBayTemplate, DeviceType, FrontPortTemplate, InterfaceTemplate,
Manufacturer, PowerOutletTemplate, PowerPortTemplate, RearPortTemplate,
)
from utilities.tables import BaseTable, BooleanColumn, ButtonsColumn, LinkedCountColumn, TagColumn, ToggleColumn
from utilities.tables import (
BaseTable, BooleanColumn, ButtonsColumn, ColorColumn, LinkedCountColumn, TagColumn, ToggleColumn,
)
__all__ = (
'ConsolePortTemplateTable',
@ -164,6 +166,7 @@ class FrontPortTemplateTable(ComponentTemplateTable):
rear_port_position = tables.Column(
verbose_name='Position'
)
color = ColorColumn()
actions = ButtonsColumn(
model=FrontPortTemplate,
buttons=('edit', 'delete'),
@ -172,11 +175,12 @@ class FrontPortTemplateTable(ComponentTemplateTable):
class Meta(BaseTable.Meta):
model = FrontPortTemplate
fields = ('pk', 'name', 'label', 'type', 'rear_port', 'rear_port_position', 'description', 'actions')
fields = ('pk', 'name', 'label', 'type', 'color', 'rear_port', 'rear_port_position', 'description', 'actions')
empty_text = "None"
class RearPortTemplateTable(ComponentTemplateTable):
color = ColorColumn()
actions = ButtonsColumn(
model=RearPortTemplate,
buttons=('edit', 'delete'),
@ -185,7 +189,7 @@ class RearPortTemplateTable(ComponentTemplateTable):
class Meta(BaseTable.Meta):
model = RearPortTemplate
fields = ('pk', 'name', 'label', 'type', 'positions', 'description', 'actions')
fields = ('pk', 'name', 'label', 'type', 'color', 'positions', 'description', 'actions')
empty_text = "None"

View File

@ -6,6 +6,7 @@ from dcim.filtersets import *
from dcim.models import *
from ipam.models import IPAddress
from tenancy.models import Tenant, TenantGroup
from utilities.choices import ColorChoices
from utilities.testing import ChangeLoggedFilterSetTests
from virtualization.models import Cluster, ClusterType
@ -959,9 +960,9 @@ class FrontPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
RearPortTemplate.objects.bulk_create(rear_ports)
FrontPortTemplate.objects.bulk_create((
FrontPortTemplate(device_type=device_types[0], name='Front Port 1', rear_port=rear_ports[0], type=PortTypeChoices.TYPE_8P8C),
FrontPortTemplate(device_type=device_types[1], name='Front Port 2', rear_port=rear_ports[1], type=PortTypeChoices.TYPE_110_PUNCH),
FrontPortTemplate(device_type=device_types[2], name='Front Port 3', rear_port=rear_ports[2], type=PortTypeChoices.TYPE_BNC),
FrontPortTemplate(device_type=device_types[0], name='Front Port 1', rear_port=rear_ports[0], type=PortTypeChoices.TYPE_8P8C, color=ColorChoices.COLOR_RED),
FrontPortTemplate(device_type=device_types[1], name='Front Port 2', rear_port=rear_ports[1], type=PortTypeChoices.TYPE_110_PUNCH, color=ColorChoices.COLOR_GREEN),
FrontPortTemplate(device_type=device_types[2], name='Front Port 3', rear_port=rear_ports[2], type=PortTypeChoices.TYPE_BNC, color=ColorChoices.COLOR_BLUE),
))
def test_name(self):
@ -977,6 +978,10 @@ class FrontPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'type': [PortTypeChoices.TYPE_8P8C, PortTypeChoices.TYPE_110_PUNCH]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_color(self):
params = {'color': [ColorChoices.COLOR_RED, ColorChoices.COLOR_GREEN]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
class RearPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
queryset = RearPortTemplate.objects.all()
@ -995,9 +1000,9 @@ class RearPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
DeviceType.objects.bulk_create(device_types)
RearPortTemplate.objects.bulk_create((
RearPortTemplate(device_type=device_types[0], name='Rear Port 1', type=PortTypeChoices.TYPE_8P8C, positions=1),
RearPortTemplate(device_type=device_types[1], name='Rear Port 2', type=PortTypeChoices.TYPE_110_PUNCH, positions=2),
RearPortTemplate(device_type=device_types[2], name='Rear Port 3', type=PortTypeChoices.TYPE_BNC, positions=3),
RearPortTemplate(device_type=device_types[0], name='Rear Port 1', type=PortTypeChoices.TYPE_8P8C, color=ColorChoices.COLOR_RED, positions=1),
RearPortTemplate(device_type=device_types[1], name='Rear Port 2', type=PortTypeChoices.TYPE_110_PUNCH, color=ColorChoices.COLOR_GREEN, positions=2),
RearPortTemplate(device_type=device_types[2], name='Rear Port 3', type=PortTypeChoices.TYPE_BNC, color=ColorChoices.COLOR_BLUE, positions=3),
))
def test_name(self):
@ -1013,6 +1018,10 @@ class RearPortTemplateTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'type': [PortTypeChoices.TYPE_8P8C, PortTypeChoices.TYPE_110_PUNCH]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_color(self):
params = {'color': [ColorChoices.COLOR_RED, ColorChoices.COLOR_GREEN]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_positions(self):
params = {'positions': [1, 2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2153,9 +2162,9 @@ class FrontPortTestCase(TestCase, ChangeLoggedFilterSetTests):
RearPort.objects.bulk_create(rear_ports)
front_ports = (
FrontPort(device=devices[0], name='Front Port 1', label='A', type=PortTypeChoices.TYPE_8P8C, rear_port=rear_ports[0], rear_port_position=1, description='First'),
FrontPort(device=devices[1], name='Front Port 2', label='B', type=PortTypeChoices.TYPE_110_PUNCH, rear_port=rear_ports[1], rear_port_position=2, description='Second'),
FrontPort(device=devices[2], name='Front Port 3', label='C', type=PortTypeChoices.TYPE_BNC, rear_port=rear_ports[2], rear_port_position=3, description='Third'),
FrontPort(device=devices[0], name='Front Port 1', label='A', type=PortTypeChoices.TYPE_8P8C, color=ColorChoices.COLOR_RED, rear_port=rear_ports[0], rear_port_position=1, description='First'),
FrontPort(device=devices[1], name='Front Port 2', label='B', type=PortTypeChoices.TYPE_110_PUNCH, color=ColorChoices.COLOR_GREEN, rear_port=rear_ports[1], rear_port_position=2, description='Second'),
FrontPort(device=devices[2], name='Front Port 3', label='C', type=PortTypeChoices.TYPE_BNC, color=ColorChoices.COLOR_BLUE, rear_port=rear_ports[2], rear_port_position=3, description='Third'),
FrontPort(device=devices[3], name='Front Port 4', label='D', type=PortTypeChoices.TYPE_FC, rear_port=rear_ports[3], rear_port_position=1),
FrontPort(device=devices[3], name='Front Port 5', label='E', type=PortTypeChoices.TYPE_FC, rear_port=rear_ports[4], rear_port_position=1),
FrontPort(device=devices[3], name='Front Port 6', label='F', type=PortTypeChoices.TYPE_FC, rear_port=rear_ports[5], rear_port_position=1),
@ -2179,6 +2188,10 @@ class FrontPortTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'type': [PortTypeChoices.TYPE_8P8C, PortTypeChoices.TYPE_110_PUNCH]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_color(self):
params = {'color': [ColorChoices.COLOR_RED, ColorChoices.COLOR_GREEN]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_description(self):
params = {'description': ['First', 'Second']}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
@ -2260,9 +2273,9 @@ class RearPortTestCase(TestCase, ChangeLoggedFilterSetTests):
Device.objects.bulk_create(devices)
rear_ports = (
RearPort(device=devices[0], name='Rear Port 1', label='A', type=PortTypeChoices.TYPE_8P8C, positions=1, description='First'),
RearPort(device=devices[1], name='Rear Port 2', label='B', type=PortTypeChoices.TYPE_110_PUNCH, positions=2, description='Second'),
RearPort(device=devices[2], name='Rear Port 3', label='C', type=PortTypeChoices.TYPE_BNC, positions=3, description='Third'),
RearPort(device=devices[0], name='Rear Port 1', label='A', type=PortTypeChoices.TYPE_8P8C, color=ColorChoices.COLOR_RED, positions=1, description='First'),
RearPort(device=devices[1], name='Rear Port 2', label='B', type=PortTypeChoices.TYPE_110_PUNCH, color=ColorChoices.COLOR_GREEN, positions=2, description='Second'),
RearPort(device=devices[2], name='Rear Port 3', label='C', type=PortTypeChoices.TYPE_BNC, color=ColorChoices.COLOR_BLUE, positions=3, description='Third'),
RearPort(device=devices[3], name='Rear Port 4', label='D', type=PortTypeChoices.TYPE_FC, positions=4),
RearPort(device=devices[3], name='Rear Port 5', label='E', type=PortTypeChoices.TYPE_FC, positions=5),
RearPort(device=devices[3], name='Rear Port 6', label='F', type=PortTypeChoices.TYPE_FC, positions=6),
@ -2286,6 +2299,10 @@ class RearPortTestCase(TestCase, ChangeLoggedFilterSetTests):
params = {'type': [PortTypeChoices.TYPE_8P8C, PortTypeChoices.TYPE_110_PUNCH]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_color(self):
params = {'color': [ColorChoices.COLOR_RED, ColorChoices.COLOR_GREEN]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
def test_positions(self):
params = {'positions': [1, 2]}
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)

View File

@ -35,6 +35,12 @@
<th scope="row">Type</th>
<td>{{ object.get_type_display }}</td>
</tr>
<tr>
<th scope="row">Color</th>
<td>
<span class="badge color-label" style="background-color: #{{ object.color }}">&nbsp;</span>
</td>
</tr>
<tr>
<th scope="row">Rear Port</th>
<td>

View File

@ -34,6 +34,12 @@
<th scope="row">Type</th>
<td>{{ object.get_type_display }}</td>
</tr>
<tr>
<th scope="row">Color</th>
<td>
<span class="badge color-label" style="background-color: #{{ object.color }}">&nbsp;</span>
</td>
</tr>
<tr>
<th scope="row">Positions</th>
<td>{{ object.positions }}</td>