serializers.py 49 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255
  1. import decimal
  2. from django.contrib.contenttypes.models import ContentType
  3. from django.utils.translation import gettext as _
  4. from drf_spectacular.types import OpenApiTypes
  5. from drf_spectacular.utils import extend_schema_field
  6. from rest_framework import serializers
  7. from timezone_field.rest_framework import TimeZoneSerializerField
  8. from dcim.choices import *
  9. from dcim.constants import *
  10. from dcim.models import *
  11. from extras.api.nested_serializers import NestedConfigTemplateSerializer
  12. from ipam.api.nested_serializers import (
  13. NestedASNSerializer, NestedIPAddressSerializer, NestedVLANSerializer, NestedVRFSerializer,
  14. )
  15. from ipam.models import ASN, VLAN
  16. from netbox.api.fields import ChoiceField, ContentTypeField, SerializedPKRelatedField
  17. from netbox.api.serializers import (
  18. GenericObjectSerializer, NestedGroupModelSerializer, NetBoxModelSerializer, ValidatedModelSerializer,
  19. WritableNestedSerializer,
  20. )
  21. from netbox.config import ConfigItem
  22. from netbox.constants import NESTED_SERIALIZER_PREFIX
  23. from tenancy.api.nested_serializers import NestedTenantSerializer
  24. from users.api.nested_serializers import NestedUserSerializer
  25. from utilities.api import get_serializer_for_model
  26. from virtualization.api.nested_serializers import NestedClusterSerializer
  27. from vpn.api.nested_serializers import NestedL2VPNTerminationSerializer
  28. from wireless.api.nested_serializers import NestedWirelessLANSerializer, NestedWirelessLinkSerializer
  29. from wireless.choices import *
  30. from wireless.models import WirelessLAN
  31. from .nested_serializers import *
  32. class CabledObjectSerializer(serializers.ModelSerializer):
  33. cable = NestedCableSerializer(read_only=True, allow_null=True)
  34. cable_end = serializers.CharField(read_only=True)
  35. link_peers_type = serializers.SerializerMethodField(read_only=True)
  36. link_peers = serializers.SerializerMethodField(read_only=True)
  37. _occupied = serializers.SerializerMethodField(read_only=True)
  38. @extend_schema_field(OpenApiTypes.STR)
  39. def get_link_peers_type(self, obj):
  40. """
  41. Return the type of the peer link terminations, or None.
  42. """
  43. if not obj.cable:
  44. return None
  45. if obj.link_peers:
  46. return f'{obj.link_peers[0]._meta.app_label}.{obj.link_peers[0]._meta.model_name}'
  47. return None
  48. @extend_schema_field(serializers.ListField)
  49. def get_link_peers(self, obj):
  50. """
  51. Return the appropriate serializer for the link termination model.
  52. """
  53. if not obj.link_peers:
  54. return []
  55. # Return serialized peer termination objects
  56. serializer = get_serializer_for_model(obj.link_peers[0], prefix=NESTED_SERIALIZER_PREFIX)
  57. context = {'request': self.context['request']}
  58. return serializer(obj.link_peers, context=context, many=True).data
  59. @extend_schema_field(serializers.BooleanField)
  60. def get__occupied(self, obj):
  61. return obj._occupied
  62. class ConnectedEndpointsSerializer(serializers.ModelSerializer):
  63. """
  64. Legacy serializer for pre-v3.3 connections
  65. """
  66. connected_endpoints_type = serializers.SerializerMethodField(read_only=True)
  67. connected_endpoints = serializers.SerializerMethodField(read_only=True)
  68. connected_endpoints_reachable = serializers.SerializerMethodField(read_only=True)
  69. @extend_schema_field(OpenApiTypes.STR)
  70. def get_connected_endpoints_type(self, obj):
  71. if endpoints := obj.connected_endpoints:
  72. return f'{endpoints[0]._meta.app_label}.{endpoints[0]._meta.model_name}'
  73. @extend_schema_field(serializers.ListField)
  74. def get_connected_endpoints(self, obj):
  75. """
  76. Return the appropriate serializer for the type of connected object.
  77. """
  78. if endpoints := obj.connected_endpoints:
  79. serializer = get_serializer_for_model(endpoints[0], prefix=NESTED_SERIALIZER_PREFIX)
  80. context = {'request': self.context['request']}
  81. return serializer(endpoints, many=True, context=context).data
  82. @extend_schema_field(serializers.BooleanField)
  83. def get_connected_endpoints_reachable(self, obj):
  84. return obj._path and obj._path.is_complete and obj._path.is_active
  85. #
  86. # Regions/sites
  87. #
  88. class RegionSerializer(NestedGroupModelSerializer):
  89. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:region-detail')
  90. parent = NestedRegionSerializer(required=False, allow_null=True, default=None)
  91. site_count = serializers.IntegerField(read_only=True)
  92. class Meta:
  93. model = Region
  94. fields = [
  95. 'id', 'url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'created',
  96. 'last_updated', 'site_count', '_depth',
  97. ]
  98. class SiteGroupSerializer(NestedGroupModelSerializer):
  99. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:sitegroup-detail')
  100. parent = NestedSiteGroupSerializer(required=False, allow_null=True, default=None)
  101. site_count = serializers.IntegerField(read_only=True)
  102. class Meta:
  103. model = SiteGroup
  104. fields = [
  105. 'id', 'url', 'display', 'name', 'slug', 'parent', 'description', 'tags', 'custom_fields', 'created',
  106. 'last_updated', 'site_count', '_depth',
  107. ]
  108. class SiteSerializer(NetBoxModelSerializer):
  109. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:site-detail')
  110. status = ChoiceField(choices=SiteStatusChoices, required=False)
  111. region = NestedRegionSerializer(required=False, allow_null=True)
  112. group = NestedSiteGroupSerializer(required=False, allow_null=True)
  113. tenant = NestedTenantSerializer(required=False, allow_null=True)
  114. time_zone = TimeZoneSerializerField(required=False, allow_null=True)
  115. asns = SerializedPKRelatedField(
  116. queryset=ASN.objects.all(),
  117. serializer=NestedASNSerializer,
  118. required=False,
  119. many=True
  120. )
  121. # Related object counts
  122. circuit_count = serializers.IntegerField(read_only=True)
  123. device_count = serializers.IntegerField(read_only=True)
  124. prefix_count = serializers.IntegerField(read_only=True)
  125. rack_count = serializers.IntegerField(read_only=True)
  126. virtualmachine_count = serializers.IntegerField(read_only=True)
  127. vlan_count = serializers.IntegerField(read_only=True)
  128. class Meta:
  129. model = Site
  130. fields = [
  131. 'id', 'url', 'display', 'name', 'slug', 'status', 'region', 'group', 'tenant', 'facility', 'time_zone',
  132. 'description', 'physical_address', 'shipping_address', 'latitude', 'longitude', 'comments', 'asns', 'tags',
  133. 'custom_fields', 'created', 'last_updated', 'circuit_count', 'device_count', 'prefix_count', 'rack_count',
  134. 'virtualmachine_count', 'vlan_count',
  135. ]
  136. #
  137. # Racks
  138. #
  139. class LocationSerializer(NestedGroupModelSerializer):
  140. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:location-detail')
  141. site = NestedSiteSerializer()
  142. parent = NestedLocationSerializer(required=False, allow_null=True)
  143. status = ChoiceField(choices=LocationStatusChoices, required=False)
  144. tenant = NestedTenantSerializer(required=False, allow_null=True)
  145. rack_count = serializers.IntegerField(read_only=True)
  146. device_count = serializers.IntegerField(read_only=True)
  147. class Meta:
  148. model = Location
  149. fields = [
  150. 'id', 'url', 'display', 'name', 'slug', 'site', 'parent', 'status', 'tenant', 'description', 'tags',
  151. 'custom_fields', 'created', 'last_updated', 'rack_count', 'device_count', '_depth',
  152. ]
  153. class RackRoleSerializer(NetBoxModelSerializer):
  154. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackrole-detail')
  155. rack_count = serializers.IntegerField(read_only=True)
  156. class Meta:
  157. model = RackRole
  158. fields = [
  159. 'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created',
  160. 'last_updated', 'rack_count',
  161. ]
  162. class RackSerializer(NetBoxModelSerializer):
  163. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rack-detail')
  164. site = NestedSiteSerializer()
  165. location = NestedLocationSerializer(required=False, allow_null=True, default=None)
  166. tenant = NestedTenantSerializer(required=False, allow_null=True)
  167. status = ChoiceField(choices=RackStatusChoices, required=False)
  168. role = NestedRackRoleSerializer(required=False, allow_null=True)
  169. type = ChoiceField(choices=RackTypeChoices, allow_blank=True, required=False, allow_null=True)
  170. facility_id = serializers.CharField(max_length=50, allow_blank=True, allow_null=True, label=_('Facility ID'),
  171. default=None)
  172. width = ChoiceField(choices=RackWidthChoices, required=False)
  173. outer_unit = ChoiceField(choices=RackDimensionUnitChoices, allow_blank=True, required=False, allow_null=True)
  174. weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
  175. device_count = serializers.IntegerField(read_only=True)
  176. powerfeed_count = serializers.IntegerField(read_only=True)
  177. class Meta:
  178. model = Rack
  179. fields = [
  180. 'id', 'url', 'display', 'name', 'facility_id', 'site', 'location', 'tenant', 'status', 'role', 'serial',
  181. 'asset_tag', 'type', 'width', 'u_height', 'starting_unit', 'weight', 'max_weight', 'weight_unit',
  182. 'desc_units', 'outer_width', 'outer_depth', 'outer_unit', 'mounting_depth', 'description', 'comments',
  183. 'tags', 'custom_fields', 'created', 'last_updated', 'device_count', 'powerfeed_count',
  184. ]
  185. class RackUnitSerializer(serializers.Serializer):
  186. """
  187. A rack unit is an abstraction formed by the set (rack, position, face); it does not exist as a row in the database.
  188. """
  189. id = serializers.DecimalField(
  190. max_digits=4,
  191. decimal_places=1,
  192. read_only=True
  193. )
  194. name = serializers.CharField(read_only=True)
  195. face = ChoiceField(choices=DeviceFaceChoices, read_only=True)
  196. device = NestedDeviceSerializer(read_only=True)
  197. occupied = serializers.BooleanField(read_only=True)
  198. display = serializers.SerializerMethodField(read_only=True)
  199. @extend_schema_field(OpenApiTypes.STR)
  200. def get_display(self, obj):
  201. return obj['name']
  202. class RackReservationSerializer(NetBoxModelSerializer):
  203. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rackreservation-detail')
  204. rack = NestedRackSerializer()
  205. user = NestedUserSerializer()
  206. tenant = NestedTenantSerializer(required=False, allow_null=True)
  207. class Meta:
  208. model = RackReservation
  209. fields = [
  210. 'id', 'url', 'display', 'rack', 'units', 'created', 'last_updated', 'user', 'tenant', 'description',
  211. 'comments', 'tags', 'custom_fields',
  212. ]
  213. class RackElevationDetailFilterSerializer(serializers.Serializer):
  214. q = serializers.CharField(
  215. required=False,
  216. default=None
  217. )
  218. face = serializers.ChoiceField(
  219. choices=DeviceFaceChoices,
  220. default=DeviceFaceChoices.FACE_FRONT
  221. )
  222. render = serializers.ChoiceField(
  223. choices=RackElevationDetailRenderChoices,
  224. default=RackElevationDetailRenderChoices.RENDER_JSON
  225. )
  226. unit_width = serializers.IntegerField(
  227. default=ConfigItem('RACK_ELEVATION_DEFAULT_UNIT_WIDTH')
  228. )
  229. unit_height = serializers.IntegerField(
  230. default=ConfigItem('RACK_ELEVATION_DEFAULT_UNIT_HEIGHT')
  231. )
  232. legend_width = serializers.IntegerField(
  233. default=RACK_ELEVATION_DEFAULT_LEGEND_WIDTH
  234. )
  235. margin_width = serializers.IntegerField(
  236. default=RACK_ELEVATION_DEFAULT_MARGIN_WIDTH
  237. )
  238. exclude = serializers.IntegerField(
  239. required=False,
  240. default=None
  241. )
  242. expand_devices = serializers.BooleanField(
  243. required=False,
  244. default=True
  245. )
  246. include_images = serializers.BooleanField(
  247. required=False,
  248. default=True
  249. )
  250. #
  251. # Device/module types
  252. #
  253. class ManufacturerSerializer(NetBoxModelSerializer):
  254. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:manufacturer-detail')
  255. devicetype_count = serializers.IntegerField(read_only=True)
  256. inventoryitem_count = serializers.IntegerField(read_only=True)
  257. platform_count = serializers.IntegerField(read_only=True)
  258. class Meta:
  259. model = Manufacturer
  260. fields = [
  261. 'id', 'url', 'display', 'name', 'slug', 'description', 'tags', 'custom_fields', 'created', 'last_updated',
  262. 'devicetype_count', 'inventoryitem_count', 'platform_count',
  263. ]
  264. class DeviceTypeSerializer(NetBoxModelSerializer):
  265. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicetype-detail')
  266. manufacturer = NestedManufacturerSerializer()
  267. default_platform = NestedPlatformSerializer(required=False, allow_null=True)
  268. u_height = serializers.DecimalField(
  269. max_digits=4,
  270. decimal_places=1,
  271. label=_('Position (U)'),
  272. min_value=0,
  273. default=1.0
  274. )
  275. subdevice_role = ChoiceField(choices=SubdeviceRoleChoices, allow_blank=True, required=False, allow_null=True)
  276. airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False, allow_null=True)
  277. weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
  278. device_count = serializers.IntegerField(read_only=True)
  279. front_image = serializers.URLField(allow_null=True, required=False)
  280. rear_image = serializers.URLField(allow_null=True, required=False)
  281. # Counter fields
  282. console_port_template_count = serializers.IntegerField(read_only=True)
  283. console_server_port_template_count = serializers.IntegerField(read_only=True)
  284. power_port_template_count = serializers.IntegerField(read_only=True)
  285. power_outlet_template_count = serializers.IntegerField(read_only=True)
  286. interface_template_count = serializers.IntegerField(read_only=True)
  287. front_port_template_count = serializers.IntegerField(read_only=True)
  288. rear_port_template_count = serializers.IntegerField(read_only=True)
  289. device_bay_template_count = serializers.IntegerField(read_only=True)
  290. module_bay_template_count = serializers.IntegerField(read_only=True)
  291. inventory_item_template_count = serializers.IntegerField(read_only=True)
  292. class Meta:
  293. model = DeviceType
  294. fields = [
  295. 'id', 'url', 'display', 'manufacturer', 'default_platform', 'model', 'slug', 'part_number', 'u_height',
  296. 'exclude_from_utilization', 'is_full_depth', 'subdevice_role', 'airflow', 'weight', 'weight_unit',
  297. 'front_image', 'rear_image', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  298. 'device_count', 'console_port_template_count', 'console_server_port_template_count', 'power_port_template_count',
  299. 'power_outlet_template_count', 'interface_template_count', 'front_port_template_count',
  300. 'rear_port_template_count', 'device_bay_template_count', 'module_bay_template_count',
  301. 'inventory_item_template_count',
  302. ]
  303. class ModuleTypeSerializer(NetBoxModelSerializer):
  304. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:moduletype-detail')
  305. manufacturer = NestedManufacturerSerializer()
  306. weight_unit = ChoiceField(choices=WeightUnitChoices, allow_blank=True, required=False, allow_null=True)
  307. class Meta:
  308. model = ModuleType
  309. fields = [
  310. 'id', 'url', 'display', 'manufacturer', 'model', 'part_number', 'weight', 'weight_unit', 'description',
  311. 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  312. ]
  313. #
  314. # Component templates
  315. #
  316. class ConsolePortTemplateSerializer(ValidatedModelSerializer):
  317. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleporttemplate-detail')
  318. device_type = NestedDeviceTypeSerializer(
  319. required=False,
  320. allow_null=True,
  321. default=None
  322. )
  323. module_type = NestedModuleTypeSerializer(
  324. required=False,
  325. allow_null=True,
  326. default=None
  327. )
  328. type = ChoiceField(
  329. choices=ConsolePortTypeChoices,
  330. allow_blank=True,
  331. required=False
  332. )
  333. class Meta:
  334. model = ConsolePortTemplate
  335. fields = [
  336. 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'description', 'created',
  337. 'last_updated',
  338. ]
  339. class ConsoleServerPortTemplateSerializer(ValidatedModelSerializer):
  340. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverporttemplate-detail')
  341. device_type = NestedDeviceTypeSerializer(
  342. required=False,
  343. allow_null=True,
  344. default=None
  345. )
  346. module_type = NestedModuleTypeSerializer(
  347. required=False,
  348. allow_null=True,
  349. default=None
  350. )
  351. type = ChoiceField(
  352. choices=ConsolePortTypeChoices,
  353. allow_blank=True,
  354. required=False
  355. )
  356. class Meta:
  357. model = ConsoleServerPortTemplate
  358. fields = [
  359. 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'description', 'created',
  360. 'last_updated',
  361. ]
  362. class PowerPortTemplateSerializer(ValidatedModelSerializer):
  363. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerporttemplate-detail')
  364. device_type = NestedDeviceTypeSerializer(
  365. required=False,
  366. allow_null=True,
  367. default=None
  368. )
  369. module_type = NestedModuleTypeSerializer(
  370. required=False,
  371. allow_null=True,
  372. default=None
  373. )
  374. type = ChoiceField(
  375. choices=PowerPortTypeChoices,
  376. allow_blank=True,
  377. required=False,
  378. allow_null=True
  379. )
  380. class Meta:
  381. model = PowerPortTemplate
  382. fields = [
  383. 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'maximum_draw',
  384. 'allocated_draw', 'description', 'created', 'last_updated',
  385. ]
  386. class PowerOutletTemplateSerializer(ValidatedModelSerializer):
  387. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlettemplate-detail')
  388. device_type = NestedDeviceTypeSerializer(
  389. required=False,
  390. allow_null=True,
  391. default=None
  392. )
  393. module_type = NestedModuleTypeSerializer(
  394. required=False,
  395. allow_null=True,
  396. default=None
  397. )
  398. type = ChoiceField(
  399. choices=PowerOutletTypeChoices,
  400. allow_blank=True,
  401. required=False,
  402. allow_null=True
  403. )
  404. power_port = NestedPowerPortTemplateSerializer(
  405. required=False,
  406. allow_null=True
  407. )
  408. feed_leg = ChoiceField(
  409. choices=PowerOutletFeedLegChoices,
  410. allow_blank=True,
  411. required=False,
  412. allow_null=True
  413. )
  414. class Meta:
  415. model = PowerOutletTemplate
  416. fields = [
  417. 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'power_port', 'feed_leg',
  418. 'description', 'created', 'last_updated',
  419. ]
  420. class InterfaceTemplateSerializer(ValidatedModelSerializer):
  421. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interfacetemplate-detail')
  422. device_type = NestedDeviceTypeSerializer(
  423. required=False,
  424. allow_null=True,
  425. default=None
  426. )
  427. module_type = NestedModuleTypeSerializer(
  428. required=False,
  429. allow_null=True,
  430. default=None
  431. )
  432. type = ChoiceField(choices=InterfaceTypeChoices)
  433. bridge = NestedInterfaceTemplateSerializer(
  434. required=False,
  435. allow_null=True
  436. )
  437. poe_mode = ChoiceField(
  438. choices=InterfacePoEModeChoices,
  439. required=False,
  440. allow_blank=True,
  441. allow_null=True
  442. )
  443. poe_type = ChoiceField(
  444. choices=InterfacePoETypeChoices,
  445. required=False,
  446. allow_blank=True,
  447. allow_null=True
  448. )
  449. rf_role = ChoiceField(
  450. choices=WirelessRoleChoices,
  451. required=False,
  452. allow_blank=True,
  453. allow_null=True
  454. )
  455. class Meta:
  456. model = InterfaceTemplate
  457. fields = [
  458. 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'enabled', 'mgmt_only',
  459. 'description', 'bridge', 'poe_mode', 'poe_type', 'rf_role', 'created', 'last_updated',
  460. ]
  461. class RearPortTemplateSerializer(ValidatedModelSerializer):
  462. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearporttemplate-detail')
  463. device_type = NestedDeviceTypeSerializer(
  464. required=False,
  465. allow_null=True,
  466. default=None
  467. )
  468. module_type = NestedModuleTypeSerializer(
  469. required=False,
  470. allow_null=True,
  471. default=None
  472. )
  473. type = ChoiceField(choices=PortTypeChoices)
  474. class Meta:
  475. model = RearPortTemplate
  476. fields = [
  477. 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'color', 'positions',
  478. 'description', 'created', 'last_updated',
  479. ]
  480. class FrontPortTemplateSerializer(ValidatedModelSerializer):
  481. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontporttemplate-detail')
  482. device_type = NestedDeviceTypeSerializer(
  483. required=False,
  484. allow_null=True,
  485. default=None
  486. )
  487. module_type = NestedModuleTypeSerializer(
  488. required=False,
  489. allow_null=True,
  490. default=None
  491. )
  492. type = ChoiceField(choices=PortTypeChoices)
  493. rear_port = NestedRearPortTemplateSerializer()
  494. class Meta:
  495. model = FrontPortTemplate
  496. fields = [
  497. 'id', 'url', 'display', 'device_type', 'module_type', 'name', 'label', 'type', 'color', 'rear_port',
  498. 'rear_port_position', 'description', 'created', 'last_updated',
  499. ]
  500. class ModuleBayTemplateSerializer(ValidatedModelSerializer):
  501. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebaytemplate-detail')
  502. device_type = NestedDeviceTypeSerializer()
  503. class Meta:
  504. model = ModuleBayTemplate
  505. fields = [
  506. 'id', 'url', 'display', 'device_type', 'name', 'label', 'position', 'description', 'created',
  507. 'last_updated',
  508. ]
  509. class DeviceBayTemplateSerializer(ValidatedModelSerializer):
  510. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebaytemplate-detail')
  511. device_type = NestedDeviceTypeSerializer()
  512. class Meta:
  513. model = DeviceBayTemplate
  514. fields = ['id', 'url', 'display', 'device_type', 'name', 'label', 'description', 'created', 'last_updated']
  515. class InventoryItemTemplateSerializer(ValidatedModelSerializer):
  516. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemtemplate-detail')
  517. device_type = NestedDeviceTypeSerializer()
  518. parent = serializers.PrimaryKeyRelatedField(
  519. queryset=InventoryItemTemplate.objects.all(),
  520. allow_null=True,
  521. default=None
  522. )
  523. role = NestedInventoryItemRoleSerializer(required=False, allow_null=True)
  524. manufacturer = NestedManufacturerSerializer(required=False, allow_null=True, default=None)
  525. component_type = ContentTypeField(
  526. queryset=ContentType.objects.filter(MODULAR_COMPONENT_TEMPLATE_MODELS),
  527. required=False,
  528. allow_null=True
  529. )
  530. component = serializers.SerializerMethodField(read_only=True)
  531. _depth = serializers.IntegerField(source='level', read_only=True)
  532. class Meta:
  533. model = InventoryItemTemplate
  534. fields = [
  535. 'id', 'url', 'display', 'device_type', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id',
  536. 'description', 'component_type', 'component_id', 'component', 'created', 'last_updated', '_depth',
  537. ]
  538. @extend_schema_field(serializers.JSONField(allow_null=True))
  539. def get_component(self, obj):
  540. if obj.component is None:
  541. return None
  542. serializer = get_serializer_for_model(obj.component, prefix=NESTED_SERIALIZER_PREFIX)
  543. context = {'request': self.context['request']}
  544. return serializer(obj.component, context=context).data
  545. #
  546. # Devices
  547. #
  548. class DeviceRoleSerializer(NetBoxModelSerializer):
  549. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicerole-detail')
  550. config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
  551. device_count = serializers.IntegerField(read_only=True)
  552. virtualmachine_count = serializers.IntegerField(read_only=True)
  553. class Meta:
  554. model = DeviceRole
  555. fields = [
  556. 'id', 'url', 'display', 'name', 'slug', 'color', 'vm_role', 'config_template', 'description', 'tags',
  557. 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
  558. ]
  559. class PlatformSerializer(NetBoxModelSerializer):
  560. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:platform-detail')
  561. manufacturer = NestedManufacturerSerializer(required=False, allow_null=True)
  562. config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
  563. device_count = serializers.IntegerField(read_only=True)
  564. virtualmachine_count = serializers.IntegerField(read_only=True)
  565. class Meta:
  566. model = Platform
  567. fields = [
  568. 'id', 'url', 'display', 'name', 'slug', 'manufacturer', 'config_template', 'description', 'tags',
  569. 'custom_fields', 'created', 'last_updated', 'device_count', 'virtualmachine_count',
  570. ]
  571. class DeviceSerializer(NetBoxModelSerializer):
  572. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:device-detail')
  573. device_type = NestedDeviceTypeSerializer()
  574. role = NestedDeviceRoleSerializer()
  575. device_role = NestedDeviceRoleSerializer(read_only=True, help_text='Deprecated in v3.6 in favor of `role`.')
  576. tenant = NestedTenantSerializer(required=False, allow_null=True, default=None)
  577. platform = NestedPlatformSerializer(required=False, allow_null=True)
  578. site = NestedSiteSerializer()
  579. location = NestedLocationSerializer(required=False, allow_null=True, default=None)
  580. rack = NestedRackSerializer(required=False, allow_null=True, default=None)
  581. face = ChoiceField(choices=DeviceFaceChoices, allow_blank=True, default=lambda: '')
  582. position = serializers.DecimalField(
  583. max_digits=4,
  584. decimal_places=1,
  585. allow_null=True,
  586. label=_('Position (U)'),
  587. min_value=decimal.Decimal(0.5),
  588. default=None
  589. )
  590. status = ChoiceField(choices=DeviceStatusChoices, required=False)
  591. airflow = ChoiceField(choices=DeviceAirflowChoices, allow_blank=True, required=False)
  592. primary_ip = NestedIPAddressSerializer(read_only=True)
  593. primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
  594. primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
  595. oob_ip = NestedIPAddressSerializer(required=False, allow_null=True)
  596. parent_device = serializers.SerializerMethodField()
  597. cluster = NestedClusterSerializer(required=False, allow_null=True)
  598. virtual_chassis = NestedVirtualChassisSerializer(required=False, allow_null=True, default=None)
  599. vc_position = serializers.IntegerField(allow_null=True, max_value=255, min_value=0, default=None)
  600. config_template = NestedConfigTemplateSerializer(required=False, allow_null=True, default=None)
  601. # Counter fields
  602. console_port_count = serializers.IntegerField(read_only=True)
  603. console_server_port_count = serializers.IntegerField(read_only=True)
  604. power_port_count = serializers.IntegerField(read_only=True)
  605. power_outlet_count = serializers.IntegerField(read_only=True)
  606. interface_count = serializers.IntegerField(read_only=True)
  607. front_port_count = serializers.IntegerField(read_only=True)
  608. rear_port_count = serializers.IntegerField(read_only=True)
  609. device_bay_count = serializers.IntegerField(read_only=True)
  610. module_bay_count = serializers.IntegerField(read_only=True)
  611. inventory_item_count = serializers.IntegerField(read_only=True)
  612. class Meta:
  613. model = Device
  614. fields = [
  615. 'id', 'url', 'display', 'name', 'device_type', 'role', 'device_role', 'tenant', 'platform', 'serial',
  616. 'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device',
  617. 'status', 'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis',
  618. 'vc_position', 'vc_priority', 'description', 'comments', 'config_template', 'local_context_data', 'tags',
  619. 'custom_fields', 'created', 'last_updated', 'console_port_count', 'console_server_port_count',
  620. 'power_port_count', 'power_outlet_count', 'interface_count', 'front_port_count', 'rear_port_count',
  621. 'device_bay_count', 'module_bay_count', 'inventory_item_count',
  622. ]
  623. @extend_schema_field(NestedDeviceSerializer)
  624. def get_parent_device(self, obj):
  625. try:
  626. device_bay = obj.parent_bay
  627. except DeviceBay.DoesNotExist:
  628. return None
  629. context = {'request': self.context['request']}
  630. data = NestedDeviceSerializer(instance=device_bay.device, context=context).data
  631. data['device_bay'] = NestedDeviceBaySerializer(instance=device_bay, context=context).data
  632. return data
  633. def get_device_role(self, obj):
  634. return obj.role
  635. class DeviceWithConfigContextSerializer(DeviceSerializer):
  636. config_context = serializers.SerializerMethodField(read_only=True)
  637. class Meta(DeviceSerializer.Meta):
  638. fields = [
  639. 'id', 'url', 'display', 'name', 'device_type', 'role', 'device_role', 'tenant', 'platform', 'serial',
  640. 'asset_tag', 'site', 'location', 'rack', 'position', 'face', 'latitude', 'longitude', 'parent_device',
  641. 'status', 'airflow', 'primary_ip', 'primary_ip4', 'primary_ip6', 'oob_ip', 'cluster', 'virtual_chassis',
  642. 'vc_position', 'vc_priority', 'description', 'comments', 'config_template', 'config_context',
  643. 'local_context_data', 'tags', 'custom_fields', 'created', 'last_updated', 'console_port_count',
  644. 'console_server_port_count', 'power_port_count', 'power_outlet_count', 'interface_count',
  645. 'front_port_count', 'rear_port_count', 'device_bay_count', 'module_bay_count', 'inventory_item_count',
  646. ]
  647. @extend_schema_field(serializers.JSONField(allow_null=True))
  648. def get_config_context(self, obj):
  649. return obj.get_config_context()
  650. class VirtualDeviceContextSerializer(NetBoxModelSerializer):
  651. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualdevicecontext-detail')
  652. device = NestedDeviceSerializer()
  653. tenant = NestedTenantSerializer(required=False, allow_null=True, default=None)
  654. primary_ip = NestedIPAddressSerializer(read_only=True, allow_null=True)
  655. primary_ip4 = NestedIPAddressSerializer(required=False, allow_null=True)
  656. primary_ip6 = NestedIPAddressSerializer(required=False, allow_null=True)
  657. status = ChoiceField(choices=VirtualDeviceContextStatusChoices)
  658. # Related object counts
  659. interface_count = serializers.IntegerField(read_only=True)
  660. class Meta:
  661. model = VirtualDeviceContext
  662. fields = [
  663. 'id', 'url', 'display', 'name', 'device', 'identifier', 'tenant', 'primary_ip', 'primary_ip4',
  664. 'primary_ip6', 'status', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  665. 'interface_count',
  666. ]
  667. class ModuleSerializer(NetBoxModelSerializer):
  668. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:module-detail')
  669. device = NestedDeviceSerializer()
  670. module_bay = NestedModuleBaySerializer()
  671. module_type = NestedModuleTypeSerializer()
  672. status = ChoiceField(choices=ModuleStatusChoices, required=False)
  673. class Meta:
  674. model = Module
  675. fields = [
  676. 'id', 'url', 'display', 'device', 'module_bay', 'module_type', 'status', 'serial', 'asset_tag',
  677. 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  678. ]
  679. #
  680. # Device components
  681. #
  682. class ConsoleServerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
  683. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleserverport-detail')
  684. device = NestedDeviceSerializer()
  685. module = ComponentNestedModuleSerializer(
  686. required=False,
  687. allow_null=True
  688. )
  689. type = ChoiceField(
  690. choices=ConsolePortTypeChoices,
  691. allow_blank=True,
  692. required=False
  693. )
  694. speed = ChoiceField(
  695. choices=ConsolePortSpeedChoices,
  696. allow_null=True,
  697. required=False
  698. )
  699. class Meta:
  700. model = ConsoleServerPort
  701. fields = [
  702. 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
  703. 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints',
  704. 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
  705. 'last_updated', '_occupied',
  706. ]
  707. class ConsolePortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
  708. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:consoleport-detail')
  709. device = NestedDeviceSerializer()
  710. module = ComponentNestedModuleSerializer(
  711. required=False,
  712. allow_null=True
  713. )
  714. type = ChoiceField(
  715. choices=ConsolePortTypeChoices,
  716. allow_blank=True,
  717. required=False
  718. )
  719. speed = ChoiceField(
  720. choices=ConsolePortSpeedChoices,
  721. allow_null=True,
  722. required=False
  723. )
  724. class Meta:
  725. model = ConsolePort
  726. fields = [
  727. 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'speed', 'description',
  728. 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'connected_endpoints',
  729. 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
  730. 'last_updated', '_occupied',
  731. ]
  732. class PowerOutletSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
  733. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:poweroutlet-detail')
  734. device = NestedDeviceSerializer()
  735. module = ComponentNestedModuleSerializer(
  736. required=False,
  737. allow_null=True
  738. )
  739. type = ChoiceField(
  740. choices=PowerOutletTypeChoices,
  741. allow_blank=True,
  742. required=False,
  743. allow_null=True
  744. )
  745. power_port = NestedPowerPortSerializer(
  746. required=False,
  747. allow_null=True
  748. )
  749. feed_leg = ChoiceField(
  750. choices=PowerOutletFeedLegChoices,
  751. allow_blank=True,
  752. required=False,
  753. allow_null=True
  754. )
  755. class Meta:
  756. model = PowerOutlet
  757. fields = [
  758. 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'power_port', 'feed_leg',
  759. 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
  760. 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields',
  761. 'created', 'last_updated', '_occupied',
  762. ]
  763. class PowerPortSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
  764. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerport-detail')
  765. device = NestedDeviceSerializer()
  766. module = ComponentNestedModuleSerializer(
  767. required=False,
  768. allow_null=True
  769. )
  770. type = ChoiceField(
  771. choices=PowerPortTypeChoices,
  772. allow_blank=True,
  773. required=False,
  774. allow_null=True
  775. )
  776. class Meta:
  777. model = PowerPort
  778. fields = [
  779. 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'maximum_draw', 'allocated_draw',
  780. 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
  781. 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields',
  782. 'created', 'last_updated', '_occupied',
  783. ]
  784. class InterfaceSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
  785. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:interface-detail')
  786. device = NestedDeviceSerializer()
  787. vdcs = SerializedPKRelatedField(
  788. queryset=VirtualDeviceContext.objects.all(),
  789. serializer=NestedVirtualDeviceContextSerializer,
  790. required=False,
  791. many=True
  792. )
  793. module = ComponentNestedModuleSerializer(
  794. required=False,
  795. allow_null=True
  796. )
  797. type = ChoiceField(choices=InterfaceTypeChoices)
  798. parent = NestedInterfaceSerializer(required=False, allow_null=True)
  799. bridge = NestedInterfaceSerializer(required=False, allow_null=True)
  800. lag = NestedInterfaceSerializer(required=False, allow_null=True)
  801. mode = ChoiceField(choices=InterfaceModeChoices, required=False, allow_blank=True)
  802. duplex = ChoiceField(choices=InterfaceDuplexChoices, required=False, allow_blank=True, allow_null=True)
  803. rf_role = ChoiceField(choices=WirelessRoleChoices, required=False, allow_blank=True)
  804. rf_channel = ChoiceField(choices=WirelessChannelChoices, required=False, allow_blank=True)
  805. poe_mode = ChoiceField(choices=InterfacePoEModeChoices, required=False, allow_blank=True)
  806. poe_type = ChoiceField(choices=InterfacePoETypeChoices, required=False, allow_blank=True)
  807. untagged_vlan = NestedVLANSerializer(required=False, allow_null=True)
  808. tagged_vlans = SerializedPKRelatedField(
  809. queryset=VLAN.objects.all(),
  810. serializer=NestedVLANSerializer,
  811. required=False,
  812. many=True
  813. )
  814. vrf = NestedVRFSerializer(required=False, allow_null=True)
  815. l2vpn_termination = NestedL2VPNTerminationSerializer(read_only=True, allow_null=True)
  816. wireless_link = NestedWirelessLinkSerializer(read_only=True, allow_null=True)
  817. wireless_lans = SerializedPKRelatedField(
  818. queryset=WirelessLAN.objects.all(),
  819. serializer=NestedWirelessLANSerializer,
  820. required=False,
  821. many=True
  822. )
  823. count_ipaddresses = serializers.IntegerField(read_only=True)
  824. count_fhrp_groups = serializers.IntegerField(read_only=True)
  825. mac_address = serializers.CharField(
  826. required=False,
  827. default=None,
  828. allow_blank=True,
  829. allow_null=True
  830. )
  831. wwn = serializers.CharField(required=False, default=None, allow_blank=True, allow_null=True)
  832. class Meta:
  833. model = Interface
  834. fields = [
  835. 'id', 'url', 'display', 'device', 'vdcs', 'module', 'name', 'label', 'type', 'enabled', 'parent', 'bridge',
  836. 'lag', 'mtu', 'mac_address', 'speed', 'duplex', 'wwn', 'mgmt_only', 'description', 'mode', 'rf_role',
  837. 'rf_channel', 'poe_mode', 'poe_type', 'rf_channel_frequency', 'rf_channel_width', 'tx_power',
  838. 'untagged_vlan', 'tagged_vlans', 'mark_connected', 'cable', 'cable_end', 'wireless_link', 'link_peers',
  839. 'link_peers_type', 'wireless_lans', 'vrf', 'l2vpn_termination', 'connected_endpoints',
  840. 'connected_endpoints_type', 'connected_endpoints_reachable', 'tags', 'custom_fields', 'created',
  841. 'last_updated', 'count_ipaddresses', 'count_fhrp_groups', '_occupied',
  842. ]
  843. def validate(self, data):
  844. # Validate many-to-many VLAN assignments
  845. device = self.instance.device if self.instance else data.get('device')
  846. for vlan in data.get('tagged_vlans', []):
  847. if vlan.site not in [device.site, None]:
  848. raise serializers.ValidationError({
  849. 'tagged_vlans': f"VLAN {vlan} must belong to the same site as the interface's parent device, or "
  850. f"it must be global."
  851. })
  852. return super().validate(data)
  853. class RearPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
  854. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
  855. device = NestedDeviceSerializer()
  856. module = ComponentNestedModuleSerializer(
  857. required=False,
  858. allow_null=True
  859. )
  860. type = ChoiceField(choices=PortTypeChoices)
  861. class Meta:
  862. model = RearPort
  863. fields = [
  864. 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'positions', 'description',
  865. 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type', 'tags', 'custom_fields', 'created',
  866. 'last_updated', '_occupied',
  867. ]
  868. class FrontPortRearPortSerializer(WritableNestedSerializer):
  869. """
  870. NestedRearPortSerializer but with parent device omitted (since front and rear ports must belong to same device)
  871. """
  872. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:rearport-detail')
  873. class Meta:
  874. model = RearPort
  875. fields = ['id', 'url', 'display', 'name', 'label', 'description']
  876. class FrontPortSerializer(NetBoxModelSerializer, CabledObjectSerializer):
  877. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:frontport-detail')
  878. device = NestedDeviceSerializer()
  879. module = ComponentNestedModuleSerializer(
  880. required=False,
  881. allow_null=True
  882. )
  883. type = ChoiceField(choices=PortTypeChoices)
  884. rear_port = FrontPortRearPortSerializer()
  885. class Meta:
  886. model = FrontPort
  887. fields = [
  888. 'id', 'url', 'display', 'device', 'module', 'name', 'label', 'type', 'color', 'rear_port',
  889. 'rear_port_position', 'description', 'mark_connected', 'cable', 'cable_end', 'link_peers',
  890. 'link_peers_type', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
  891. ]
  892. class ModuleBaySerializer(NetBoxModelSerializer):
  893. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:modulebay-detail')
  894. device = NestedDeviceSerializer()
  895. installed_module = ModuleBayNestedModuleSerializer(required=False, allow_null=True)
  896. class Meta:
  897. model = ModuleBay
  898. fields = [
  899. 'id', 'url', 'display', 'device', 'name', 'installed_module', 'label', 'position', 'description', 'tags',
  900. 'custom_fields',
  901. 'created', 'last_updated',
  902. ]
  903. class DeviceBaySerializer(NetBoxModelSerializer):
  904. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:devicebay-detail')
  905. device = NestedDeviceSerializer()
  906. installed_device = NestedDeviceSerializer(required=False, allow_null=True)
  907. class Meta:
  908. model = DeviceBay
  909. fields = [
  910. 'id', 'url', 'display', 'device', 'name', 'label', 'description', 'installed_device', 'tags',
  911. 'custom_fields', 'created', 'last_updated',
  912. ]
  913. class InventoryItemSerializer(NetBoxModelSerializer):
  914. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitem-detail')
  915. device = NestedDeviceSerializer()
  916. parent = serializers.PrimaryKeyRelatedField(queryset=InventoryItem.objects.all(), allow_null=True, default=None)
  917. role = NestedInventoryItemRoleSerializer(required=False, allow_null=True)
  918. manufacturer = NestedManufacturerSerializer(required=False, allow_null=True, default=None)
  919. component_type = ContentTypeField(
  920. queryset=ContentType.objects.filter(MODULAR_COMPONENT_MODELS),
  921. required=False,
  922. allow_null=True
  923. )
  924. component = serializers.SerializerMethodField(read_only=True)
  925. _depth = serializers.IntegerField(source='level', read_only=True)
  926. class Meta:
  927. model = InventoryItem
  928. fields = [
  929. 'id', 'url', 'display', 'device', 'parent', 'name', 'label', 'role', 'manufacturer', 'part_id', 'serial',
  930. 'asset_tag', 'discovered', 'description', 'component_type', 'component_id', 'component', 'tags',
  931. 'custom_fields', 'created', 'last_updated', '_depth',
  932. ]
  933. @extend_schema_field(serializers.JSONField(allow_null=True))
  934. def get_component(self, obj):
  935. if obj.component is None:
  936. return None
  937. serializer = get_serializer_for_model(obj.component, prefix=NESTED_SERIALIZER_PREFIX)
  938. context = {'request': self.context['request']}
  939. return serializer(obj.component, context=context).data
  940. #
  941. # Device component roles
  942. #
  943. class InventoryItemRoleSerializer(NetBoxModelSerializer):
  944. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:inventoryitemrole-detail')
  945. inventoryitem_count = serializers.IntegerField(read_only=True)
  946. class Meta:
  947. model = InventoryItemRole
  948. fields = [
  949. 'id', 'url', 'display', 'name', 'slug', 'color', 'description', 'tags', 'custom_fields', 'created',
  950. 'last_updated', 'inventoryitem_count',
  951. ]
  952. #
  953. # Cables
  954. #
  955. class CableSerializer(NetBoxModelSerializer):
  956. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
  957. a_terminations = GenericObjectSerializer(many=True, required=False)
  958. b_terminations = GenericObjectSerializer(many=True, required=False)
  959. status = ChoiceField(choices=LinkStatusChoices, required=False)
  960. tenant = NestedTenantSerializer(required=False, allow_null=True)
  961. length_unit = ChoiceField(choices=CableLengthUnitChoices, allow_blank=True, required=False, allow_null=True)
  962. class Meta:
  963. model = Cable
  964. fields = [
  965. 'id', 'url', 'display', 'type', 'a_terminations', 'b_terminations', 'status', 'tenant', 'label', 'color',
  966. 'length', 'length_unit', 'description', 'comments', 'tags', 'custom_fields', 'created', 'last_updated',
  967. ]
  968. class TracedCableSerializer(serializers.ModelSerializer):
  969. """
  970. Used only while tracing a cable path.
  971. """
  972. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cable-detail')
  973. class Meta:
  974. model = Cable
  975. fields = [
  976. 'id', 'url', 'type', 'status', 'label', 'color', 'length', 'length_unit', 'description',
  977. ]
  978. class CableTerminationSerializer(NetBoxModelSerializer):
  979. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:cabletermination-detail')
  980. termination_type = ContentTypeField(
  981. queryset=ContentType.objects.filter(CABLE_TERMINATION_MODELS)
  982. )
  983. termination = serializers.SerializerMethodField(read_only=True)
  984. class Meta:
  985. model = CableTermination
  986. fields = [
  987. 'id', 'url', 'display', 'cable', 'cable_end', 'termination_type', 'termination_id', 'termination',
  988. 'created', 'last_updated',
  989. ]
  990. @extend_schema_field(serializers.JSONField(allow_null=True))
  991. def get_termination(self, obj):
  992. serializer = get_serializer_for_model(obj.termination, prefix=NESTED_SERIALIZER_PREFIX)
  993. context = {'request': self.context['request']}
  994. return serializer(obj.termination, context=context).data
  995. class CablePathSerializer(serializers.ModelSerializer):
  996. path = serializers.SerializerMethodField(read_only=True)
  997. class Meta:
  998. model = CablePath
  999. fields = ['id', 'path', 'is_active', 'is_complete', 'is_split']
  1000. @extend_schema_field(serializers.ListField)
  1001. def get_path(self, obj):
  1002. ret = []
  1003. for nodes in obj.path_objects:
  1004. serializer = get_serializer_for_model(nodes[0], prefix=NESTED_SERIALIZER_PREFIX)
  1005. context = {'request': self.context['request']}
  1006. ret.append(serializer(nodes, context=context, many=True).data)
  1007. return ret
  1008. #
  1009. # Virtual chassis
  1010. #
  1011. class VirtualChassisSerializer(NetBoxModelSerializer):
  1012. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:virtualchassis-detail')
  1013. master = NestedDeviceSerializer(required=False, allow_null=True, default=None)
  1014. # Counter fields
  1015. member_count = serializers.IntegerField(read_only=True)
  1016. class Meta:
  1017. model = VirtualChassis
  1018. fields = [
  1019. 'id', 'url', 'display', 'name', 'domain', 'master', 'description', 'comments', 'tags', 'custom_fields',
  1020. 'created', 'last_updated', 'member_count',
  1021. ]
  1022. #
  1023. # Power panels
  1024. #
  1025. class PowerPanelSerializer(NetBoxModelSerializer):
  1026. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerpanel-detail')
  1027. site = NestedSiteSerializer()
  1028. location = NestedLocationSerializer(
  1029. required=False,
  1030. allow_null=True,
  1031. default=None
  1032. )
  1033. powerfeed_count = serializers.IntegerField(read_only=True)
  1034. class Meta:
  1035. model = PowerPanel
  1036. fields = [
  1037. 'id', 'url', 'display', 'site', 'location', 'name', 'description', 'comments', 'tags', 'custom_fields',
  1038. 'powerfeed_count', 'created', 'last_updated',
  1039. ]
  1040. class PowerFeedSerializer(NetBoxModelSerializer, CabledObjectSerializer, ConnectedEndpointsSerializer):
  1041. url = serializers.HyperlinkedIdentityField(view_name='dcim-api:powerfeed-detail')
  1042. power_panel = NestedPowerPanelSerializer()
  1043. rack = NestedRackSerializer(
  1044. required=False,
  1045. allow_null=True,
  1046. default=None
  1047. )
  1048. type = ChoiceField(
  1049. choices=PowerFeedTypeChoices,
  1050. default=lambda: PowerFeedTypeChoices.TYPE_PRIMARY,
  1051. )
  1052. status = ChoiceField(
  1053. choices=PowerFeedStatusChoices,
  1054. default=lambda: PowerFeedStatusChoices.STATUS_ACTIVE,
  1055. )
  1056. supply = ChoiceField(
  1057. choices=PowerFeedSupplyChoices,
  1058. default=lambda: PowerFeedSupplyChoices.SUPPLY_AC,
  1059. )
  1060. phase = ChoiceField(
  1061. choices=PowerFeedPhaseChoices,
  1062. default=lambda: PowerFeedPhaseChoices.PHASE_SINGLE,
  1063. )
  1064. tenant = NestedTenantSerializer(
  1065. required=False,
  1066. allow_null=True
  1067. )
  1068. class Meta:
  1069. model = PowerFeed
  1070. fields = [
  1071. 'id', 'url', 'display', 'power_panel', 'rack', 'name', 'status', 'type', 'supply', 'phase', 'voltage',
  1072. 'amperage', 'max_utilization', 'mark_connected', 'cable', 'cable_end', 'link_peers', 'link_peers_type',
  1073. 'connected_endpoints', 'connected_endpoints_type', 'connected_endpoints_reachable', 'description',
  1074. 'tenant', 'comments', 'tags', 'custom_fields', 'created', 'last_updated', '_occupied',
  1075. ]