serializers.py 43 KB

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