nautobot 2.0.0a2__py3-none-any.whl → 2.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1029) hide show
  1. nautobot/__init__.py +1 -5
  2. nautobot/apps/api.py +6 -8
  3. nautobot/apps/forms.py +0 -2
  4. nautobot/apps/ui.py +0 -8
  5. nautobot/circuits/api/serializers.py +9 -119
  6. nautobot/circuits/api/urls.py +1 -1
  7. nautobot/circuits/api/views.py +0 -1
  8. nautobot/circuits/choices.py +0 -2
  9. nautobot/circuits/filters.py +7 -6
  10. nautobot/circuits/forms.py +3 -73
  11. nautobot/circuits/migrations/0001_initial_part_1.py +0 -1
  12. nautobot/circuits/migrations/0002_initial_part_2.py +0 -1
  13. nautobot/circuits/migrations/0003_auto_slug.py +0 -1
  14. nautobot/circuits/migrations/0004_increase_provider_account_length.py +0 -1
  15. nautobot/circuits/migrations/0005_providernetwork.py +0 -1
  16. nautobot/circuits/migrations/0006_cache_circuit_terminations.py +0 -1
  17. nautobot/circuits/migrations/0007_circuitterminations_primary_model.py +0 -1
  18. nautobot/circuits/migrations/0008_add_natural_indexing.py +0 -1
  19. nautobot/circuits/migrations/0009_circuittermination_location.py +0 -1
  20. nautobot/circuits/migrations/0010_rename_foreign_keys_and_related_names.py +0 -1
  21. nautobot/circuits/migrations/0011_remove_site_foreign_key_from_circuit_termination_class.py +0 -1
  22. nautobot/circuits/migrations/0012_created_datetime.py +0 -1
  23. nautobot/circuits/migrations/0013_alter_circuittermination__path.py +0 -1
  24. nautobot/circuits/migrations/0014_related_name_changes.py +1 -2
  25. nautobot/circuits/migrations/0015_remove_circuittype_provider_slug.py +20 -0
  26. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  27. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  28. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  29. nautobot/circuits/models.py +3 -93
  30. nautobot/circuits/navigation.py +14 -69
  31. nautobot/circuits/signals.py +0 -2
  32. nautobot/circuits/tables.py +42 -5
  33. nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -1
  34. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -1
  35. nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -1
  36. nautobot/circuits/templates/circuits/provider_create.html +0 -1
  37. nautobot/circuits/templates/circuits/provider_retrieve.html +1 -1
  38. nautobot/circuits/tests/integration/test_relationships.py +13 -16
  39. nautobot/circuits/tests/test_api.py +13 -43
  40. nautobot/circuits/tests/test_filters.py +20 -15
  41. nautobot/circuits/tests/test_models.py +7 -3
  42. nautobot/circuits/tests/test_views.py +57 -67
  43. nautobot/circuits/views.py +18 -9
  44. nautobot/core/api/__init__.py +8 -2
  45. nautobot/core/api/authentication.py +0 -3
  46. nautobot/core/api/fields.py +15 -6
  47. nautobot/core/api/filter_backends.py +3 -2
  48. nautobot/core/api/metadata.py +237 -30
  49. nautobot/core/api/mixins.py +94 -0
  50. nautobot/core/api/pagination.py +3 -3
  51. nautobot/core/api/parsers.py +154 -0
  52. nautobot/core/api/renderers.py +153 -2
  53. nautobot/core/api/schema.py +47 -3
  54. nautobot/core/api/serializers.py +377 -37
  55. nautobot/core/api/urls.py +11 -3
  56. nautobot/core/api/utils.py +174 -2
  57. nautobot/core/api/versioning.py +32 -10
  58. nautobot/core/api/views.py +266 -75
  59. nautobot/core/apps/__init__.py +138 -221
  60. nautobot/core/celery/__init__.py +112 -41
  61. nautobot/core/celery/backends.py +19 -13
  62. nautobot/core/celery/control.py +46 -0
  63. nautobot/core/celery/encoders.py +53 -0
  64. nautobot/core/celery/log.py +38 -0
  65. nautobot/core/celery/schedulers.py +23 -4
  66. nautobot/core/celery/task.py +1 -16
  67. nautobot/core/checks.py +0 -27
  68. nautobot/core/choices.py +21 -113
  69. nautobot/core/{cli.py → cli/__init__.py} +1 -2
  70. nautobot/core/cli/__main__.py +3 -0
  71. nautobot/core/constants.py +25 -43
  72. nautobot/core/context_processors.py +12 -0
  73. nautobot/core/filters.py +2 -2
  74. nautobot/core/forms/__init__.py +0 -4
  75. nautobot/core/forms/fields.py +39 -68
  76. nautobot/core/forms/forms.py +27 -27
  77. nautobot/core/forms/utils.py +7 -59
  78. nautobot/core/forms/widgets.py +0 -1
  79. nautobot/core/graphql/__init__.py +2 -2
  80. nautobot/core/graphql/schema.py +4 -27
  81. nautobot/core/jobs/__init__.py +75 -0
  82. nautobot/core/management/commands/build_ui.py +255 -0
  83. nautobot/core/management/commands/celery.py +0 -1
  84. nautobot/core/management/commands/generate_test_data.py +18 -13
  85. nautobot/core/management/commands/post_upgrade.py +24 -24
  86. nautobot/core/management/commands/validate_models.py +0 -1
  87. nautobot/core/middleware.py +0 -1
  88. nautobot/core/models/__init__.py +26 -1
  89. nautobot/core/models/fields.py +24 -5
  90. nautobot/core/models/generics.py +2 -46
  91. nautobot/core/models/managers.py +5 -0
  92. nautobot/core/models/name_color_content_types.py +1 -19
  93. nautobot/core/models/tree_queries.py +14 -4
  94. nautobot/core/models/utils.py +9 -10
  95. nautobot/core/models/validators.py +17 -8
  96. nautobot/core/releases.py +8 -10
  97. nautobot/core/settings.py +81 -53
  98. nautobot/core/tables.py +5 -5
  99. nautobot/core/tasks.py +4 -7
  100. nautobot/core/templates/base.html +1 -49
  101. nautobot/core/templates/base_django.html +49 -0
  102. nautobot/core/templates/base_react.html +55 -0
  103. nautobot/core/templates/buttons/export.html +6 -4
  104. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  105. nautobot/core/templates/generic/object_list.html +4 -1
  106. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  107. nautobot/core/templates/inc/footer.html +1 -0
  108. nautobot/core/templates/inc/javascript.html +0 -14
  109. nautobot/core/templates/inc/nav_menu.html +28 -33
  110. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  111. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  112. nautobot/core/templates/nautobot_config.py.j2 +8 -25
  113. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  114. nautobot/core/templates/rest_framework/api.html +8 -0
  115. nautobot/core/templatetags/buttons.py +32 -29
  116. nautobot/core/templatetags/helpers.py +1 -1
  117. nautobot/core/testing/__init__.py +47 -44
  118. nautobot/core/testing/api.py +365 -47
  119. nautobot/core/testing/filters.py +12 -7
  120. nautobot/core/testing/integration.py +1 -1
  121. nautobot/core/testing/migrations.py +2 -0
  122. nautobot/core/testing/mixins.py +22 -12
  123. nautobot/core/testing/schema.py +2 -1
  124. nautobot/core/testing/views.py +28 -51
  125. nautobot/core/tests/integration/test_filters.py +17 -8
  126. nautobot/core/tests/integration/test_navbar.py +11 -34
  127. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  128. nautobot/core/tests/nautobot_config.py +2 -3
  129. nautobot/core/tests/runner.py +0 -1
  130. nautobot/core/tests/test_api.py +290 -24
  131. nautobot/core/tests/test_authentication.py +57 -14
  132. nautobot/core/tests/test_checks.py +0 -7
  133. nautobot/core/tests/test_choices.py +0 -1
  134. nautobot/core/tests/test_filters.py +117 -110
  135. nautobot/core/tests/test_forms.py +47 -110
  136. nautobot/core/tests/test_graphql.py +158 -135
  137. nautobot/core/tests/test_logging.py +4 -1
  138. nautobot/core/tests/test_managers.py +3 -5
  139. nautobot/core/tests/test_models.py +2 -0
  140. nautobot/core/tests/test_ordering.py +0 -2
  141. nautobot/core/tests/test_paginator.py +3 -1
  142. nautobot/core/tests/test_releases.py +12 -12
  143. nautobot/core/tests/test_templatetags_helpers.py +7 -4
  144. nautobot/core/tests/test_utils.py +112 -78
  145. nautobot/core/tests/test_views.py +12 -17
  146. nautobot/core/tests/test_views_utils.py +6 -9
  147. nautobot/core/utils/data.py +17 -0
  148. nautobot/core/utils/deprecation.py +13 -20
  149. nautobot/core/utils/filtering.py +53 -9
  150. nautobot/core/utils/git.py +12 -4
  151. nautobot/core/utils/lookup.py +3 -1
  152. nautobot/core/utils/requests.py +23 -116
  153. nautobot/core/views/__init__.py +1 -2
  154. nautobot/core/views/generic.py +131 -119
  155. nautobot/core/views/mixins.py +53 -62
  156. nautobot/core/views/paginator.py +0 -1
  157. nautobot/core/views/renderers.py +14 -12
  158. nautobot/core/views/utils.py +87 -4
  159. nautobot/dcim/api/serializers.py +160 -672
  160. nautobot/dcim/api/urls.py +1 -1
  161. nautobot/dcim/api/views.py +7 -46
  162. nautobot/dcim/choices.py +2 -25
  163. nautobot/dcim/elevations.py +0 -1
  164. nautobot/dcim/factory.py +15 -4
  165. nautobot/dcim/filters/__init__.py +42 -13
  166. nautobot/dcim/form_mixins.py +1 -27
  167. nautobot/dcim/forms.py +58 -797
  168. nautobot/dcim/management/commands/trace_paths.py +0 -1
  169. nautobot/dcim/migrations/0001_initial_part_1.py +0 -1
  170. nautobot/dcim/migrations/0002_initial_part_2.py +0 -1
  171. nautobot/dcim/migrations/0003_initial_part_3.py +0 -1
  172. nautobot/dcim/migrations/0004_initial_part_4.py +0 -1
  173. nautobot/dcim/migrations/0005_device_local_context_schema.py +0 -1
  174. nautobot/dcim/migrations/0006_auto_slug.py +0 -1
  175. nautobot/dcim/migrations/0007_device_secrets_group.py +0 -1
  176. nautobot/dcim/migrations/0008_increase_all_serial_lengths.py +0 -1
  177. nautobot/dcim/migrations/0009_add_natural_indexing.py +0 -1
  178. nautobot/dcim/migrations/0010_interface_status.py +0 -1
  179. nautobot/dcim/migrations/0011_interface_status_data_migration.py +0 -1
  180. nautobot/dcim/migrations/0012_interface_parent_bridge.py +0 -1
  181. nautobot/dcim/migrations/0013_location_location_type.py +0 -1
  182. nautobot/dcim/migrations/0014_location_status_data_migration.py +0 -1
  183. nautobot/dcim/migrations/0015_device_components__changeloggedmodel.py +0 -1
  184. nautobot/dcim/migrations/0016_device_components__timestamp_data_migration.py +0 -1
  185. nautobot/dcim/migrations/0017_locationtype_nestable.py +0 -1
  186. nautobot/dcim/migrations/0018_device_redundancy_group.py +0 -1
  187. nautobot/dcim/migrations/0019_device_redundancy_group_data_migration.py +0 -1
  188. nautobot/dcim/migrations/0020_move_site_fields_to_location_model.py +0 -1
  189. nautobot/dcim/migrations/0021_mptt_to_tree_queries.py +0 -1
  190. nautobot/dcim/migrations/0022_interface_mac_address_data_migration.py +0 -1
  191. nautobot/dcim/migrations/0023_alter_interface_mac_address.py +0 -1
  192. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -2
  193. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -14
  194. nautobot/dcim/migrations/0026_rename_device_and_rack_role.py +0 -1
  195. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -2
  196. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -2
  197. nautobot/dcim/migrations/0029_add_tree_managers_and_foreign_keys_pre_data_migration.py +0 -1
  198. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  199. nautobot/dcim/migrations/0031_rename_path_end_point_related_name.py +0 -1
  200. nautobot/dcim/migrations/0032_remove_site_foreign_key_from_dcim_models.py +0 -1
  201. nautobot/dcim/migrations/0033_created_datetime.py +0 -1
  202. nautobot/dcim/migrations/0034_fixup_fks_and_related_names.py +0 -1
  203. nautobot/dcim/migrations/0035_related_name_changes.py +1 -2
  204. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -2
  205. nautobot/dcim/migrations/0037_interface_ip_addresses_m2m.py +0 -1
  206. nautobot/dcim/migrations/0038_alter_location_managers.py +0 -1
  207. nautobot/dcim/migrations/0039_remove_slug.py +24 -0
  208. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  209. nautobot/dcim/migrations/0041_ipam__namespaces.py +25 -0
  210. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  211. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  212. nautobot/dcim/models/cables.py +4 -35
  213. nautobot/dcim/models/device_component_templates.py +7 -2
  214. nautobot/dcim/models/device_components.py +26 -203
  215. nautobot/dcim/models/devices.py +30 -152
  216. nautobot/dcim/models/locations.py +3 -64
  217. nautobot/dcim/models/power.py +3 -51
  218. nautobot/dcim/models/racks.py +7 -86
  219. nautobot/dcim/navigation.py +141 -467
  220. nautobot/dcim/signals.py +0 -2
  221. nautobot/dcim/tables/devices.py +8 -5
  222. nautobot/dcim/tables/devicetypes.py +1 -1
  223. nautobot/dcim/tables/locations.py +2 -2
  224. nautobot/dcim/tables/power.py +2 -2
  225. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  226. nautobot/dcim/templates/dcim/device.html +15 -4
  227. nautobot/dcim/templates/dcim/device_edit.html +6 -0
  228. nautobot/dcim/templates/dcim/deviceredundancygroup_create.html +0 -1
  229. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  230. nautobot/dcim/templates/dcim/interface.html +4 -0
  231. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  232. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  233. nautobot/dcim/templates/dcim/location.html +16 -1
  234. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  235. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  236. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  237. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  238. nautobot/dcim/tests/test_api.py +202 -130
  239. nautobot/dcim/tests/test_cablepaths.py +47 -42
  240. nautobot/dcim/tests/test_filters.py +156 -134
  241. nautobot/dcim/tests/test_forms.py +12 -213
  242. nautobot/dcim/tests/test_graphql.py +8 -3
  243. nautobot/dcim/tests/test_migrations.py +6 -11
  244. nautobot/dcim/tests/test_models.py +208 -158
  245. nautobot/dcim/tests/test_natural_ordering.py +12 -14
  246. nautobot/dcim/tests/test_signals.py +7 -4
  247. nautobot/dcim/tests/test_views.py +270 -264
  248. nautobot/dcim/urls.py +21 -26
  249. nautobot/dcim/views.py +14 -156
  250. nautobot/docs/additional-features/caching.md +6 -87
  251. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  252. nautobot/docs/additional-features/jobs.md +179 -197
  253. nautobot/docs/administration/nautobot-server.md +9 -24
  254. nautobot/docs/administration/nautobot-shell.md +6 -6
  255. nautobot/docs/administration/replicating-nautobot.md +0 -10
  256. nautobot/docs/configuration/index.md +9 -9
  257. nautobot/docs/configuration/optional-settings.md +32 -61
  258. nautobot/docs/configuration/required-settings.md +11 -52
  259. nautobot/docs/development/application-registry.md +2 -13
  260. nautobot/docs/development/best-practices.md +2 -1
  261. nautobot/docs/development/docker-compose-advanced-use-cases.md +1 -1
  262. nautobot/docs/development/extending-models.md +15 -17
  263. nautobot/docs/development/generic-views.md +0 -2
  264. nautobot/docs/development/getting-started.md +56 -6
  265. nautobot/docs/development/navigation-menu.md +22 -93
  266. nautobot/docs/development/react-ui.md +105 -0
  267. nautobot/docs/development/release-checklist.md +3 -3
  268. nautobot/docs/development/role-internals.md +1 -3
  269. nautobot/docs/development/style-guide.md +6 -4
  270. nautobot/docs/development/templates.md +2 -1
  271. nautobot/docs/docker/index.md +16 -14
  272. nautobot/docs/index.md +7 -3
  273. nautobot/docs/installation/index.md +4 -1
  274. nautobot/docs/installation/migrating-from-netbox.md +12 -43
  275. nautobot/docs/installation/migrating-from-postgresql.md +1 -1
  276. nautobot/docs/installation/nautobot.md +1 -1
  277. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  278. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  279. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  280. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  281. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  282. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  283. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  284. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  285. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  286. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  287. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  288. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  289. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  290. nautobot/docs/installation/upgrading-from-nautobot-v1.md +190 -636
  291. nautobot/docs/installation/upgrading.md +5 -2
  292. nautobot/docs/models/dcim/device.md +3 -0
  293. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  294. nautobot/docs/models/extras/computedfield.md +4 -4
  295. nautobot/docs/models/extras/dynamicgroup.md +9 -9
  296. nautobot/docs/models/extras/gitrepository.md +3 -0
  297. nautobot/docs/models/extras/job.md +1 -0
  298. nautobot/docs/models/extras/jobbutton.md +18 -13
  299. nautobot/docs/models/extras/jobhook.md +7 -4
  300. nautobot/docs/models/extras/jobresult.md +6 -2
  301. nautobot/docs/models/extras/relationship.md +2 -2
  302. nautobot/docs/models/extras/status.md +6 -19
  303. nautobot/docs/models/ipam/ipaddress.md +3 -0
  304. nautobot/docs/models/ipam/vrf.md +0 -3
  305. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  306. nautobot/docs/plugins/development.md +92 -24
  307. nautobot/docs/release-notes/version-1.5.md +96 -0
  308. nautobot/docs/release-notes/version-2.0.md +216 -0
  309. nautobot/docs/requirements.txt +5 -4
  310. nautobot/docs/rest-api/overview.md +384 -215
  311. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  312. nautobot/extras/admin.py +3 -5
  313. nautobot/extras/api/customfields.py +15 -39
  314. nautobot/extras/api/fields.py +0 -11
  315. nautobot/extras/api/mixins.py +45 -0
  316. nautobot/extras/api/relationships.py +63 -159
  317. nautobot/extras/api/serializers.py +165 -706
  318. nautobot/extras/api/urls.py +1 -1
  319. nautobot/extras/api/views.py +295 -282
  320. nautobot/extras/apps.py +4 -7
  321. nautobot/extras/choices.py +11 -22
  322. nautobot/extras/constants.py +9 -3
  323. nautobot/extras/datasources/__init__.py +2 -0
  324. nautobot/extras/datasources/git.py +135 -186
  325. nautobot/extras/datasources/registry.py +25 -35
  326. nautobot/extras/factory.py +1 -3
  327. nautobot/extras/filters/__init__.py +49 -47
  328. nautobot/extras/filters/mixins.py +10 -8
  329. nautobot/extras/forms/forms.py +72 -148
  330. nautobot/extras/forms/mixins.py +34 -57
  331. nautobot/extras/health_checks.py +0 -33
  332. nautobot/extras/jobs.py +387 -566
  333. nautobot/extras/management/__init__.py +55 -48
  334. nautobot/extras/management/commands/renaturalize.py +0 -1
  335. nautobot/extras/management/commands/runjob.py +24 -62
  336. nautobot/extras/management/commands/webhook_receiver.py +0 -1
  337. nautobot/extras/managers.py +30 -7
  338. nautobot/extras/migrations/0001_initial_part_1.py +0 -1
  339. nautobot/extras/migrations/0002_initial_part_2.py +0 -1
  340. nautobot/extras/migrations/0003_initial_part_3.py +0 -1
  341. nautobot/extras/migrations/0004_populate_default_status_records.py +0 -1
  342. nautobot/extras/migrations/0005_configcontext_device_types.py +0 -1
  343. nautobot/extras/migrations/0006_graphqlquery.py +0 -1
  344. nautobot/extras/migrations/0007_configcontextschema.py +0 -1
  345. nautobot/extras/migrations/0008_jobresult__custom_field_data.py +0 -1
  346. nautobot/extras/migrations/0009_computedfield.py +0 -1
  347. nautobot/extras/migrations/0010_change_cf_validation_max_min_field_to_bigint.py +0 -1
  348. nautobot/extras/migrations/0011_fileattachment_fileproxy.py +0 -1
  349. nautobot/extras/migrations/0012_healthchecktestmodel.py +0 -1
  350. nautobot/extras/migrations/0013_default_fallback_value_computedfield.py +0 -1
  351. nautobot/extras/migrations/0014_auto_slug.py +0 -1
  352. nautobot/extras/migrations/0015_scheduled_job.py +0 -1
  353. nautobot/extras/migrations/0016_secret.py +0 -1
  354. nautobot/extras/migrations/0017_joblogentry.py +0 -1
  355. nautobot/extras/migrations/0018_joblog_data_migration.py +0 -2
  356. nautobot/extras/migrations/0019_joblogentry__meta_options__related_name.py +0 -1
  357. nautobot/extras/migrations/0020_customfield_changelog.py +0 -1
  358. nautobot/extras/migrations/0021_customfield_changelog_data.py +0 -1
  359. nautobot/extras/migrations/0022_objectchange_object_datav2.py +0 -1
  360. nautobot/extras/migrations/0023_job_model.py +0 -1
  361. nautobot/extras/migrations/0024_job_data_migration.py +0 -1
  362. nautobot/extras/migrations/0025_add_advanced_ui_boolean_to_customfield_conputedfield_and_relationship.py +0 -1
  363. nautobot/extras/migrations/0026_job_add_gitrepository_fk.py +0 -1
  364. nautobot/extras/migrations/0027_job_gitrepository_data_migration.py +0 -1
  365. nautobot/extras/migrations/0028_job_reduce_source.py +0 -1
  366. nautobot/extras/migrations/0029_dynamicgroup.py +0 -1
  367. nautobot/extras/migrations/0030_webhook_alter_unique_together.py +0 -1
  368. nautobot/extras/migrations/0031_tag_content_types.py +0 -1
  369. nautobot/extras/migrations/0032_tag_content_types_data_migration.py +0 -1
  370. nautobot/extras/migrations/0033_add__optimized_indexing.py +0 -1
  371. nautobot/extras/migrations/0034_alter_fileattachment_mimetype.py +0 -1
  372. nautobot/extras/migrations/0035_scheduledjob_crontab.py +0 -1
  373. nautobot/extras/migrations/0036_job_add_has_sensitive_variables.py +0 -1
  374. nautobot/extras/migrations/0037_configcontextschema__remove_name_unique__create_constraint_unique_name_owner.py +0 -1
  375. nautobot/extras/migrations/0038_configcontext_locations.py +0 -1
  376. nautobot/extras/migrations/0039_objectchange__add_change_context.py +0 -1
  377. nautobot/extras/migrations/0040_dynamicgroup__dynamicgroupmembership.py +0 -1
  378. nautobot/extras/migrations/0041_jobresult_job_kwargs.py +0 -1
  379. nautobot/extras/migrations/0042_job__add_is_job_hook_receiver.py +0 -1
  380. nautobot/extras/migrations/0043_note.py +0 -1
  381. nautobot/extras/migrations/0044_add_job_hook.py +0 -1
  382. nautobot/extras/migrations/0045_add_custom_field_slug.py +0 -1
  383. nautobot/extras/migrations/0046_populate_custom_field_slug_label.py +0 -1
  384. nautobot/extras/migrations/0047_enforce_custom_field_slug.py +0 -1
  385. nautobot/extras/migrations/0048_alter_objectchange_change_context_detail.py +0 -1
  386. nautobot/extras/migrations/0049_alter_tag_slug.py +0 -1
  387. nautobot/extras/migrations/0050_customfield_grouping.py +0 -1
  388. nautobot/extras/migrations/0051_add_job_task_queues.py +0 -1
  389. nautobot/extras/migrations/0052_configcontext_device_redundancy_groups.py +0 -1
  390. nautobot/extras/migrations/0053_relationship_required_on.py +0 -1
  391. nautobot/extras/migrations/0054_scheduledjob_kwargs_request_user_change.py +0 -1
  392. nautobot/extras/migrations/0055_configcontext_dynamic_groups.py +0 -1
  393. nautobot/extras/migrations/0056_objectchange_add_reverse_time_idx.py +0 -1
  394. nautobot/extras/migrations/0057_jobbutton.py +0 -1
  395. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  396. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -2
  397. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -2
  398. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -8
  399. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -33
  400. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -2
  401. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -2
  402. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  403. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -2
  404. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -3
  405. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -2
  406. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -2
  407. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  408. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -2
  409. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  410. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -10
  411. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -2
  412. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  413. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  414. nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
  415. nautobot/extras/migrations/0078_remove_slug.py +45 -0
  416. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  417. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  418. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  419. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  420. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  421. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  422. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  423. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  424. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  425. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  426. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  427. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  428. nautobot/extras/models/__init__.py +2 -3
  429. nautobot/extras/models/change_logging.py +0 -36
  430. nautobot/extras/models/customfields.py +39 -33
  431. nautobot/extras/models/datasources.py +48 -50
  432. nautobot/extras/models/groups.py +5 -12
  433. nautobot/extras/models/jobs.py +190 -323
  434. nautobot/extras/models/mixins.py +0 -71
  435. nautobot/extras/models/models.py +1 -22
  436. nautobot/extras/models/relationships.py +20 -21
  437. nautobot/extras/models/roles.py +0 -23
  438. nautobot/extras/models/secrets.py +2 -31
  439. nautobot/extras/models/statuses.py +6 -5
  440. nautobot/extras/models/tags.py +2 -17
  441. nautobot/extras/navigation.py +89 -307
  442. nautobot/extras/plugins/__init__.py +3 -121
  443. nautobot/extras/plugins/utils.py +0 -3
  444. nautobot/extras/plugins/validators.py +5 -4
  445. nautobot/extras/plugins/views.py +16 -4
  446. nautobot/extras/querysets.py +1 -7
  447. nautobot/extras/registry.py +3 -0
  448. nautobot/extras/signals.py +26 -60
  449. nautobot/extras/tables.py +42 -49
  450. nautobot/extras/tasks.py +0 -12
  451. nautobot/extras/templates/extras/configcontext.html +1 -1
  452. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  453. nautobot/extras/templates/extras/customfield.html +0 -13
  454. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -1
  455. nautobot/extras/templates/extras/gitrepository.html +3 -3
  456. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  457. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  458. nautobot/extras/templates/extras/job.html +35 -25
  459. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  460. nautobot/extras/templates/extras/job_detail.html +13 -31
  461. nautobot/extras/templates/extras/job_edit.html +14 -17
  462. nautobot/extras/templates/extras/jobresult.html +24 -6
  463. nautobot/extras/templates/extras/objectchange_list.html +1 -1
  464. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  465. nautobot/extras/templates/extras/secret.html +28 -0
  466. nautobot/extras/templates/extras/secret_edit.html +0 -1
  467. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -1
  468. nautobot/extras/templatetags/custom_links.py +0 -2
  469. nautobot/extras/templatetags/job_buttons.py +1 -0
  470. nautobot/extras/templatetags/plugins.py +0 -1
  471. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  472. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  473. nautobot/extras/test_jobs/dry_run.py +29 -0
  474. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  475. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  476. nautobot/extras/test_jobs/fail.py +23 -0
  477. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  478. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  479. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  480. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  481. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  482. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  483. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  484. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  485. nautobot/extras/test_jobs/job_variables.py +88 -0
  486. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  487. nautobot/extras/test_jobs/log_redaction.py +20 -0
  488. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  489. nautobot/extras/test_jobs/modify_db.py +25 -0
  490. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  491. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  492. nautobot/extras/test_jobs/object_var_required.py +21 -0
  493. nautobot/extras/test_jobs/object_vars.py +26 -0
  494. nautobot/extras/test_jobs/pass.py +25 -0
  495. nautobot/extras/test_jobs/profiling.py +32 -0
  496. nautobot/extras/test_jobs/read_only_job.py +15 -0
  497. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  498. nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
  499. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  500. nautobot/extras/tests/integration/__init__.py +3 -3
  501. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  502. nautobot/extras/tests/integration/test_configcontextschema.py +7 -5
  503. nautobot/extras/tests/integration/test_customfields.py +4 -2
  504. nautobot/extras/tests/integration/test_dynamicgroups.py +2 -2
  505. nautobot/extras/tests/integration/test_jobs.py +25 -27
  506. nautobot/extras/tests/integration/test_notes.py +8 -4
  507. nautobot/extras/tests/integration/test_plugins.py +4 -4
  508. nautobot/extras/tests/integration/test_relationships.py +2 -2
  509. nautobot/extras/tests/test_api.py +371 -381
  510. nautobot/extras/tests/test_changelog.py +17 -16
  511. nautobot/extras/tests/test_context_managers.py +5 -6
  512. nautobot/extras/tests/test_customfields.py +112 -73
  513. nautobot/extras/tests/test_datasources.py +191 -117
  514. nautobot/extras/tests/test_dynamicgroups.py +45 -68
  515. nautobot/extras/tests/test_filters.py +170 -130
  516. nautobot/extras/tests/test_forms.py +107 -109
  517. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  518. nautobot/extras/tests/test_jobs.py +271 -273
  519. nautobot/extras/tests/test_management.py +3 -6
  520. nautobot/extras/tests/test_migrations.py +5 -3
  521. nautobot/extras/tests/test_models.py +121 -173
  522. nautobot/extras/tests/test_notes.py +0 -1
  523. nautobot/extras/tests/test_plugins.py +55 -89
  524. nautobot/extras/tests/test_relationships.py +174 -130
  525. nautobot/extras/tests/test_tags.py +6 -12
  526. nautobot/extras/tests/test_utils.py +31 -1
  527. nautobot/extras/tests/test_views.py +223 -184
  528. nautobot/extras/tests/test_webhooks.py +16 -15
  529. nautobot/extras/urls.py +69 -69
  530. nautobot/extras/utils.py +137 -163
  531. nautobot/extras/views.py +81 -153
  532. nautobot/ipam/api/fields.py +17 -0
  533. nautobot/ipam/api/serializers.py +77 -164
  534. nautobot/ipam/api/urls.py +4 -1
  535. nautobot/ipam/api/views.py +28 -19
  536. nautobot/ipam/apps.py +1 -0
  537. nautobot/ipam/choices.py +5 -12
  538. nautobot/ipam/constants.py +1 -0
  539. nautobot/ipam/factory.py +41 -30
  540. nautobot/ipam/filters.py +58 -25
  541. nautobot/ipam/forms.py +82 -211
  542. nautobot/ipam/graphql/types.py +0 -9
  543. nautobot/ipam/lookups.py +13 -8
  544. nautobot/ipam/management/commands/__init__.py +0 -0
  545. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  546. nautobot/ipam/migrations/0001_initial_part_1.py +0 -1
  547. nautobot/ipam/migrations/0002_initial_part_2.py +0 -1
  548. nautobot/ipam/migrations/0003_remove_max_length.py +0 -1
  549. nautobot/ipam/migrations/0004_fixup_p2p_broadcast.py +0 -1
  550. nautobot/ipam/migrations/0005_auto_slug.py +0 -1
  551. nautobot/ipam/migrations/0006_ipaddress_nat_outside_list.py +0 -1
  552. nautobot/ipam/migrations/0007_add_natural_indexing.py +0 -1
  553. nautobot/ipam/migrations/0008_prefix_vlan_vlangroup_location.py +0 -1
  554. nautobot/ipam/migrations/0009_alter_vlan_name.py +0 -1
  555. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -2
  556. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -39
  557. nautobot/ipam/migrations/0012_rename_ipam_roles.py +0 -1
  558. nautobot/ipam/migrations/0013_delete_role.py +0 -1
  559. nautobot/ipam/migrations/0014_rename_foreign_keys_and_related_names.py +0 -1
  560. nautobot/ipam/migrations/0015_prefix_add_type.py +0 -1
  561. nautobot/ipam/migrations/0016_prefix_type_data_migration.py +0 -3
  562. nautobot/ipam/migrations/0017_prefix_remove_is_pool.py +0 -1
  563. nautobot/ipam/migrations/0018_remove_site_foreign_key_from_ipam_models.py +0 -1
  564. nautobot/ipam/migrations/0019_created_datetime.py +0 -1
  565. nautobot/ipam/migrations/0020_related_name_changes.py +1 -2
  566. nautobot/ipam/migrations/0021_prefix_add_rir_and_date_allocated.py +0 -1
  567. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +3 -5
  568. nautobot/ipam/migrations/0023_delete_aggregate.py +0 -1
  569. nautobot/ipam/migrations/0024_interface_to_ipaddress_m2m.py +0 -1
  570. nautobot/ipam/migrations/0025_interface_ipaddress_m2m_data_migration.py +0 -1
  571. nautobot/ipam/migrations/0026_ipaddress_remove_assigned_object.py +0 -1
  572. nautobot/ipam/migrations/0027_remove_rir_slug.py +16 -0
  573. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  574. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  575. nautobot/ipam/migrations/0030_ipam__namespaces.py +231 -0
  576. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  577. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  578. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  579. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  580. nautobot/ipam/models.py +579 -368
  581. nautobot/ipam/navigation.py +36 -159
  582. nautobot/ipam/querysets.py +117 -90
  583. nautobot/ipam/signals.py +89 -0
  584. nautobot/ipam/tables.py +86 -28
  585. nautobot/ipam/templates/ipam/ipaddress.html +14 -30
  586. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -0
  587. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  588. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  589. nautobot/ipam/templates/ipam/namespace_retrieve.html +42 -0
  590. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  591. nautobot/ipam/templates/ipam/prefix.html +27 -33
  592. nautobot/ipam/templates/ipam/prefix_edit.html +7 -1
  593. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  594. nautobot/ipam/templates/ipam/vrf.html +6 -4
  595. nautobot/ipam/templates/ipam/vrf_edit.html +20 -2
  596. nautobot/ipam/tests/integration/test_prefixes.py +4 -27
  597. nautobot/ipam/tests/test_api.py +60 -61
  598. nautobot/ipam/tests/test_filters.py +187 -126
  599. nautobot/ipam/tests/test_forms.py +12 -6
  600. nautobot/ipam/tests/test_graphql.py +8 -6
  601. nautobot/ipam/tests/test_migrations.py +8 -13
  602. nautobot/ipam/tests/test_models.py +426 -274
  603. nautobot/ipam/tests/test_ordering.py +6 -3
  604. nautobot/ipam/tests/test_querysets.py +340 -96
  605. nautobot/ipam/tests/test_views.py +100 -55
  606. nautobot/ipam/urls.py +28 -5
  607. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  608. nautobot/ipam/utils/migrations.py +713 -0
  609. nautobot/ipam/views.py +237 -122
  610. nautobot/project-static/docs/404.html +1399 -166
  611. nautobot/project-static/docs/additional-features/caching.html +1416 -320
  612. nautobot/project-static/docs/additional-features/change-logging.html +1389 -190
  613. nautobot/project-static/docs/additional-features/config-contexts.html +1389 -190
  614. nautobot/project-static/docs/additional-features/graphql.html +1389 -190
  615. nautobot/project-static/docs/additional-features/healthcheck.html +1389 -190
  616. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1393 -190
  617. nautobot/project-static/docs/additional-features/jobs.html +1677 -460
  618. nautobot/project-static/docs/additional-features/napalm.html +1389 -190
  619. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1389 -190
  620. nautobot/project-static/docs/additional-features/template-filters.html +1389 -190
  621. nautobot/project-static/docs/administration/celery-queues.html +1389 -190
  622. nautobot/project-static/docs/administration/nautobot-server.html +1553 -375
  623. nautobot/project-static/docs/administration/nautobot-shell.html +1395 -196
  624. nautobot/project-static/docs/administration/permissions.html +1389 -190
  625. nautobot/project-static/docs/administration/replicating-nautobot.html +1387 -207
  626. nautobot/project-static/docs/apps/index.html +1389 -190
  627. nautobot/project-static/docs/apps/nautobot-apps.html +1387 -175
  628. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js +29 -0
  629. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js.map +8 -0
  630. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js → search.208ed371.min.js} +9 -15
  631. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js.map → search.208ed371.min.js.map} +4 -4
  632. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css +1 -0
  633. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css.map +1 -0
  634. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css +1 -0
  635. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css.map +1 -0
  636. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1775 -590
  637. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1389 -190
  638. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3588 -1922
  639. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1461 -262
  640. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1401 -170
  641. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1396 -191
  642. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +2095 -894
  643. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2357 -1194
  644. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2258 -940
  645. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1389 -190
  646. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1400 -201
  647. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11068 -7861
  648. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2867 -2224
  649. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1389 -190
  650. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2641 -1573
  651. nautobot/project-static/docs/configuration/authentication/ldap.html +1389 -190
  652. nautobot/project-static/docs/configuration/authentication/remote.html +1389 -190
  653. nautobot/project-static/docs/configuration/authentication/sso.html +1389 -190
  654. nautobot/project-static/docs/configuration/index.html +1398 -199
  655. nautobot/project-static/docs/configuration/optional-settings.html +1418 -274
  656. nautobot/project-static/docs/configuration/required-settings.html +1419 -287
  657. nautobot/project-static/docs/core-functionality/circuits.html +1446 -247
  658. nautobot/project-static/docs/core-functionality/device-types.html +1448 -249
  659. nautobot/project-static/docs/core-functionality/devices.html +1452 -249
  660. nautobot/project-static/docs/core-functionality/ipam.html +1452 -253
  661. nautobot/project-static/docs/core-functionality/power.html +1448 -249
  662. nautobot/project-static/docs/core-functionality/secrets.html +1448 -249
  663. nautobot/project-static/docs/core-functionality/services.html +1448 -249
  664. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1448 -249
  665. nautobot/project-static/docs/core-functionality/tenancy.html +1448 -249
  666. nautobot/project-static/docs/core-functionality/virtualization.html +1452 -249
  667. nautobot/project-static/docs/core-functionality/vlans.html +1448 -249
  668. nautobot/project-static/docs/development/application-registry.html +1393 -214
  669. nautobot/project-static/docs/development/best-practices.html +1392 -192
  670. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1390 -191
  671. nautobot/project-static/docs/development/extending-models.html +1443 -257
  672. nautobot/project-static/docs/development/generic-views.html +1403 -174
  673. nautobot/project-static/docs/development/getting-started.html +1568 -262
  674. nautobot/project-static/docs/development/homepage.html +1389 -190
  675. nautobot/project-static/docs/development/index.html +1389 -190
  676. nautobot/project-static/docs/development/model-features.html +1389 -190
  677. nautobot/project-static/docs/development/natural-keys.html +1389 -190
  678. nautobot/project-static/docs/development/navigation-menu.html +1451 -330
  679. nautobot/project-static/docs/development/react-ui.html +4199 -0
  680. nautobot/project-static/docs/development/release-checklist.html +1392 -193
  681. nautobot/project-static/docs/development/role-internals.html +1402 -172
  682. nautobot/project-static/docs/development/style-guide.html +1399 -199
  683. nautobot/project-static/docs/development/templates.html +1391 -191
  684. nautobot/project-static/docs/development/testing.html +1389 -190
  685. nautobot/project-static/docs/development/user-preferences.html +1389 -190
  686. nautobot/project-static/docs/docker/index.html +1408 -206
  687. nautobot/project-static/docs/index.html +1397 -180
  688. nautobot/project-static/docs/installation/centos.html +1401 -170
  689. nautobot/project-static/docs/installation/external-authentication.html +1389 -190
  690. nautobot/project-static/docs/installation/http-server.html +1389 -190
  691. nautobot/project-static/docs/installation/index.html +1394 -191
  692. nautobot/project-static/docs/installation/migrating-from-netbox.html +1452 -305
  693. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1390 -191
  694. nautobot/project-static/docs/installation/nautobot.html +1390 -191
  695. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1389 -190
  696. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1401 -170
  697. nautobot/project-static/docs/installation/services.html +1389 -190
  698. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  699. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  700. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  701. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  702. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  703. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  704. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  705. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  706. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  707. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  708. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  709. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  710. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  711. nautobot/project-static/docs/installation/ubuntu.html +1401 -170
  712. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +4254 -1923
  713. nautobot/project-static/docs/installation/upgrading.html +1395 -192
  714. nautobot/project-static/docs/models/circuits/circuit.html +1427 -174
  715. nautobot/project-static/docs/models/circuits/circuittermination.html +1427 -174
  716. nautobot/project-static/docs/models/circuits/circuittype.html +1427 -174
  717. nautobot/project-static/docs/models/circuits/provider.html +1427 -174
  718. nautobot/project-static/docs/models/circuits/providernetwork.html +1427 -174
  719. nautobot/project-static/docs/models/dcim/cable.html +1458 -174
  720. nautobot/project-static/docs/models/dcim/consoleport.html +1427 -174
  721. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1427 -174
  722. nautobot/project-static/docs/models/dcim/consoleserverport.html +1427 -174
  723. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1427 -174
  724. nautobot/project-static/docs/models/dcim/device.html +1431 -174
  725. nautobot/project-static/docs/models/dcim/devicebay.html +1427 -174
  726. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1427 -174
  727. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1522 -177
  728. nautobot/project-static/docs/models/dcim/devicetype.html +1427 -174
  729. nautobot/project-static/docs/models/dcim/frontport.html +1427 -174
  730. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1427 -174
  731. nautobot/project-static/docs/models/dcim/interface.html +1427 -174
  732. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1427 -174
  733. nautobot/project-static/docs/models/dcim/inventoryitem.html +1427 -174
  734. nautobot/project-static/docs/models/dcim/location.html +1427 -174
  735. nautobot/project-static/docs/models/dcim/locationtype.html +1427 -174
  736. nautobot/project-static/docs/models/dcim/manufacturer.html +1427 -174
  737. nautobot/project-static/docs/models/dcim/platform.html +1427 -174
  738. nautobot/project-static/docs/models/dcim/powerfeed.html +1425 -172
  739. nautobot/project-static/docs/models/dcim/poweroutlet.html +1427 -174
  740. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1427 -174
  741. nautobot/project-static/docs/models/dcim/powerpanel.html +1425 -172
  742. nautobot/project-static/docs/models/dcim/powerport.html +1427 -174
  743. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1427 -174
  744. nautobot/project-static/docs/models/dcim/rack.html +1427 -174
  745. nautobot/project-static/docs/models/dcim/rackgroup.html +1427 -174
  746. nautobot/project-static/docs/models/dcim/rackreservation.html +1427 -174
  747. nautobot/project-static/docs/models/dcim/rearport.html +1427 -174
  748. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1427 -174
  749. nautobot/project-static/docs/models/dcim/region.html +1401 -170
  750. nautobot/project-static/docs/models/dcim/site.html +1401 -170
  751. nautobot/project-static/docs/models/dcim/virtualchassis.html +1425 -172
  752. nautobot/project-static/docs/models/extras/computedfield.html +1393 -194
  753. nautobot/project-static/docs/models/extras/configcontext.html +1465 -174
  754. nautobot/project-static/docs/models/extras/configcontextschema.html +1421 -168
  755. nautobot/project-static/docs/models/extras/customfield.html +1389 -190
  756. nautobot/project-static/docs/models/extras/customlink.html +1389 -190
  757. nautobot/project-static/docs/models/extras/dynamicgroup.html +1398 -199
  758. nautobot/project-static/docs/models/extras/exporttemplate.html +1389 -190
  759. nautobot/project-static/docs/models/extras/gitrepository.html +1393 -190
  760. nautobot/project-static/docs/models/extras/graphqlquery.html +1469 -171
  761. nautobot/project-static/docs/models/extras/imageattachment.html +1434 -181
  762. nautobot/project-static/docs/models/extras/job.html +1411 -157
  763. nautobot/project-static/docs/models/extras/jobbutton.html +1410 -207
  764. nautobot/project-static/docs/models/extras/jobhook.html +1397 -194
  765. nautobot/project-static/docs/models/extras/joblogentry.html +1408 -155
  766. nautobot/project-static/docs/models/extras/jobresult.html +1417 -159
  767. nautobot/project-static/docs/models/extras/note.html +1389 -190
  768. nautobot/project-static/docs/models/extras/relationship.html +1391 -192
  769. nautobot/project-static/docs/models/extras/role.html +1495 -198
  770. nautobot/project-static/docs/models/extras/secret.html +1492 -201
  771. nautobot/project-static/docs/models/extras/secretsgroup.html +1410 -157
  772. nautobot/project-static/docs/models/extras/status.html +1381 -221
  773. nautobot/project-static/docs/models/extras/tag.html +1389 -190
  774. nautobot/project-static/docs/models/extras/webhook.html +1389 -190
  775. nautobot/project-static/docs/models/ipam/ipaddress.html +1488 -200
  776. nautobot/project-static/docs/models/ipam/prefix.html +1410 -157
  777. nautobot/project-static/docs/models/ipam/rir.html +1410 -157
  778. nautobot/project-static/docs/models/ipam/routetarget.html +1410 -157
  779. nautobot/project-static/docs/models/ipam/service.html +1410 -157
  780. nautobot/project-static/docs/models/ipam/vlan.html +1410 -157
  781. nautobot/project-static/docs/models/ipam/vlangroup.html +1410 -157
  782. nautobot/project-static/docs/models/ipam/vrf.html +1410 -161
  783. nautobot/project-static/docs/models/tenancy/tenant.html +1412 -159
  784. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1412 -159
  785. nautobot/project-static/docs/models/users/objectpermission.html +1462 -171
  786. nautobot/project-static/docs/models/users/token.html +1410 -157
  787. nautobot/project-static/docs/models/virtualization/cluster.html +1410 -157
  788. nautobot/project-static/docs/models/virtualization/clustergroup.html +1410 -157
  789. nautobot/project-static/docs/models/virtualization/clustertype.html +1410 -157
  790. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1414 -157
  791. nautobot/project-static/docs/models/virtualization/vminterface.html +1410 -157
  792. nautobot/project-static/docs/objects.inv +0 -0
  793. nautobot/project-static/docs/plugins/development.html +1916 -646
  794. nautobot/project-static/docs/plugins/index.html +1389 -190
  795. nautobot/project-static/docs/plugins/porting-from-netbox.html +1389 -190
  796. nautobot/project-static/docs/release-notes/index.html +1389 -190
  797. nautobot/project-static/docs/release-notes/version-1.0.html +1389 -190
  798. nautobot/project-static/docs/release-notes/version-1.1.html +1389 -190
  799. nautobot/project-static/docs/release-notes/version-1.2.html +1389 -190
  800. nautobot/project-static/docs/release-notes/version-1.3.html +1389 -190
  801. nautobot/project-static/docs/release-notes/version-1.4.html +1389 -190
  802. nautobot/project-static/docs/release-notes/version-1.5.html +2016 -397
  803. nautobot/project-static/docs/release-notes/version-2.0.html +1935 -287
  804. nautobot/project-static/docs/requirements.txt +5 -4
  805. nautobot/project-static/docs/rest-api/authentication.html +1389 -190
  806. nautobot/project-static/docs/rest-api/filtering.html +1389 -190
  807. nautobot/project-static/docs/rest-api/overview.html +2002 -576
  808. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  809. nautobot/project-static/docs/search/search_index.json +1 -1
  810. nautobot/project-static/docs/sitemap.xml +197 -187
  811. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  812. nautobot/project-static/docs/user-guides/custom-fields.html +1390 -191
  813. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1392 -193
  814. nautobot/project-static/docs/user-guides/getting-started/index.html +1388 -189
  815. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1388 -189
  816. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1386 -187
  817. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1448 -249
  818. nautobot/project-static/docs/user-guides/getting-started/regions.html +1411 -212
  819. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1395 -196
  820. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1448 -249
  821. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1448 -249
  822. nautobot/project-static/docs/user-guides/git-data-source.html +1405 -206
  823. nautobot/project-static/docs/user-guides/graphql.html +1402 -203
  824. nautobot/project-static/docs/user-guides/relationships.html +1448 -249
  825. nautobot/project-static/docs/user-guides/s3-django-storage.html +1448 -249
  826. nautobot/project-static/js/forms.js +16 -9
  827. nautobot/project-static/js/theme.js +5 -0
  828. nautobot/tenancy/api/serializers.py +4 -34
  829. nautobot/tenancy/api/urls.py +1 -1
  830. nautobot/tenancy/filters/__init__.py +9 -7
  831. nautobot/tenancy/filters/mixins.py +3 -2
  832. nautobot/tenancy/forms.py +3 -36
  833. nautobot/tenancy/migrations/0001_initial.py +0 -1
  834. nautobot/tenancy/migrations/0002_auto_slug.py +0 -1
  835. nautobot/tenancy/migrations/0003_mptt_to_tree_queries.py +0 -1
  836. nautobot/tenancy/migrations/0004_change_tree_manager_on_tree_models.py +0 -1
  837. nautobot/tenancy/migrations/0005_rename_foreign_keys_and_related_names.py +0 -1
  838. nautobot/tenancy/migrations/0006_created_datetime.py +0 -1
  839. nautobot/tenancy/migrations/0007_remove_tenant_tenantgroup_slug.py +20 -0
  840. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  841. nautobot/tenancy/models.py +0 -30
  842. nautobot/tenancy/navigation.py +6 -39
  843. nautobot/tenancy/tables.py +4 -4
  844. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  845. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -1
  846. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  847. nautobot/tenancy/tests/test_api.py +1 -12
  848. nautobot/tenancy/tests/test_filters.py +20 -12
  849. nautobot/tenancy/tests/test_views.py +11 -29
  850. nautobot/tenancy/urls.py +10 -10
  851. nautobot/tenancy/views.py +0 -3
  852. nautobot/ui/.eslintignore +6 -0
  853. nautobot/ui/.gitignore +10 -0
  854. nautobot/ui/.prettierignore +9 -0
  855. nautobot/ui/.prettierrc +4 -0
  856. nautobot/ui/README.md +33 -0
  857. nautobot/ui/app_imports.js.j2 +7 -0
  858. nautobot/ui/craco.config.js +46 -0
  859. nautobot/ui/jsconfig-base.json +11 -0
  860. nautobot/ui/jsconfig.json +5 -0
  861. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  862. nautobot/ui/package-lock.json +21451 -0
  863. nautobot/ui/package.json +70 -0
  864. nautobot/ui/public/index.html +47 -0
  865. nautobot/ui/public/logo192.png +0 -0
  866. nautobot/ui/public/logo512.png +0 -0
  867. nautobot/ui/public/manifest.json +25 -0
  868. nautobot/ui/public/nautobot_logo.svg +131 -0
  869. nautobot/ui/public/robots.txt +3 -0
  870. nautobot/ui/src/App.js +71 -0
  871. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  872. nautobot/ui/src/components/AppTab.js +40 -0
  873. nautobot/ui/src/components/Apps.js +60 -0
  874. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  875. nautobot/ui/src/components/HomePanel.js +58 -0
  876. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  877. nautobot/ui/src/components/Layout.js +53 -0
  878. nautobot/ui/src/components/LoadingWidget.js +25 -0
  879. nautobot/ui/src/components/Navbar.js +116 -0
  880. nautobot/ui/src/components/NotificationPopover.js +27 -0
  881. nautobot/ui/src/components/ObjectListTable.js +209 -0
  882. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  883. nautobot/ui/src/components/RouterButton.js +10 -0
  884. nautobot/ui/src/components/RouterLink.js +10 -0
  885. nautobot/ui/src/components/SidebarNav.js +147 -0
  886. nautobot/ui/src/components/Table.js +48 -0
  887. nautobot/ui/src/components/TableItem.js +71 -0
  888. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  889. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  890. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  891. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  892. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  893. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  894. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  895. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  896. nautobot/ui/src/components/pagination.js +93 -0
  897. nautobot/ui/src/components/paginator.js +79 -0
  898. nautobot/ui/src/components/paginator_form.js +43 -0
  899. nautobot/ui/src/components/usePagination.js +57 -0
  900. nautobot/ui/src/constants/apiPath.js +10 -0
  901. nautobot/ui/src/constants/icons.js +15 -0
  902. nautobot/ui/src/constants/size.js +15 -0
  903. nautobot/ui/src/index.js +65 -0
  904. nautobot/ui/src/reportWebVitals.js +15 -0
  905. nautobot/ui/src/router.js +77 -0
  906. nautobot/ui/src/utils/api.js +131 -0
  907. nautobot/ui/src/utils/app-import.js +15 -0
  908. nautobot/ui/src/utils/color.js +15 -0
  909. nautobot/ui/src/utils/date.js +14 -0
  910. nautobot/ui/src/utils/index.js +15 -0
  911. nautobot/ui/src/utils/navigation.js +32 -0
  912. nautobot/ui/src/utils/session.js +64 -0
  913. nautobot/ui/src/utils/store.js +242 -0
  914. nautobot/ui/src/utils/string.js +6 -0
  915. nautobot/ui/src/utils/url.js +4 -0
  916. nautobot/ui/src/views/Home.js +138 -0
  917. nautobot/ui/src/views/InstalledApps.js +80 -0
  918. nautobot/ui/src/views/Login.js +48 -0
  919. nautobot/ui/src/views/Logout.js +20 -0
  920. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  921. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  922. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  923. nautobot/ui/src/views/generic/GenericView.js +142 -0
  924. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  925. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  926. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  927. nautobot/users/admin.py +1 -1
  928. nautobot/users/api/serializers.py +51 -61
  929. nautobot/users/api/urls.py +1 -1
  930. nautobot/users/api/views.py +53 -2
  931. nautobot/users/migrations/0001_initial.py +0 -1
  932. nautobot/users/migrations/0002_token_ordering_by_created.py +0 -1
  933. nautobot/users/migrations/0003_alter_user_options.py +0 -1
  934. nautobot/users/migrations/0004_alter_user_managers.py +0 -1
  935. nautobot/users/tests/test_api.py +109 -28
  936. nautobot/users/tests/test_filters.py +0 -4
  937. nautobot/users/tests/test_models.py +0 -1
  938. nautobot/users/views.py +0 -7
  939. nautobot/virtualization/api/serializers.py +18 -132
  940. nautobot/virtualization/api/urls.py +1 -1
  941. nautobot/virtualization/api/views.py +1 -22
  942. nautobot/virtualization/choices.py +0 -2
  943. nautobot/virtualization/filters.py +12 -7
  944. nautobot/virtualization/forms.py +21 -117
  945. nautobot/virtualization/migrations/0001_initial.py +0 -1
  946. nautobot/virtualization/migrations/0002_virtualmachine_local_context_schema.py +0 -1
  947. nautobot/virtualization/migrations/0003_vminterface_verbose_name.py +0 -1
  948. nautobot/virtualization/migrations/0004_auto_slug.py +0 -1
  949. nautobot/virtualization/migrations/0005_add_natural_indexing.py +0 -1
  950. nautobot/virtualization/migrations/0006_vminterface_status.py +0 -1
  951. nautobot/virtualization/migrations/0007_vminterface_status_data_migration.py +0 -1
  952. nautobot/virtualization/migrations/0008_vminterface_parent.py +0 -1
  953. nautobot/virtualization/migrations/0009_cluster_location.py +0 -1
  954. nautobot/virtualization/migrations/0010_vminterface_mac_address_data_migration.py +0 -1
  955. nautobot/virtualization/migrations/0011_alter_vminterface_mac_address.py +0 -1
  956. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -2
  957. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -12
  958. nautobot/virtualization/migrations/0014_rename_virtualmachine_roles.py +0 -1
  959. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -2
  960. nautobot/virtualization/migrations/0016_remove_site_foreign_key_from_cluster_class.py +0 -1
  961. nautobot/virtualization/migrations/0017_created_datetime.py +0 -1
  962. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -2
  963. nautobot/virtualization/migrations/0019_vminterface_ip_addresses_m2m.py +0 -1
  964. nautobot/virtualization/migrations/0020_remove_clustergroup_clustertype_slug.py +20 -0
  965. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  966. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  967. nautobot/virtualization/migrations/0023_ipam__namespaces.py +25 -0
  968. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  969. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  970. nautobot/virtualization/models.py +39 -131
  971. nautobot/virtualization/navigation.py +18 -99
  972. nautobot/virtualization/tables.py +4 -4
  973. nautobot/virtualization/templates/virtualization/virtualmachine.html +13 -2
  974. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  975. nautobot/virtualization/tests/test_api.py +42 -52
  976. nautobot/virtualization/tests/test_filters.py +98 -75
  977. nautobot/virtualization/tests/test_models.py +36 -13
  978. nautobot/virtualization/tests/test_views.py +68 -73
  979. nautobot/virtualization/urls.py +10 -10
  980. nautobot/virtualization/views.py +8 -14
  981. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +15 -22
  982. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +987 -834
  983. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  984. nautobot/circuits/api/nested_serializers.py +0 -69
  985. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  986. nautobot/dcim/api/nested_serializers.py +0 -356
  987. nautobot/dcim/templates/dcim/device_import.html +0 -5
  988. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  989. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  990. nautobot/extras/api/nested_serializers.py +0 -353
  991. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -42
  992. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -47
  993. nautobot/extras/reports.py +0 -60
  994. nautobot/extras/scripts.py +0 -72
  995. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  996. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  997. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  998. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  999. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  1000. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  1001. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  1002. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  1003. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  1004. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -19
  1005. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  1006. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  1007. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  1008. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  1009. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  1010. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  1011. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  1012. nautobot/ipam/api/nested_serializers.py +0 -143
  1013. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js +0 -29
  1014. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js.map +0 -8
  1015. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js +0 -18
  1016. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js.map +0 -8
  1017. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css +0 -1
  1018. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css.map +0 -1
  1019. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css +0 -1
  1020. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css.map +0 -1
  1021. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css +0 -1
  1022. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css.map +0 -1
  1023. nautobot/tenancy/api/nested_serializers.py +0 -31
  1024. nautobot/users/api/nested_serializers.py +0 -67
  1025. nautobot/virtualization/api/nested_serializers.py +0 -65
  1026. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  1027. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  1028. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  1029. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -3,32 +3,33 @@ import logging
