mirror of
https://github.com/netbox-community/netbox.git
synced 2025-07-21 03:27:21 -06:00
Add associatiton from power outlet to power port/phase
This commit is contained in:
parent
0ddd71fc36
commit
3d5f85c0ca
@ -215,10 +215,16 @@ class PowerPortTemplateSerializer(ValidatedModelSerializer):
|
|||||||
|
|
||||||
class PowerOutletTemplateSerializer(ValidatedModelSerializer):
|
class PowerOutletTemplateSerializer(ValidatedModelSerializer):
|
||||||
device_type = NestedDeviceTypeSerializer()
|
device_type = NestedDeviceTypeSerializer()
|
||||||
|
power_port = PowerPortTemplateSerializer()
|
||||||
|
feed_leg = ChoiceField(
|
||||||
|
choices=POWERFEED_LEG_CHOICES,
|
||||||
|
required=False,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutletTemplate
|
model = PowerOutletTemplate
|
||||||
fields = ['id', 'device_type', 'name']
|
fields = ['id', 'device_type', 'name', 'power_port', 'feed_leg']
|
||||||
|
|
||||||
|
|
||||||
class InterfaceTemplateSerializer(ValidatedModelSerializer):
|
class InterfaceTemplateSerializer(ValidatedModelSerializer):
|
||||||
@ -372,14 +378,24 @@ class ConsolePortSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
|||||||
|
|
||||||
class PowerOutletSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
class PowerOutletSerializer(TaggitSerializer, ConnectedEndpointSerializer):
|
||||||
device = NestedDeviceSerializer()
|
device = NestedDeviceSerializer()
|
||||||
cable = NestedCableSerializer(read_only=True)
|
power_port = NestedPowerPortSerializer()
|
||||||
tags = TagListSerializerField(required=False)
|
feed_leg = ChoiceField(
|
||||||
|
choices=POWERFEED_LEG_CHOICES,
|
||||||
|
required=False,
|
||||||
|
allow_null=True
|
||||||
|
)
|
||||||
|
cable = NestedCableSerializer(
|
||||||
|
read_only=True
|
||||||
|
)
|
||||||
|
tags = TagListSerializerField(
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutlet
|
model = PowerOutlet
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'device', 'name', 'description', 'connected_endpoint_type', 'connected_endpoint', 'connection_status',
|
'id', 'device', 'name', 'power_port', 'feed_leg', 'description', 'connected_endpoint_type',
|
||||||
'cable', 'tags',
|
'connected_endpoint', 'connection_status', 'cable', 'tags',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
|
@ -44,6 +44,8 @@ class DCIMFieldChoicesViewSet(FieldChoicesViewSet):
|
|||||||
(FrontPortTemplate, ['type']),
|
(FrontPortTemplate, ['type']),
|
||||||
(Interface, ['form_factor', 'mode']),
|
(Interface, ['form_factor', 'mode']),
|
||||||
(InterfaceTemplate, ['form_factor']),
|
(InterfaceTemplate, ['form_factor']),
|
||||||
|
(PowerOutlet, ['feed_leg']),
|
||||||
|
(PowerOutletTemplate, ['feed_leg']),
|
||||||
(PowerPort, ['connection_status']),
|
(PowerPort, ['connection_status']),
|
||||||
(Rack, ['outer_unit', 'status', 'type', 'width']),
|
(Rack, ['outer_unit', 'status', 'type', 'width']),
|
||||||
(RearPort, ['type']),
|
(RearPort, ['type']),
|
||||||
|
@ -475,3 +475,11 @@ POWERFEED_STATUS_CHOICES = (
|
|||||||
(POWERFEED_STATUS_PLANNED, 'Planned'),
|
(POWERFEED_STATUS_PLANNED, 'Planned'),
|
||||||
(POWERFEED_STATUS_FAILED, 'Failed'),
|
(POWERFEED_STATUS_FAILED, 'Failed'),
|
||||||
)
|
)
|
||||||
|
POWERFEED_LEG_A = 1
|
||||||
|
POWERFEED_LEG_B = 2
|
||||||
|
POWERFEED_LEG_C = 3
|
||||||
|
POWERFEED_LEG_CHOICES = (
|
||||||
|
(POWERFEED_LEG_A, 'A'),
|
||||||
|
(POWERFEED_LEG_B, 'B'),
|
||||||
|
(POWERFEED_LEG_C, 'C'),
|
||||||
|
)
|
||||||
|
@ -977,16 +977,29 @@ class PowerPortTemplateCreateForm(ComponentForm):
|
|||||||
|
|
||||||
|
|
||||||
class PowerOutletTemplateForm(BootstrapMixin, forms.ModelForm):
|
class PowerOutletTemplateForm(BootstrapMixin, forms.ModelForm):
|
||||||
|
power_port = forms.ModelChoiceField(
|
||||||
|
queryset=PowerPortTemplate.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutletTemplate
|
model = PowerOutletTemplate
|
||||||
fields = [
|
fields = [
|
||||||
'device_type', 'name',
|
'device_type', 'name', 'power_port', 'feed_leg',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'device_type': forms.HiddenInput(),
|
'device_type': forms.HiddenInput(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Limit power_port choices to current DeviceType
|
||||||
|
self.fields['power_port'].queryset = PowerPortTemplate.objects.filter(
|
||||||
|
device_type=self.parent
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletTemplateCreateForm(ComponentForm):
|
class PowerOutletTemplateCreateForm(ComponentForm):
|
||||||
name_pattern = ExpandableNameField(
|
name_pattern = ExpandableNameField(
|
||||||
@ -1972,6 +1985,10 @@ class PowerPortCreateForm(ComponentForm):
|
|||||||
#
|
#
|
||||||
|
|
||||||
class PowerOutletForm(BootstrapMixin, forms.ModelForm):
|
class PowerOutletForm(BootstrapMixin, forms.ModelForm):
|
||||||
|
power_port = forms.ModelChoiceField(
|
||||||
|
queryset=PowerPort.objects.all(),
|
||||||
|
required=False
|
||||||
|
)
|
||||||
tags = TagField(
|
tags = TagField(
|
||||||
required=False
|
required=False
|
||||||
)
|
)
|
||||||
@ -1979,12 +1996,20 @@ class PowerOutletForm(BootstrapMixin, forms.ModelForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = PowerOutlet
|
model = PowerOutlet
|
||||||
fields = [
|
fields = [
|
||||||
'device', 'name', 'description', 'tags',
|
'device', 'name', 'power_port', 'feed_leg', 'description', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'device': forms.HiddenInput(),
|
'device': forms.HiddenInput(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def __init__(self, *args, **kwargs):
|
||||||
|
super().__init__(*args, **kwargs)
|
||||||
|
|
||||||
|
# Limit power_port choices to the local device
|
||||||
|
self.fields['power_port'].queryset = PowerPort.objects.filter(
|
||||||
|
device=self.instance.device
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class PowerOutletCreateForm(ComponentForm):
|
class PowerOutletCreateForm(ComponentForm):
|
||||||
name_pattern = ExpandableNameField(
|
name_pattern = ExpandableNameField(
|
||||||
@ -2004,6 +2029,10 @@ class PowerOutletBulkEditForm(BootstrapMixin, AddRemoveTagsForm, BulkEditForm):
|
|||||||
queryset=PowerOutlet.objects.all(),
|
queryset=PowerOutlet.objects.all(),
|
||||||
widget=forms.MultipleHiddenInput()
|
widget=forms.MultipleHiddenInput()
|
||||||
)
|
)
|
||||||
|
feed_leg = forms.ChoiceField(
|
||||||
|
choices=POWERFEED_LEG_CHOICES,
|
||||||
|
required=False,
|
||||||
|
)
|
||||||
description = forms.CharField(
|
description = forms.CharField(
|
||||||
max_length=100,
|
max_length=100,
|
||||||
required=False
|
required=False
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
# Generated by Django 2.1.7 on 2019-03-21 20:59
|
|
||||||
|
|
||||||
import django.core.validators
|
import django.core.validators
|
||||||
from django.db import migrations, models
|
from django.db import migrations, models
|
||||||
import django.db.models.deletion
|
import django.db.models.deletion
|
||||||
@ -112,4 +110,24 @@ class Migration(migrations.Migration):
|
|||||||
name='powerfeed',
|
name='powerfeed',
|
||||||
unique_together={('power_panel', 'name')},
|
unique_together={('power_panel', 'name')},
|
||||||
),
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='poweroutlet',
|
||||||
|
name='feed_leg',
|
||||||
|
field=models.PositiveSmallIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='poweroutlet',
|
||||||
|
name='power_port',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='poweroutlets', to='dcim.PowerPort'),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='poweroutlettemplate',
|
||||||
|
name='feed_leg',
|
||||||
|
field=models.PositiveSmallIntegerField(blank=True, null=True),
|
||||||
|
),
|
||||||
|
migrations.AddField(
|
||||||
|
model_name='poweroutlettemplate',
|
||||||
|
name='power_port',
|
||||||
|
field=models.ForeignKey(blank=True, null=True, on_delete=django.db.models.deletion.SET_NULL, related_name='poweroutlet_templates', to='dcim.PowerPortTemplate'),
|
||||||
|
),
|
||||||
]
|
]
|
||||||
|
@ -1088,6 +1088,19 @@ class PowerOutletTemplate(ComponentTemplateModel):
|
|||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
power_port = models.ForeignKey(
|
||||||
|
to='dcim.PowerPortTemplate',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name='poweroutlet_templates'
|
||||||
|
)
|
||||||
|
feed_leg = models.PositiveSmallIntegerField(
|
||||||
|
choices=POWERFEED_LEG_CHOICES,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text="Phase (for three-phase feeds)"
|
||||||
|
)
|
||||||
|
|
||||||
objects = DeviceComponentManager()
|
objects = DeviceComponentManager()
|
||||||
|
|
||||||
@ -1098,6 +1111,14 @@ class PowerOutletTemplate(ComponentTemplateModel):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.name
|
return self.name
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
|
||||||
|
# Validate power port assignment
|
||||||
|
if self.power_port and self.power_port.device_type != self.device_type:
|
||||||
|
raise ValidationError(
|
||||||
|
"Parent power port ({}) must belong to the same device type".format(self.power_port)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
class InterfaceTemplate(ComponentTemplateModel):
|
class InterfaceTemplate(ComponentTemplateModel):
|
||||||
"""
|
"""
|
||||||
@ -1934,6 +1955,19 @@ class PowerOutlet(CableTermination, ComponentModel):
|
|||||||
name = models.CharField(
|
name = models.CharField(
|
||||||
max_length=50
|
max_length=50
|
||||||
)
|
)
|
||||||
|
power_port = models.ForeignKey(
|
||||||
|
to='dcim.PowerPort',
|
||||||
|
on_delete=models.SET_NULL,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
related_name='poweroutlets'
|
||||||
|
)
|
||||||
|
feed_leg = models.PositiveSmallIntegerField(
|
||||||
|
choices=POWERFEED_LEG_CHOICES,
|
||||||
|
blank=True,
|
||||||
|
null=True,
|
||||||
|
help_text="Phase (for three-phase feeds)"
|
||||||
|
)
|
||||||
connection_status = models.NullBooleanField(
|
connection_status = models.NullBooleanField(
|
||||||
choices=CONNECTION_STATUS_CHOICES,
|
choices=CONNECTION_STATUS_CHOICES,
|
||||||
blank=True
|
blank=True
|
||||||
@ -1942,7 +1976,7 @@ class PowerOutlet(CableTermination, ComponentModel):
|
|||||||
objects = DeviceComponentManager()
|
objects = DeviceComponentManager()
|
||||||
tags = TaggableManager(through=TaggedItem)
|
tags = TaggableManager(through=TaggedItem)
|
||||||
|
|
||||||
csv_headers = ['device', 'name', 'description']
|
csv_headers = ['device', 'name', 'power_port', 'feed_leg', 'description']
|
||||||
|
|
||||||
class Meta:
|
class Meta:
|
||||||
unique_together = ['device', 'name']
|
unique_together = ['device', 'name']
|
||||||
@ -1957,9 +1991,19 @@ class PowerOutlet(CableTermination, ComponentModel):
|
|||||||
return (
|
return (
|
||||||
self.device.identifier,
|
self.device.identifier,
|
||||||
self.name,
|
self.name,
|
||||||
|
self.power_port.name if self.power_port else None,
|
||||||
|
self.get_feed_leg_display(),
|
||||||
self.description,
|
self.description,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def clean(self):
|
||||||
|
|
||||||
|
# Validate power port assignment
|
||||||
|
if self.power_port and self.power_port.device != self.device:
|
||||||
|
raise ValidationError(
|
||||||
|
"Parent power port ({}) must belong to the same device".format(self.power_port)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Interfaces
|
# Interfaces
|
||||||
|
@ -627,6 +627,7 @@
|
|||||||
<th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
|
<th class="pk"><input type="checkbox" class="toggle" title="Toggle all" /></th>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<th>Name</th>
|
<th>Name</th>
|
||||||
|
<th>Input/Leg</th>
|
||||||
<th>Description</th>
|
<th>Description</th>
|
||||||
<th>Cable</th>
|
<th>Cable</th>
|
||||||
<th colspan="3">Connection</th>
|
<th colspan="3">Connection</th>
|
||||||
|
@ -14,6 +14,15 @@
|
|||||||
<i class="fa fa-fw fa-bolt"></i> {{ po }}
|
<i class="fa fa-fw fa-bolt"></i> {{ po }}
|
||||||
</td>
|
</td>
|
||||||
|
|
||||||
|
{# Power port #}
|
||||||
|
<td>
|
||||||
|
{% if po.power_port %}
|
||||||
|
{{ po.power_port }}{% if po.feed_leg %} / {{ po.get_feed_leg_display }}{% endif %}
|
||||||
|
{% else %}
|
||||||
|
<span class="text-warning">None</span>
|
||||||
|
{% endif %}
|
||||||
|
</td>
|
||||||
|
|
||||||
{# Description #}
|
{# Description #}
|
||||||
<td>
|
<td>
|
||||||
{{ po.description|placeholder }}
|
{{ po.description|placeholder }}
|
||||||
|
Loading…
Reference in New Issue
Block a user