serializers.py 44 KB

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