3
3
  from django.conf import settings
4
4
  from django.contrib.contenttypes.models import ContentType
5
5
  from django.core.exceptions import ObjectDoesNotExist
6
- from django.urls import NoReverseMatch
7
6
  from drf_spectacular.utils import extend_schema_field
8
7
  from rest_framework import serializers
9
- from rest_framework.reverse import reverse
10
8
 
11
9
  from nautobot.core.api import (
10
+ BaseModelSerializer,
12
11
  ChoiceField,
13
12
  ContentTypeField,
14
- SerializedPKRelatedField,
13
+ CustomFieldModelSerializerMixin,
14
+ NautobotModelSerializer,
15
+ NotesSerializerMixin,
16
+ RelationshipModelSerializerMixin,
15
17
  ValidatedModelSerializer,
16
18
  )
17
19
  from nautobot.core.api.exceptions import SerializerNotFound
18
- from nautobot.core.api.mixins import LimitQuerysetChoicesSerializerMixin
19
- from nautobot.core.api.serializers import BaseModelSerializer, PolymorphicProxySerializer
20
- from nautobot.core.api.utils import get_serializer_for_model, get_serializers_for_models
20
+ from nautobot.core.api.serializers import PolymorphicProxySerializer
21
+ from nautobot.core.api.utils import (
22
+ get_nested_serializer_depth,
23
+ get_serializers_for_models,
24
+ return_nested_serializer_data_based_on_depth,
25
+ )
21
26
  from nautobot.core.models.utils import get_all_concrete_models
