serializers.py 43 KB

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