serializers.py 44 KB

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