22
- from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
23
- from nautobot.core.utils.lookup import get_route_for_model
24
- from nautobot.dcim.api.nested_serializers import (
25
- NestedDeviceSerializer,
26
- NestedDeviceTypeSerializer,
27
- NestedLocationSerializer,
28
- NestedPlatformSerializer,
29
- NestedRackSerializer,
27
+ from nautobot.dcim.api.serializers import (
28
+ DeviceSerializer,
29
+ LocationSerializer,
30
+ RackSerializer,
30
31
  )
31
- from nautobot.dcim.models import DeviceType, Location, Platform
32
+ from nautobot.extras import choices, models
32
33
  from nautobot.extras.choices import (
33
34
  CustomFieldFilterLogicChoices,
34
35
  CustomFieldTypeChoices,
@@ -36,6 +37,9 @@ from nautobot.extras.choices import (
36
37
  JobResultStatusChoices,
37
38
  ObjectChangeActionChoices,
38
39
  )
40
+ from nautobot.extras.api.mixins import (
41
+ TaggedModelSerializerMixin,
42
+ )
39
43
  from nautobot.extras.datasources import get_datasource_content_choices
40
44
  from nautobot.extras.models import (
41
45
  ComputedField,
@@ -70,54 +74,8 @@ from nautobot.extras.models import (
70
74
  )
71
75
  from nautobot.extras.models.mixins import NotesMixin
72
76
  from nautobot.extras.utils import ChangeLoggedModelsQuery, FeatureQuery, RoleModelsQuery, TaggableClassesQuery
73
- from nautobot.tenancy.api.nested_serializers import (
74
- NestedTenantSerializer,
75
- NestedTenantGroupSerializer,
76
- )
77
- from nautobot.tenancy.models import Tenant, TenantGroup
78
- from nautobot.users.api.nested_serializers import NestedUserSerializer
79
- from nautobot.virtualization.api.nested_serializers import (
80
- NestedClusterGroupSerializer,
81
- NestedClusterSerializer,
82
- )
83
- from nautobot.virtualization.models import Cluster, ClusterGroup
84
-
85
- from .customfields import CustomFieldModelSerializerMixin
86
- from .fields import MultipleChoiceJSONField, RoleSerializerField, StatusSerializerField
87
- from .relationships import RelationshipModelSerializerMixin
88
-
89
- # Not all of these variable(s) are not actually used anywhere in this file, but required for the
90
- # automagically replacing a Serializer with its corresponding NestedSerializer.
91
- from .nested_serializers import ( # noqa: F401
92
- NestedComputedFieldSerializer,
93
- NestedConfigContextSchemaSerializer,
94
- NestedConfigContextSerializer,
95
- NestedCustomFieldChoiceSerializer,
96
- NestedCustomFieldSerializer,
97
- NestedCustomLinkSerializer,
98
- NestedDynamicGroupSerializer,
99
- NestedDynamicGroupMembershipSerializer,
100
- NestedExportTemplateSerializer,
101
- NestedGitRepositorySerializer,
102
- NestedGraphQLQuerySerializer,
103
- NestedImageAttachmentSerializer,
104
- NestedJobButtonSerializer,
105
- NestedJobHookSerializer,
106
- NestedJobSerializer,
107
- NestedJobResultSerializer,
108
- NestedNoteSerializer,
109
- NestedRelationshipAssociationSerializer,
110
- NestedRelationshipSerializer,
111
- NestedRoleSerializer,
112
- NestedScheduledJobSerializer,
113
- NestedScheduledJobCreationSerializer,
114
- NestedSecretSerializer,
115
- NestedSecretsGroupSerializer,
116
- NestedSecretsGroupAssociationSerializer,
117
- NestedStatusSerializer,
118
- NestedTagSerializer,
119
- NestedWebhookSerializer,
120
- )
77
+
78
+ from .fields import MultipleChoiceJSONField
121
79
 
122
80
  #
123
81
  # Mixins and Base Classes
@@ -126,130 +84,19 @@ from .nested_serializers import ( # noqa: F401
126
84
  logger = logging.getLogger(__name__)
127
85
 
128
86
 
129
- class NotesSerializerMixin(BaseModelSerializer):
130
- """Extend Serializer with a `notes` field."""
131
-
132
- notes_url = serializers.SerializerMethodField()
133
-
134
- def get_field_names(self, declared_fields, info):
135
- """Ensure that fields includes "notes_url" field if applicable."""
136
- fields = list(super().get_field_names(declared_fields, info))
137
- if hasattr(self.Meta.model, "notes"):
138
- self.extend_field_names(fields, "notes_url")
139
- return fields
140
-
141
- @extend_schema_field(serializers.URLField())
142
- def get_notes_url(self, instance):
143
- try:
144
- notes_url = get_route_for_model(instance, "notes", api=True)
145
- return reverse(notes_url, args=[instance.id], request=self.context["request"])
146
- except NoReverseMatch:
147
- model_name = type(instance).__name__
148
- logger.warning(
149
- (
150
- f"Notes feature is not available for model {model_name}. "
151
- "Please make sure to: "
152
- f"1. Include NotesMixin from nautobot.extras.model.mixins in the {model_name} class definition "
153
- f"2. Include NotesViewSetMixin from nautobot.extras.api.mixins in the {model_name}ViewSet "
154
- "before including NotesSerializerMixin in the model serializer"
155
- )
156
- )
157
-
158
- return None
159
-
160
-
161
- class NautobotModelSerializer(
162
- RelationshipModelSerializerMixin, CustomFieldModelSerializerMixin, NotesSerializerMixin, ValidatedModelSerializer
163
- ):
164
- """Base class to use for serializers based on OrganizationalModel or PrimaryModel.
165
-
166
- Can also be used for models derived from BaseModel, so long as they support custom fields and relationships.
167
- """
168
-
169
-
170
- class StatusModelSerializerMixin(BaseModelSerializer):
171
- """Mixin to add `status` choice field to model serializers."""
172
-
173
- status = StatusSerializerField(required=True)
174
-
175
- def get_field_names(self, declared_fields, info):
176
- """Ensure that "status" field is always present."""
177
- fields = list(super().get_field_names(declared_fields, info))
178
- self.extend_field_names(fields, "status")
179
- return fields
180
-
181
-
182
- class TagSerializerField(LimitQuerysetChoicesSerializerMixin, NestedTagSerializer):
183
- """NestedSerializer field for `Tag` object fields."""
184
-
185
-
186
- class TaggedModelSerializerMixin(BaseModelSerializer):
187
- tags = TagSerializerField(many=True, required=False)
188
-
189
- def get_field_names(self, declared_fields, info):
190
- """Ensure that 'tags' field is always present."""
191
- fields = list(super().get_field_names(declared_fields, info))
192
- self.extend_field_names(fields, "tags")
193
- return fields
194
-
195
- def create(self, validated_data):
196
- tags = validated_data.pop("tags", None)
197
- instance = super().create(validated_data)
198
-
199
- if tags is not None:
200
- return self._save_tags(instance, tags)
201
- return instance
202
-
203
- def update(self, instance, validated_data):
204
- tags = validated_data.pop("tags", None)
205
-
206
- # Cache tags on instance for change logging
207
- instance._tags = tags or []
208
-
209
- instance = super().update(instance, validated_data)
210
-
211
- if tags is not None:
212
- return self._save_tags(instance, tags)
213
- return instance
214
-
215
- def _save_tags(self, instance, tags):
216
- if tags:
217
- instance.tags.set([t.name for t in tags])
218
- else:
219
- instance.tags.clear()
220
-
221
- return instance
222
-
223
-
224
- # TODO: remove in 2.2
225
- @class_deprecated_in_favor_of(TaggedModelSerializerMixin)
226
- class TaggedObjectSerializer(TaggedModelSerializerMixin):
227
- pass
228
-
229
-
230
87
  #
231
88
  # Computed Fields
232
89
  #
233
90
 
234
91
 
235
92
  class ComputedFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
236
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:computedfield-detail")
237
93
  content_type = ContentTypeField(
238
94
  queryset=ContentType.objects.filter(FeatureQuery("custom_fields").get_query()).order_by("app_label", "model"),
239
95
  )
240
96
 
241
97
  class Meta:
242
98
  model = ComputedField
243
- fields = (
244
- "url",
245
- "slug",
246
- "label",
247
- "description",
248
- "content_type",
249
- "template",
250
- "fallback_value",
251
- "weight",
252
- )
99
+ fields = "__all__"
253
100
 
254
101
 
255
102
  #
@@ -257,8 +104,7 @@ class ComputedFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
257
104
  #
258
105
 
259
106
 
260
- class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
261
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:configcontext-detail")
107
+ class ConfigContextSerializer(ValidatedModelSerializer, TaggedModelSerializerMixin, NotesSerializerMixin):
262
108
  owner_content_type = ContentTypeField(
263
109
  queryset=ContentType.objects.filter(FeatureQuery("config_context_owners").get_query()),
264
110
  required=False,
@@ -266,63 +112,6 @@ class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
266
112
  default=None,
267
113
  )
268
114
  owner = serializers.SerializerMethodField(read_only=True)
269
- config_context_schema = NestedConfigContextSchemaSerializer(required=False, allow_null=True)
270
- locations = SerializedPKRelatedField(
271
- queryset=Location.objects.all(),
272
- serializer=NestedLocationSerializer,
273
- required=False,
274
- many=True,
275
- )
276
- roles = SerializedPKRelatedField(
277
- queryset=Role.objects.all(),
278
- serializer=NestedRoleSerializer,
279
- required=False,
280
- many=True,
281
- )
282
- device_types = SerializedPKRelatedField(
283
- queryset=DeviceType.objects.all(),
284
- serializer=NestedDeviceTypeSerializer,
285
- required=False,
286
- many=True,
287
- )
288
- platforms = SerializedPKRelatedField(
289
- queryset=Platform.objects.all(),
290
- serializer=NestedPlatformSerializer,
291
- required=False,
292
- many=True,
293
- )
294
- cluster_groups = SerializedPKRelatedField(
295
- queryset=ClusterGroup.objects.all(),
296
- serializer=NestedClusterGroupSerializer,
297
- required=False,
298
- many=True,
299
- )
300
- clusters = SerializedPKRelatedField(
301
- queryset=Cluster.objects.all(),
302
- serializer=NestedClusterSerializer,
303
- required=False,
304
- many=True,
305
- )
306
- tenant_groups = SerializedPKRelatedField(
307
- queryset=TenantGroup.objects.all(),
308
- serializer=NestedTenantGroupSerializer,
309
- required=False,
310
- many=True,
311
- )
312
- tenants = SerializedPKRelatedField(
313
- queryset=Tenant.objects.all(),
314
- serializer=NestedTenantSerializer,
315
- required=False,
316
- many=True,
317
- )
318
- tags = serializers.SlugRelatedField(queryset=Tag.objects.all(), slug_field="slug", required=False, many=True)
319
-
320
- dynamic_groups = SerializedPKRelatedField(
321
- queryset=DynamicGroup.objects.all(),
322
- serializer=NestedDynamicGroupSerializer,
323
- required=False,
324
- many=True,
325
- )
326
115
 
327
116
  # Conditional enablement of dynamic groups filtering
328
117
  def __init__(self, *args, **kwargs):
@@ -333,45 +122,21 @@ class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
333
122
 
334
123
  class Meta:
335
124
  model = ConfigContext
336
- fields = [
337
- "url",
338
- "name",
339
- "owner_content_type",
340
- "owner_object_id",
341
- "owner",
342
- "weight",
343
- "description",
344
- "config_context_schema",
345
- "is_active",
346
- "locations",
347
- "roles",
348
- "device_types",
349
- "platforms",
350
- "cluster_groups",
351
- "clusters",
352
- "tenant_groups",
353
- "tenants",
354
- "tags",
355
- "dynamic_groups",
356
- "data",
357
- ]
125
+ fields = "__all__"
358
126
 
359
127
  @extend_schema_field(
360
128
  PolymorphicProxySerializer(
361
129
  component_name="ConfigContextOwner",
362
130
  resource_type_field_name="object_type",
363
- serializers=lambda: get_serializers_for_models(
364
- FeatureQuery("config_context_owners").list_subclasses(), prefix="Nested"
365
- ),
131
+ serializers=lambda: get_serializers_for_models(FeatureQuery("config_context_owners").list_subclasses()),
366
132
  allow_null=True,
367
133
  )
368
134
  )
369
135
  def get_owner(self, obj):
370
136
  if obj.owner is None:
371
137
  return None
372
- serializer = get_serializer_for_model(obj.owner, prefix="Nested")
373
- context = {"request": self.context["request"]}
374
- return serializer(obj.owner, context=context).data
138
+ depth = get_nested_serializer_depth(self)
139
+ return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
375
140
 
376
141
 
377
142
  #
@@ -380,7 +145,6 @@ class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
380
145
 
381
146
 
382
147
  class ConfigContextSchemaSerializer(NautobotModelSerializer):
383
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:configcontextschema-detail")
384
148
  owner_content_type = ContentTypeField(
385
149
  queryset=ContentType.objects.filter(FeatureQuery("config_context_owners").get_query()),
386
150
  required=False,
@@ -391,33 +155,21 @@ class ConfigContextSchemaSerializer(NautobotModelSerializer):
391
155
 
392
156
  class Meta:
393
157
  model = ConfigContextSchema
394
- fields = [
395
- "url",
396
- "name",
397
- "slug",
398
- "owner_content_type",
399
- "owner_object_id",
400
- "owner",
401
- "description",
402
- "data_schema",
403
- ]
158
+ fields = "__all__"
404
159
 
405
160
  @extend_schema_field(
406
161
  PolymorphicProxySerializer(
407
162
  component_name="ConfigContextSchemaOwner",
408
163
  resource_type_field_name="object_type",
409
- serializers=lambda: get_serializers_for_models(
410
- FeatureQuery("config_context_owners").list_subclasses(), prefix="Nested"
411
- ),
164
+ serializers=lambda: get_serializers_for_models(FeatureQuery("config_context_owners").list_subclasses()),
412
165
  allow_null=True,
413
166
  )
414
167
  )
415
168
  def get_owner(self, obj):
416
169
  if obj.owner is None:
417
170
  return None
418
- serializer = get_serializer_for_model(obj.owner, prefix="Nested")
419
- context = {"request": self.context["request"]}
420
- return serializer(obj.owner, context=context).data
171
+ depth = get_nested_serializer_depth(self)
172
+ return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
421
173
 
422
174
 
423
175
  #
@@ -431,7 +183,7 @@ class ContentTypeSerializer(BaseModelSerializer):
431
183
 
432
184
  class Meta:
433
185
  model = ContentType
434
- fields = ["url", "app_label", "model"]
186
+ fields = "__all__"
435
187
 
436
188
  @extend_schema_field(serializers.CharField)
437
189
  def get_display(self, obj):
@@ -444,7 +196,6 @@ class ContentTypeSerializer(BaseModelSerializer):
444
196
 
445
197
 
446
198
  class CustomFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
447
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:customfield-detail")
448
199
  content_types = ContentTypeField(
449
200
  queryset=ContentType.objects.filter(FeatureQuery("custom_fields").get_query()),
450
201
  many=True,
@@ -455,30 +206,13 @@ class CustomFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
455
206
 
456
207
  class Meta:
457
208
  model = CustomField
458
- fields = [
459
- "url",
460
- "content_types",
461
- "type",
462
- "label",
463
- "key",
464
- "description",
465
- "required",
466
- "filter_logic",
467
- "default",
468
- "weight",
469
- "validation_minimum",
470
- "validation_maximum",
471
- "validation_regex",
472
- ]
209
+ fields = "__all__"
473
210
 
474
211
 
475
212
  class CustomFieldChoiceSerializer(ValidatedModelSerializer):
476
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:customfieldchoice-detail")
477
- custom_field = NestedCustomFieldSerializer()
478
-
479
213
  class Meta:
480
214
  model = CustomFieldChoice
481
- fields = ["url", "custom_field", "value", "weight"]
215
+ fields = "__all__"
482
216
 
483
217
 
484
218
  #
@@ -487,24 +221,13 @@ class CustomFieldChoiceSerializer(ValidatedModelSerializer):
487
221
 
488
222
 
489
223
  class CustomLinkSerializer(ValidatedModelSerializer, NotesSerializerMixin):
490
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:customlink-detail")
491
224
  content_type = ContentTypeField(
492
225
  queryset=ContentType.objects.filter(FeatureQuery("custom_links").get_query()).order_by("app_label", "model"),
493
226
  )
494
227
 
495
228
  class Meta:
496
229
  model = CustomLink
497
- fields = (
498
- "url",
499
- "target_url",
500
- "name",
501
- "content_type",
502
- "text",
503
- "weight",
504
- "group_name",
505
- "button_class",
506
- "new_window",
507
- )
230
+ fields = "__all__"
508
231
 
509
232
 
510
233
  #
@@ -512,37 +235,24 @@ class CustomLinkSerializer(ValidatedModelSerializer, NotesSerializerMixin):
512
235
  #
513
236
 
514
237
 
238
+ class DynamicGroupMembershipSerializer(ValidatedModelSerializer):
239
+ class Meta:
240
+ model = DynamicGroupMembership
241
+ fields = "__all__"
242
+
243
+
515
244
  class DynamicGroupSerializer(NautobotModelSerializer):
516
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:dynamicgroup-detail")
517
245
  content_type = ContentTypeField(
518
246
  queryset=ContentType.objects.filter(FeatureQuery("dynamic_groups").get_query()).order_by("app_label", "model"),
519
247
  )
520
- # Read-only because m2m is hard. Easier to just create # `DynamicGroupMemberships` explicitly
521
- # using their own endpoint at /api/extras/dynamic-group-memberships/.
522
- children = NestedDynamicGroupMembershipSerializer(source="dynamic_group_memberships", read_only=True, many=True)
523
248
 
524
249
  class Meta:
525
250
  model = DynamicGroup
526
- fields = [
527
- "url",
528
- "name",
529
- "slug",
530
- "description",
531
- "content_type",
532
- "filter",
533
- "children",
534
- ]
535
- extra_kwargs = {"filter": {"read_only": False}}
536
-
537
-
538
- class DynamicGroupMembershipSerializer(ValidatedModelSerializer):
539
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:dynamicgroupmembership-detail")
540
- group = NestedDynamicGroupSerializer()
541
- parent_group = NestedDynamicGroupSerializer()
542
-
543
- class Meta:
544
- model = DynamicGroupMembership
545
- fields = ["url", "group", "parent_group", "operator", "weight"]
251
+ fields = "__all__"
252
+ extra_kwargs = {
253
+ "children": {"source": "dynamic_group_memberships", "read_only": True},
254
+ "filter": {"read_only": False},
255
+ }
546
256
 
547
257
 
548
258
  #
@@ -552,7 +262,6 @@ class DynamicGroupMembershipSerializer(ValidatedModelSerializer):
552
262
 
553
263
  # TODO: export-templates don't support custom-fields, is this omission intentional?
554
264
  class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelSerializer, NotesSerializerMixin):
555
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:exporttemplate-detail")
556
265
  content_type = ContentTypeField(
557
266
  queryset=ContentType.objects.filter(FeatureQuery("export_templates").get_query()),
558
267
  )
@@ -566,35 +275,21 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
566
275
 
567
276
  class Meta:
568
277
  model = ExportTemplate
569
- fields = [
570
- "url",
571
- "content_type",
572
- "owner_content_type",
573
- "owner_object_id",
574
- "owner",
575
- "name",
576
- "description",
577
- "template_code",
578
- "mime_type",
579
- "file_extension",
580
- ]
278
+ fields = "__all__"
581
279
 
582
280
  @extend_schema_field(
583
281
  PolymorphicProxySerializer(
584
282
  component_name="ExportTemplateOwner",
585
283
  resource_type_field_name="object_type",
586
- serializers=lambda: get_serializers_for_models(
587
- FeatureQuery("export_template_owners").list_subclasses(), prefix="Nested"
588
- ),
284
+ serializers=lambda: get_serializers_for_models(FeatureQuery("export_template_owners").list_subclasses()),
589
285
  allow_null=True,
590
286
  )
591
287
  )
592
288
  def get_owner(self, obj):
593
289
  if obj.owner is None:
594
290
  return None
595
- serializer = get_serializer_for_model(obj.owner, prefix="Nested")
596
- context = {"request": self.context["request"]}
597
- return serializer(obj.owner, context=context).data
291
+ depth = get_nested_serializer_depth(self)
292
+ return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
598
293
 
599
294
 
600
295
  #
@@ -605,10 +300,6 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
605
300
  class GitRepositorySerializer(NautobotModelSerializer):
606
301
  """Git repositories defined as a data source."""
607
302
 
608
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:gitrepository-detail")
609
-
610
- secrets_group = NestedSecretsGroupSerializer(required=False, allow_null=True)
611
-
612
303
  provided_contents = MultipleChoiceJSONField(
613
304
  choices=lambda: get_datasource_content_choices("extras.gitrepository"),
614
305
  allow_blank=True,
@@ -617,23 +308,7 @@ class GitRepositorySerializer(NautobotModelSerializer):
617
308
 
618
309
  class Meta:
619
310
  model = GitRepository
620
- fields = [
621
- "url",
622
- "name",
623
- "slug",
624
- "remote_url",
625
- "branch",
626
- "secrets_group",
627
- "current_head",
628
- "provided_contents",
629
- ]
630
-
631
- def validate(self, data):
632
- """
633
- Add the originating Request as a parameter to be passed when creating/updating a GitRepository.
634
- """
635
- data["request"] = self.context["request"]
636
- return super().validate(data)
311
+ fields = "__all__"
637
312
 
638
313
 
639
314
  #
@@ -642,18 +317,11 @@ class GitRepositorySerializer(NautobotModelSerializer):
642
317
 
643
318
 
644
319
  class GraphQLQuerySerializer(ValidatedModelSerializer, NotesSerializerMixin):
645
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:graphqlquery-detail")
646
320
  variables = serializers.DictField(required=False, allow_null=True, default={})
647
321
 
648
322
  class Meta:
649
323
  model = GraphQLQuery
650
- fields = (
651
- "url",
652
- "name",
653
- "slug",
654
- "query",
655
- "variables",
656
- )
324
+ fields = "__all__"
657
325
 
658
326
 
659
327
  class GraphQLQueryInputSerializer(serializers.Serializer):
@@ -670,23 +338,11 @@ class GraphQLQueryOutputSerializer(serializers.Serializer):
670
338
 
671
339
 
672
340
  class ImageAttachmentSerializer(ValidatedModelSerializer):
673
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:imageattachment-detail")
674
341
  content_type = ContentTypeField(queryset=ContentType.objects.all())
675
- parent = serializers.SerializerMethodField(read_only=True)
676
342
 
677
343
  class Meta:
678
344
  model = ImageAttachment
679
- fields = [
680
- "url",
681
- "content_type",
682
- "object_id",
683
- "parent",
684
- "name",
685
- "image",
686
- "image_height",
687
- "image_width",
688
- "created",
689
- ]
345
+ fields = "__all__"
690
346
 
691
347
  def validate(self, data):
692
348
  # Validate that the parent object exists
@@ -705,15 +361,15 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
705
361
  component_name="ImageAttachmentParent",
706
362
  resource_type_field_name="object_type",
707
363
  serializers=[
708
- NestedDeviceSerializer,
709
- NestedLocationSerializer,
710
- NestedRackSerializer,
364
+ DeviceSerializer,
365
+ LocationSerializer,
366
+ RackSerializer,
711
367
  ],
712
368
  )
713
369
  )
714
370
  def get_parent(self, obj):
715
- serializer = get_serializer_for_model(obj.parent, prefix="Nested")
716
- return serializer(obj.parent, context={"request": self.context["request"]}).data
371
+ depth = get_nested_serializer_depth(self)
372
+ return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.parent, "parent")
717
373
 
718
374
 
719
375
  #
@@ -722,44 +378,9 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
722
378
 
723
379
 
724
380
  class JobSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
725
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:job-detail")
726
-
727
381
  class Meta:
728
382
  model = Job
729
- fields = [
730
- "url",
731
- "source",
732
- "module_name",
733
- "job_class_name",
734
- "grouping",
735
- "grouping_override",
736
- "name",
737
- "name_override",
738
- "slug",
739
- "description",
740
- "description_override",
741
- "installed",
742
- "enabled",
743
- "is_job_hook_receiver",
744
- "is_job_button_receiver",
745
- "has_sensitive_variables",
746
- "has_sensitive_variables_override",
747
- "approval_required",
748
- "approval_required_override",
749
- "commit_default",
750
- "commit_default_override",
751
- "hidden",
752
- "hidden_override",
753
- "read_only",
754
- "read_only_override",
755
- "soft_time_limit",
756
- "soft_time_limit_override",
757
- "time_limit",
758
- "time_limit_override",
759
- "task_queues",
760
- "task_queues_override",
761
- "tags",
762
- ]
383
+ fields = "__all__"
763
384
 
764
385
  def validate(self, data):
765
386
  # note no validation for on creation of jobs because we do not support user creation of Job records via API
@@ -790,7 +411,6 @@ class JobVariableSerializer(serializers.Serializer):
790
411
  help_text = serializers.CharField(read_only=True, required=False)
791
412
  default = serializers.JSONField(read_only=True, required=False)
792
413
  required = serializers.BooleanField(read_only=True, required=False)
793
-
794
414
  min_length = serializers.IntegerField(read_only=True, required=False)
795
415
  max_length = serializers.IntegerField(read_only=True, required=False)
796
416
  min_value = serializers.IntegerField(read_only=True, required=False)
@@ -799,11 +419,17 @@ class JobVariableSerializer(serializers.Serializer):
799
419
  model = serializers.CharField(read_only=True, required=False)
800
420
 
801
421
 
802
- class JobRunResponseSerializer(serializers.Serializer):
803
- """Serializer representing responses from the JobModelViewSet.run() POST endpoint."""
422
+ #
423
+ # Scheduled Jobs
424
+ #
425
+
804
426
 
805
- schedule = NestedScheduledJobSerializer(read_only=True, required=False)
806
- job_result = NestedJobResultSerializer(read_only=True, required=False)
427
+ class ScheduledJobSerializer(BaseModelSerializer):
428
+ # start_time = serializers.DateTimeField(format=None, required=False)
429
+
430
+ class Meta:
431
+ model = ScheduledJob
432
+ fields = "__all__"
807
433
 
808
434
 
809
435
  #
@@ -812,63 +438,18 @@ class JobRunResponseSerializer(serializers.Serializer):
812
438
 
813
439
 
814
440
  class JobResultSerializer(CustomFieldModelSerializerMixin, BaseModelSerializer):
815
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:jobresult-detail")
816
- user = NestedUserSerializer(read_only=True)
817
441
  status = ChoiceField(choices=JobResultStatusChoices, read_only=True)
818
- job_model = NestedJobSerializer(read_only=True)
819
- obj_type = ContentTypeField(read_only=True)
820
- scheduled_job = NestedScheduledJobSerializer(read_only=True)
821
442
 
822
443
  class Meta:
823
444
  model = JobResult
824
- fields = [
825
- "url",
826
- "date_created",
827
- "date_done",
828
- "name",
829
- "job_model",
830
- "obj_type",
831
- "status",
832
- "user",
833
- "data",
834
- "task_id",
835
- "task_kwargs",
836
- "scheduled_job",
837
- ]
445
+ fields = "__all__"
838
446
 
839
447
 
840
- #
841
- # Scheduled Jobs
842
- #
843
-
844
-
845
- class ScheduledJobSerializer(BaseModelSerializer):
846
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:scheduledjob-detail")
847
- user = NestedUserSerializer(read_only=True)
848
- job_model = NestedJobSerializer(read_only=True)
849
- approved_by_user = NestedUserSerializer(read_only=True)
448
+ class JobRunResponseSerializer(serializers.Serializer):
449
+ """Serializer representing responses from the JobModelViewSet.run() POST endpoint."""
850
450
 
851
- class Meta:
852
- model = ScheduledJob
853
- fields = [
854
- "url",
855
- "name",
856
- "user",
857
- "job_model",
858
- "task",
859
- "interval",
860
- "queue",
861
- "job_class",
862
- "last_run_at",
863
- "total_run_count",
864
- "date_changed",
865
- "description",
866
- "user",
867
- "approved_by_user",
868
- "approval_required",
869
- "approved_at",
870
- "crontab",
871
- ]
451
+ schedule = ScheduledJobSerializer(read_only=True, required=False)
452
+ job_result = JobResultSerializer(read_only=True, required=False)
872
453
 
873
454
 
874
455
  #
@@ -889,7 +470,6 @@ class JobClassSerializer(serializers.Serializer):
889
470
  description = serializers.CharField(max_length=255, required=False, read_only=True)
890
471
  test_methods = serializers.ListField(child=serializers.CharField(max_length=255))
891
472
  vars = serializers.SerializerMethodField(read_only=True)
892
- result = NestedJobResultSerializer(required=False)
893
473
 
894
474
  @extend_schema_field(serializers.DictField)
895
475
  def get_vars(self, instance):
@@ -912,7 +492,6 @@ class JobClassDetailSerializer(JobClassSerializer):
912
492
 
913
493
 
914
494
  class JobHookSerializer(NautobotModelSerializer):
915
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:jobhook-detail")
916
495
  content_types = ContentTypeField(
917
496
  queryset=ChangeLoggedModelsQuery().as_queryset(),
918
497
  many=True,
@@ -920,17 +499,7 @@ class JobHookSerializer(NautobotModelSerializer):
920
499
 
921
500
  class Meta:
922
501
  model = JobHook
923
- fields = [
924
- "id",
925
- "url",
926
- "name",
927
- "content_types",
928
- "job",
929
- "enabled",
930
- "type_create",
931
- "type_update",
932
- "type_delete",
933
- ]
502
+ fields = "__all__"
934
503
 
935
504
  def validate(self, data):
936
505
  validated_data = super().validate(data)
@@ -950,17 +519,58 @@ class JobHookSerializer(NautobotModelSerializer):
950
519
  return validated_data
951
520
 
952
521
 
522
+ class JobCreationSerializer(BaseModelSerializer):
523
+ """
524
+ Nested serializer specifically for use with `JobInputSerializer.schedule`.
525
+
526
+ We don't use `WritableNestedSerializer` here because this is not used to look up
527
+ an existing `ScheduledJob`, but instead used to specify parameters for creating one.
528
+ """
529
+
530
+ url = serializers.HyperlinkedIdentityField(view_name="extras-api:scheduledjob-detail")
531
+ name = serializers.CharField(max_length=255, required=False)
532
+ start_time = serializers.DateTimeField(format=None, required=False)
533
+
534
+ class Meta:
535
+ model = ScheduledJob
536
+ fields = ["url", "name", "start_time", "interval", "crontab"]
537
+
538
+ def validate(self, data):
539
+ data = super().validate(data)
540
+
541
+ if data["interval"] in choices.JobExecutionType.SCHEDULE_CHOICES:
542
+ if "name" not in data:
543
+ raise serializers.ValidationError({"name": "Please provide a name for the job schedule."})
544
+
545
+ if ("start_time" not in data and data["interval"] != choices.JobExecutionType.TYPE_CUSTOM) or (
546
+ "start_time" in data and data["start_time"] < models.ScheduledJob.earliest_possible_time()
547
+ ):
548
+ raise serializers.ValidationError(
549
+ {
550
+ "start_time": "Please enter a valid date and time greater than or equal to the current date and time."
551
+ }
552
+ )
553
+
554
+ if data["interval"] == choices.JobExecutionType.TYPE_CUSTOM:
555
+ if data.get("crontab") is None:
556
+ raise serializers.ValidationError({"crontab": "Please enter a valid crontab."})
557
+ try:
558
+ models.ScheduledJob.get_crontab(data["crontab"])
559
+ except Exception as e:
560
+ raise serializers.ValidationError({"crontab": e})
561
+
562
+ return data
563
+
564
+
953
565
  class JobInputSerializer(serializers.Serializer):
954
566
  data = serializers.JSONField(required=False, default=dict)
955
- commit = serializers.BooleanField(required=False, default=None)
956
- schedule = NestedScheduledJobCreationSerializer(required=False)
567
+ schedule = JobCreationSerializer(required=False)
957
568
  task_queue = serializers.CharField(required=False, allow_blank=True)
958
569
 
959
570
 
960
571
  class JobMultiPartInputSerializer(serializers.Serializer):
961
572
  """JobMultiPartInputSerializer is a "flattened" version of JobInputSerializer for use with multipart/form-data submissions which only accept key-value pairs"""
962
573
 
963
- _commit = serializers.BooleanField(required=False, default=None)
964
574
  _schedule_name = serializers.CharField(max_length=255, required=False)
965
575
  _schedule_start_time = serializers.DateTimeField(format=None, required=False)
966
576
  _schedule_interval = ChoiceField(choices=JobExecutionType, required=False)
@@ -995,25 +605,9 @@ class JobMultiPartInputSerializer(serializers.Serializer):
995
605
 
996
606
 
997
607
  class JobLogEntrySerializer(BaseModelSerializer):
998
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:joblogentry-detail")
999
- display = serializers.SerializerMethodField()
1000
-
1001
608
  class Meta:
1002
609
  model = JobLogEntry
1003
- fields = [
1004
- "url",
1005
- "absolute_url",
1006
- "created",
1007
- "grouping",
1008
- "job_result",
1009
- "log_level",
1010
- "log_object",
1011
- "message",
1012
- ]
1013
-
1014
- @extend_schema_field(serializers.CharField)
1015
- def get_display(self, obj):
1016
- return obj.created.isoformat()
610
+ fields = "__all__"
1017
611
 
1018
612
 
1019
613
  #
@@ -1022,22 +616,11 @@ class JobLogEntrySerializer(BaseModelSerializer):
1022
616
 
1023
617
 
1024
618
  class JobButtonSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1025
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:jobbutton-detail")
1026
619
  content_types = ContentTypeField(queryset=ContentType.objects.all(), many=True)
1027
620
 
1028
621
  class Meta:
1029
622
  model = JobButton
1030
- fields = (
1031
- "url",
1032
- "job",
1033
- "name",
1034
- "content_types",
1035
- "text",
1036
- "weight",
1037
- "group_name",
1038
- "button_class",
1039
- "confirmation",
1040
- )
623
+ fields = "__all__"
1041
624
 
1042
625
 
1043
626
  #
@@ -1046,29 +629,19 @@ class JobButtonSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1046
629
 
1047
630
 
1048
631
  class NoteSerializer(BaseModelSerializer):
1049
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:note-detail")
1050
- user = NestedUserSerializer(read_only=True)
1051
632
  assigned_object_type = ContentTypeField(queryset=ContentType.objects.all())
1052
633
  assigned_object = serializers.SerializerMethodField()
1053
634
 
1054
635
  class Meta:
1055
636
  model = Note
1056
- fields = [
1057
- "url",
1058
- "user",
1059
- "user_name",
1060
- "assigned_object_type",
1061
- "assigned_object_id",
1062
- "assigned_object",
1063
- "note",
1064
- "slug",
1065
- ]
637
+ fields = "__all__"
638
+ list_display_fields = ["note", "assigned_object_type", "assigned_object_id", "user"]
1066
639
 
1067
640
  @extend_schema_field(
1068
641
  PolymorphicProxySerializer(
1069
642
  component_name="NoteAssignedObject",
1070
643
  resource_type_field_name="object_type",
1071
- serializers=lambda: get_serializers_for_models(get_all_concrete_models(NotesMixin), prefix="Nested"),
644
+ serializers=lambda: get_serializers_for_models(get_all_concrete_models(NotesMixin)),
1072
645
  allow_null=True,
1073
646
  )
1074
647
  )
@@ -1076,9 +649,10 @@ class NoteSerializer(BaseModelSerializer):
1076
649
  if obj.assigned_object is None:
1077
650
  return None
1078
651
  try:
1079
- serializer = get_serializer_for_model(obj.assigned_object, prefix="Nested")
1080
- context = {"request": self.context["request"]}
1081
- return serializer(obj.assigned_object, context=context).data
652
+ depth = get_nested_serializer_depth(self)
653
+ return return_nested_serializer_data_based_on_depth(
654
+ self, depth, obj, obj.assigned_object, "assigned_object"
655
+ )
1082
656
  except SerializerNotFound:
1083
657
  return None
1084
658
 
@@ -1093,34 +667,20 @@ class NoteInputSerializer(serializers.Serializer):
1093
667
 
1094
668
 
1095
669
  class ObjectChangeSerializer(BaseModelSerializer):
1096
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:objectchange-detail")
1097
- user = NestedUserSerializer(read_only=True)
1098
670
  action = ChoiceField(choices=ObjectChangeActionChoices, read_only=True)
1099
671
  changed_object_type = ContentTypeField(read_only=True)
1100
672
  changed_object = serializers.SerializerMethodField(read_only=True)
1101
673
 
1102
674
  class Meta:
1103
675
  model = ObjectChange
1104
- fields = [
1105
- "url",
1106
- "time",
1107
- "user",
1108
- "user_name",
1109
- "request_id",
1110
- "action",
1111
- "changed_object_type",
1112
- "changed_object_id",
1113
- "changed_object",
1114
- "object_data",
1115
- ]
676
+ fields = "__all__"
677
+ list_display_fields = ["changed_object_id", "related_object_id", "related_object_type", "user"]
1116
678
 
1117
679
  @extend_schema_field(
1118
680
  PolymorphicProxySerializer(
1119
681
  component_name="ObjectChangeChangedObject",
1120
682
  resource_type_field_name="object_type",
1121
- serializers=lambda: get_serializers_for_models(
1122
- ChangeLoggedModelsQuery().list_subclasses(), prefix="Nested"
1123
- ),
683
+ serializers=lambda: get_serializers_for_models(ChangeLoggedModelsQuery().list_subclasses()),
1124
684
  allow_null=True,
1125
685
  )
1126
686
  )
@@ -1130,15 +690,11 @@ class ObjectChangeSerializer(BaseModelSerializer):
1130
690
  """
1131
691
  if obj.changed_object is None:
1132
692
  return None
1133
-
1134
693
  try:
1135
- serializer = get_serializer_for_model(obj.changed_object, prefix="Nested")
694
+ depth = get_nested_serializer_depth(self)
695
+ return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.changed_object, "changed_object")
1136
696
  except SerializerNotFound:
1137
697
  return obj.object_repr
1138
- context = {"request": self.context["request"]}
1139
- data = serializer(obj.changed_object, context=context).data
1140
-
1141
- return data
1142
698
 
1143
699
 
1144
700
  #
@@ -1147,8 +703,6 @@ class ObjectChangeSerializer(BaseModelSerializer):
1147
703
 
1148
704
 
1149
705
  class RelationshipSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1150
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:relationship-detail")
1151
-
1152
706
  source_type = ContentTypeField(
1153
707
  queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()),
1154
708
  )
@@ -1159,27 +713,10 @@ class RelationshipSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1159
713
 
1160
714
  class Meta:
1161
715
  model = Relationship
1162
- fields = [
1163
- "url",
1164
- "name",
1165
- "slug",
1166
- "description",
1167
- "type",
1168
- "required_on",
1169
- "source_type",
1170
- "source_label",
1171
- "source_hidden",
1172
- "source_filter",
1173
- "destination_type",
1174
- "destination_label",
1175
- "destination_hidden",
1176
- "destination_filter",
1177
- ]
716
+ fields = "__all__"
1178
717
 
1179
718
 
1180
719
  class RelationshipAssociationSerializer(ValidatedModelSerializer):
1181
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:relationshipassociation-detail")
1182
-
1183
720
  source_type = ContentTypeField(
1184
721
  queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()),
1185
722
  )
@@ -1188,18 +725,9 @@ class RelationshipAssociationSerializer(ValidatedModelSerializer):
1188
725
  queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()),
1189
726
  )
1190
727
 
1191
- relationship = NestedRelationshipSerializer()
1192
-
1193
728
  class Meta:
1194
729
  model = RelationshipAssociation
1195
- fields = [
1196
- "url",
1197
- "relationship",
1198
- "source_type",
1199
- "source_id",
1200
- "destination_type",
1201
- "destination_id",
1202
- ]
730
+ fields = "__all__"
1203
731
 
1204
732
 
1205
733
  #
@@ -1207,22 +735,9 @@ class RelationshipAssociationSerializer(ValidatedModelSerializer):
1207
735
  #
1208
736
 
1209
737
 
1210
- class RoleModelSerializerMixin(BaseModelSerializer):
1211
- """Mixin to add `role` choice field to model serializers."""
1212
-
1213
- role = RoleSerializerField(required=False)
1214
-
1215
-
1216
- class RoleRequiredRoleModelSerializerMixin(BaseModelSerializer):
1217
- """Mixin to add `role` choice field to model serializers."""
1218
-
1219
- role = RoleSerializerField()
1220
-
1221
-
1222
738
  class RoleSerializer(NautobotModelSerializer):
1223
739
  """Serializer for `Role` objects."""
1224
740
 
1225
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:role-detail")
1226
741
  content_types = ContentTypeField(
1227
742
  queryset=RoleModelsQuery().as_queryset(),
1228
743
  many=True,
@@ -1230,14 +745,10 @@ class RoleSerializer(NautobotModelSerializer):
1230
745
 
1231
746
  class Meta:
1232
747
  model = Role
1233
- fields = [
1234
- "url",
1235
- "content_types",
1236
- "name",
1237
- "slug",
1238
- "color",
1239
- "weight",
1240
- ]
748
+ fields = "__all__"
749
+ extra_kwargs = {
750
+ "color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
751
+ }
1241
752
 
1242
753
 
1243
754
  #
@@ -1248,59 +759,33 @@ class RoleSerializer(NautobotModelSerializer):
1248
759
  class SecretSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
1249
760
  """Serializer for `Secret` objects."""
1250
761
 
1251
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:secret-detail")
1252
-
1253
762
  class Meta:
1254
763
  model = Secret
1255
- fields = [
1256
- "url",
1257
- "name",
1258
- "slug",
1259
- "description",
1260
- "provider",
1261
- "parameters",
1262
- ]
764
+ fields = "__all__"
1263
765
 
1264
766
 
1265
- class SecretsGroupSerializer(NautobotModelSerializer):
1266
- """Serializer for `SecretsGroup` objects."""
1267
-
1268
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:secretsgroup-detail")
1269
-
1270
- # TODO: it would be **awesome** if we could create/update SecretsGroupAssociations
1271
- # alongside creating/updating the base SecretsGroup, but since this is a ManyToManyField with
1272
- # a `through` table, that appears very non-trivial to implement. For now we have this as a
1273
- # read-only field; to create/update SecretsGroupAssociations you must make separate calls to the
1274
- # api/extras/secrets-group-associations/ REST endpoint as appropriate.
1275
- secrets = NestedSecretsGroupAssociationSerializer(source="secrets_group_associations", many=True, read_only=True)
767
+ class SecretsGroupAssociationSerializer(ValidatedModelSerializer):
768
+ """Serializer for `SecretsGroupAssociation` objects."""
1276
769
 
1277
770
  class Meta:
1278
- model = SecretsGroup
1279
- fields = [
1280
- "url",
1281
- "name",
1282
- "slug",
1283
- "description",
1284
- "secrets",
1285
- ]
1286
-
771
+ model = SecretsGroupAssociation
772
+ fields = "__all__"
1287
773
 
1288
- class SecretsGroupAssociationSerializer(ValidatedModelSerializer):
1289
- """Serializer for `SecretsGroupAssociation` objects."""
1290
774
 
1291
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:secretsgroupassociation-detail")
1292
- secrets_group = NestedSecretsGroupSerializer()
1293
- secret = NestedSecretSerializer()
775
+ class SecretsGroupSerializer(NautobotModelSerializer):
776
+ """Serializer for `SecretsGroup` objects."""
1294
777
 
1295
778
  class Meta:
1296
- model = SecretsGroupAssociation
1297
- fields = [
1298
- "url",
1299
- "secrets_group",
1300
- "access_type",
1301
- "secret_type",
1302
- "secret",
1303
- ]
779
+ model = SecretsGroup
780
+ fields = "__all__"
781
+ # TODO: it would be **awesome** if we could create/update SecretsGroupAssociations
782
+ # alongside creating/updating the base SecretsGroup, but since this is a ManyToManyField with
783
+ # a `through` table, that appears very non-trivial to implement. For now we have this as a
784
+ # read-only field; to create/update SecretsGroupAssociations you must make separate calls to the
785
+ # api/extras/secrets-group-associations/ REST endpoint as appropriate.
786
+ extra_kwargs = {
787
+ "secrets": {"source": "secrets_group_associations", "read_only": True},
788
+ }
1304
789
 
1305
790
 
1306
791
  #
@@ -1311,7 +796,6 @@ class SecretsGroupAssociationSerializer(ValidatedModelSerializer):
1311
796
  class StatusSerializer(NautobotModelSerializer):
1312
797
  """Serializer for `Status` objects."""
1313
798
 
1314
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:status-detail")
1315
799
  content_types = ContentTypeField(
1316
800
  queryset=ContentType.objects.filter(FeatureQuery("statuses").get_query()),
1317
801
  many=True,
@@ -1319,13 +803,10 @@ class StatusSerializer(NautobotModelSerializer):
1319
803
 
1320
804
  class Meta:
1321
805
  model = Status
1322
- fields = [
1323
- "url",
1324
- "content_types",
1325
- "name",
1326
- "slug",
1327
- "color",
1328
- ]
806
+ fields = "__all__"
807
+ extra_kwargs = {
808
+ "color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
809
+ }
1329
810
 
1330
811
 
1331
812
  #
@@ -1334,7 +815,6 @@ class StatusSerializer(NautobotModelSerializer):
1334
815
 
1335
816
 
1336
817
  class TagSerializer(NautobotModelSerializer):
1337
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:tag-detail")
1338
818
  tagged_items = serializers.IntegerField(read_only=True)
1339
819
  content_types = ContentTypeField(
1340
820
  queryset=TaggableClassesQuery().as_queryset(),
@@ -1344,15 +824,10 @@ class TagSerializer(NautobotModelSerializer):
1344
824
 
1345
825
  class Meta:
1346
826
  model = Tag
1347
- fields = [
1348
- "url",
1349
- "name",
1350
- "slug",
1351
- "color",
1352
- "description",
1353
- "tagged_items",
1354
- "content_types",
1355
- ]
827
+ fields = "__all__"
828
+ extra_kwargs = {
829
+ "color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
830
+ }
1356
831
 
1357
832
  def validate(self, data):
1358
833
  data = super().validate(data)
@@ -1374,7 +849,6 @@ class TagSerializer(NautobotModelSerializer):
1374
849
 
1375
850
 
1376
851
  class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1377
- url = serializers.HyperlinkedIdentityField(view_name="extras-api:webhook-detail")
1378
852
  content_types = ContentTypeField(
1379
853
  queryset=ContentType.objects.filter(FeatureQuery("webhooks").get_query()).order_by("app_label", "model"),
1380
854
  many=True,
@@ -1382,22 +856,7 @@ class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1382
856
 
1383
857
  class Meta:
1384
858
  model = Webhook
1385
- fields = [
1386
- "url",
1387
- "content_types",
1388
- "name",
1389
- "type_create",
1390
- "type_update",
1391
- "type_delete",
1392
- "payload_url",
1393
- "http_method",
1394
- "http_content_type",
1395
- "additional_headers",
1396
- "body_template",
1397
- "secret",
1398
- "ssl_verification",
1399
- "ca_file_path",
1400
- ]
859
+ fields = "__all__"
1401
860
 
1402
861
  def validate(self, data):
1403
862
  validated_data = super().validate(data)