mirror of
https://github.com/netbox-community/netbox.git
synced 2025-08-25 08:46:10 -06:00
Fix missing NestedSerializer.
This commit is contained in:
parent
04af1e12b2
commit
b78eebed31
@ -45,6 +45,7 @@ __all__ = [
|
|||||||
'NestedSiteSerializer',
|
'NestedSiteSerializer',
|
||||||
'NestedSiteGroupSerializer',
|
'NestedSiteGroupSerializer',
|
||||||
'NestedVirtualChassisSerializer',
|
'NestedVirtualChassisSerializer',
|
||||||
|
'NestedVirtualDeviceContextSerializer',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -466,3 +467,12 @@ class NestedPowerFeedSerializer(WritableNestedSerializer):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = models.PowerFeed
|
model = models.PowerFeed
|
||||||
fields = ['id', 'url', 'display', 'name', 'cable', '_occupied']
|
fields = ['id', 'url', 'display', 'name', 'cable', '_occupied']
|
||||||
|
|
||||||
|
|
||||||
|
class NestedVirtualDeviceContextSerializer(WritableNestedSerializer):
|
||||||
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualdevicecontext-detail')
|
||||||
|
device = NestedDeviceSerializer()
|
||||||
|
|
||||||
|
class Meta:
|
||||||
|
model = models.VirtualDeviceContext
|
||||||
|
fields = ['id', 'url', 'display', 'name', 'identifier', 'device', 'vdc_type']
|
||||||
|
@ -317,6 +317,7 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
|
|||||||
)
|
)
|
||||||
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False)
|
subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False)
|
||||||
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
|
airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
|
||||||
|
vdc_type = ChoiceField(choices=VirtualDeviceContextTypeChoices, allow_blank=True, required=False)
|
||||||
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
|
weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False)
|
||||||
device_count = serializers.IntegerField(read_only=True)
|
device_count = serializers.IntegerField(read_only=True)
|
||||||
|
|
||||||
@ -324,8 +325,8 @@ class DeviceTypeSerializer(NetBoxModelSerializer):
|
|||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
|
'id', 'url', 'display', 'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth',
|
||||||
'subdevice_role', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'comments', 'tags',
|
'subdevice_role', 'vdc_type', 'airflow', 'weight', 'weight_unit', 'front_image', 'rear_image', 'comments',
|
||||||
'custom_fields', 'created', 'last_updated', 'device_count',
|
'tags', 'custom_fields', 'created', 'last_updated', 'device_count',
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@ -840,6 +841,11 @@ class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
|
|||||||
class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
|
class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
|
||||||
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
|
url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
|
||||||
device = NestedDeviceSerializer()
|
device = NestedDeviceSerializer()
|
||||||
|
vdcs = NestedVirtualDeviceContextSerializer(
|
||||||
|
required=False,
|
||||||
|
allow_null=True,
|
||||||
|
many=True
|
||||||
|
)
|
||||||
module = ComponentNestedModuleSerializer(
|
module = ComponentNestedModuleSerializer(
|
||||||
required=False,
|
required=False,
|
||||||
allow_null=True
|
allow_null=True
|
||||||
@ -876,13 +882,13 @@ class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, Connect
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = [
|
fields = [
|
||||||
'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge', 'lag',
|
'id', 'url', 'display', 'device', 'vdcs', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge',
|
||||||
'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role', 'rf_channel',
|
'lag', 'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role',
|
||||||
'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'untagged_vlan',
|
'rf_channel', 'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
|
||||||
'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link', 'link_peers', 'link_peers_type',
|
'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link', 'link_peers',
|
||||||
'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints', 'connected_endpoints_type',
|
'link_peers_type', 'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints',
|
||||||
'connected_endpoints_reachable', 'tags', 'custom_fields', 'created', 'last_updated', 'count_ipaddresses',
|
'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
|
||||||
'count_fhrp_groups', '_occupied',
|
'last_updated', 'count_ipaddresses', 'count_fhrp_groups', '_occupied',
|
||||||
]
|
]
|
||||||
|
|
||||||
def validate(self, data):
|
def validate(self, data):
|
||||||
|
@ -397,7 +397,7 @@ class DeviceTypeForm(NetBoxModelForm):
|
|||||||
model = DeviceType
|
model = DeviceType
|
||||||
fields = [
|
fields = [
|
||||||
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
'manufacturer', 'model', 'slug', 'part_number', 'u_height', 'is_full_depth', 'subdevice_role', 'airflow',
|
||||||
'vdc_type', 'vdc_type', 'weight', 'weight_unit', 'front_image', 'rear_image', 'comments', 'tags',
|
'vdc_type', 'weight', 'weight_unit', 'front_image', 'rear_image', 'comments', 'tags',
|
||||||
]
|
]
|
||||||
widgets = {
|
widgets = {
|
||||||
'airflow': StaticSelect(),
|
'airflow': StaticSelect(),
|
||||||
@ -1375,7 +1375,7 @@ class PowerOutletForm(ModularDeviceComponentForm):
|
|||||||
|
|
||||||
|
|
||||||
class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
|
class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
|
||||||
vdc = DynamicModelMultipleChoiceField(
|
vdcs = DynamicModelMultipleChoiceField(
|
||||||
queryset=VirtualDeviceContext.objects.all(),
|
queryset=VirtualDeviceContext.objects.all(),
|
||||||
required=False,
|
required=False,
|
||||||
label='Virtual Device Contexts',
|
label='Virtual Device Contexts',
|
||||||
@ -1457,7 +1457,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
|
|||||||
)
|
)
|
||||||
|
|
||||||
fieldsets = (
|
fieldsets = (
|
||||||
('Interface', ('device', 'module', 'vdc', 'name', 'label', 'type', 'speed', 'duplex', 'description', 'tags')),
|
('Interface', ('device', 'module', 'vdcs', 'name', 'label', 'type', 'speed', 'duplex', 'description', 'tags')),
|
||||||
('Addressing', ('vrf', 'mac_address', 'wwn')),
|
('Addressing', ('vrf', 'mac_address', 'wwn')),
|
||||||
('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')),
|
('Operation', ('mtu', 'tx_power', 'enabled', 'mgmt_only', 'mark_connected')),
|
||||||
('Related Interfaces', ('parent', 'bridge', 'lag')),
|
('Related Interfaces', ('parent', 'bridge', 'lag')),
|
||||||
@ -1471,7 +1471,7 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
|
|||||||
class Meta:
|
class Meta:
|
||||||
model = Interface
|
model = Interface
|
||||||
fields = [
|
fields = [
|
||||||
'device', 'module', 'vdc', 'name', 'label', 'type', 'speed', 'duplex', 'enabled', 'parent', 'bridge', 'lag',
|
'device', 'module', 'vdcs', 'name', 'label', 'type', 'speed', 'duplex', 'enabled', 'parent', 'bridge', 'lag',
|
||||||
'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'poe_mode', 'poe_type', 'mode',
|
'mac_address', 'wwn', 'mtu', 'mgmt_only', 'mark_connected', 'description', 'poe_mode', 'poe_type', 'mode',
|
||||||
'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'wireless_lans',
|
'rf_role', 'rf_channel', 'rf_channel_frequency', 'rf_channel_width', 'tx_power', 'wireless_lans',
|
||||||
'untagged_vlan', 'tagged_vlans', 'vrf', 'tags',
|
'untagged_vlan', 'tagged_vlans', 'vrf', 'tags',
|
||||||
@ -1498,9 +1498,9 @@ class InterfaceForm(InterfaceCommonForm, ModularDeviceComponentForm):
|
|||||||
def clean_vdc(self):
|
def clean_vdc(self):
|
||||||
device = self.cleaned_data.get('device')
|
device = self.cleaned_data.get('device')
|
||||||
if device.device_type.vdc_type not in [VirtualDeviceContextTypeChoices.CISCO_ASA_CONTEXT, VirtualDeviceContextTypeChoices.CISCO_FTD_INSTANCE]\
|
if device.device_type.vdc_type not in [VirtualDeviceContextTypeChoices.CISCO_ASA_CONTEXT, VirtualDeviceContextTypeChoices.CISCO_FTD_INSTANCE]\
|
||||||
and len(self.cleaned_data.get('vdc')) > 1:
|
and len(self.cleaned_data.get('vdcs')) > 1:
|
||||||
raise forms.ValidationError(f"You cannot assign more then 1 VDC for {device.device_type}")
|
raise forms.ValidationError(f"You cannot assign more then 1 VDC for {device.device_type}")
|
||||||
return self.cleaned_data.get('vdc')
|
return self.cleaned_data.get('vdcs')
|
||||||
|
|
||||||
|
|
||||||
class FrontPortForm(ModularDeviceComponentForm):
|
class FrontPortForm(ModularDeviceComponentForm):
|
||||||
|
@ -45,7 +45,7 @@ class Migration(migrations.Migration):
|
|||||||
),
|
),
|
||||||
migrations.AddField(
|
migrations.AddField(
|
||||||
model_name='interface',
|
model_name='interface',
|
||||||
name='vdc',
|
name='vdcs',
|
||||||
field=models.ManyToManyField(related_name='interfaces', to='dcim.virtualdevicecontext'),
|
field=models.ManyToManyField(related_name='interfaces', to='dcim.virtualdevicecontext'),
|
||||||
),
|
),
|
||||||
migrations.AddConstraint(
|
migrations.AddConstraint(
|
||||||
|
@ -531,7 +531,7 @@ class Interface(ModularComponentModel, BaseInterface, CabledObjectModel, PathEnd
|
|||||||
max_length=100,
|
max_length=100,
|
||||||
blank=True
|
blank=True
|
||||||
)
|
)
|
||||||
vdc = models.ManyToManyField(
|
vdcs = models.ManyToManyField(
|
||||||
to='dcim.VirtualDeviceContext',
|
to='dcim.VirtualDeviceContext',
|
||||||
related_name='interfaces'
|
related_name='interfaces'
|
||||||
)
|
)
|
||||||
|
@ -124,17 +124,17 @@ class DeviceType(NetBoxModel, WeightMixin):
|
|||||||
help_text='Parent devices house child devices in device bays. Leave blank '
|
help_text='Parent devices house child devices in device bays. Leave blank '
|
||||||
'if this device type is neither a parent nor a child.'
|
'if this device type is neither a parent nor a child.'
|
||||||
)
|
)
|
||||||
|
airflow = models.CharField(
|
||||||
|
max_length=50,
|
||||||
|
choices=DeviceAirflowChoices,
|
||||||
|
blank=True
|
||||||
|
)
|
||||||
vdc_type = models.CharField(
|
vdc_type = models.CharField(
|
||||||
max_length=50,
|
max_length=50,
|
||||||
blank=True,
|
blank=True,
|
||||||
choices=VirtualDeviceContextTypeChoices,
|
choices=VirtualDeviceContextTypeChoices,
|
||||||
verbose_name='VDC Type'
|
verbose_name='VDC Type'
|
||||||
)
|
)
|
||||||
airflow = models.CharField(
|
|
||||||
max_length=50,
|
|
||||||
choices=DeviceAirflowChoices,
|
|
||||||
blank=True
|
|
||||||
)
|
|
||||||
front_image = models.ImageField(
|
front_image = models.ImageField(
|
||||||
upload_to='devicetype-images',
|
upload_to='devicetype-images',
|
||||||
blank=True
|
blank=True
|
||||||
@ -1217,3 +1217,7 @@ class VirtualDeviceContext(NetBoxModel):
|
|||||||
return self.primary_ip4
|
return self.primary_ip4
|
||||||
else:
|
else:
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
@property
|
||||||
|
def vdc_type(self):
|
||||||
|
return self.device.device_type.vdc_type
|
||||||
|
@ -127,13 +127,13 @@ def nullify_connected_endpoints(instance, **kwargs):
|
|||||||
cablepath.retrace()
|
cablepath.retrace()
|
||||||
|
|
||||||
|
|
||||||
@receiver(m2m_changed, sender=Interface.vdc.through)
|
@receiver(m2m_changed, sender=Interface.vdcs.through)
|
||||||
def enforce_vdc_type_restrictions(instance, **kwargs):
|
def enforce_vdc_type_restrictions(instance, **kwargs):
|
||||||
if 'action' == 'post_add':
|
if 'action' == 'post_add':
|
||||||
device = instance.device
|
device = instance.device
|
||||||
if device.device_type.vdc_type not in [VirtualDeviceContextTypeChoices.CISCO_ASA_CONTEXT, VirtualDeviceContextTypeChoices.CISCO_FTD_INSTANCE] \
|
if device.device_type.vdc_type not in [VirtualDeviceContextTypeChoices.CISCO_ASA_CONTEXT, VirtualDeviceContextTypeChoices.CISCO_FTD_INSTANCE] \
|
||||||
and len(instance.vdc) > 1:
|
and len(instance.vdcs) > 1:
|
||||||
print('Error')
|
print('Error')
|
||||||
raise forms.ValidationError({
|
raise forms.ValidationError({
|
||||||
'vdc': f"You cannot assign more then 1 VDC for {device.device_type}"
|
'vdcs': f"You cannot assign more then 1 VDC for {device.device_type}"
|
||||||
})
|
})
|
||||||
|
@ -57,6 +57,12 @@
|
|||||||
{{ object.get_airflow_display|placeholder }}
|
{{ object.get_airflow_display|placeholder }}
|
||||||
</td>
|
</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<td>VDC Type</td>
|
||||||
|
<td>
|
||||||
|
{{ object.get_vdc_type_display|placeholder }}
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<td>Front Image</td>
|
<td>Front Image</td>
|
||||||
<td>
|
<td>
|
||||||
|
@ -36,6 +36,11 @@
|
|||||||
<th scope="row">Identifier</th>
|
<th scope="row">Identifier</th>
|
||||||
<td>{{ object.identifier|placeholder }}</td>
|
<td>{{ object.identifier|placeholder }}</td>
|
||||||
</tr>
|
</tr>
|
||||||
|
</tr>
|
||||||
|
<tr>
|
||||||
|
<th scope="row">VDC Type</th>
|
||||||
|
<td>{{ object.device.device_type.get_vdc_type_display |placeholder }}</td>
|
||||||
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
<th scope="row">Primary IPv4</th>
|
<th scope="row">Primary IPv4</th>
|
||||||
<td>
|
<td>
|
||||||
|
Loading…
Reference in New Issue
Block a user