nautobot 2.3.16__py3-none-any.whl → 2.4.0__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.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (721) hide show
  1. nautobot/__init__.py +15 -0
  2. nautobot/apps/__init__.py +1 -1
  3. nautobot/apps/api.py +8 -10
  4. nautobot/apps/change_logging.py +2 -2
  5. nautobot/apps/choices.py +4 -4
  6. nautobot/apps/config.py +32 -3
  7. nautobot/apps/events.py +19 -0
  8. nautobot/apps/exceptions.py +0 -2
  9. nautobot/apps/factory.py +2 -2
  10. nautobot/apps/filters.py +1 -1
  11. nautobot/apps/forms.py +20 -20
  12. nautobot/apps/graphql.py +2 -2
  13. nautobot/apps/jobs.py +8 -8
  14. nautobot/apps/models.py +19 -19
  15. nautobot/apps/tables.py +1 -1
  16. nautobot/apps/testing.py +10 -10
  17. nautobot/apps/ui.py +44 -9
  18. nautobot/apps/utils.py +7 -15
  19. nautobot/apps/views.py +8 -6
  20. nautobot/circuits/api/serializers.py +1 -0
  21. nautobot/circuits/api/views.py +4 -8
  22. nautobot/circuits/navigation.py +0 -57
  23. nautobot/circuits/templates/circuits/circuit_create.html +1 -7
  24. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
  25. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
  26. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
  27. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
  28. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
  29. nautobot/circuits/tests/integration/test_relationships.py +33 -24
  30. nautobot/circuits/tests/test_filters.py +4 -8
  31. nautobot/circuits/views.py +140 -23
  32. nautobot/cloud/api/views.py +6 -10
  33. nautobot/cloud/factory.py +4 -1
  34. nautobot/cloud/tests/test_filters.py +5 -4
  35. nautobot/cloud/views.py +0 -16
  36. nautobot/core/api/constants.py +11 -0
  37. nautobot/core/api/filter_backends.py +3 -9
  38. nautobot/core/api/metadata.py +28 -256
  39. nautobot/core/api/pagination.py +3 -2
  40. nautobot/core/api/renderers.py +3 -0
  41. nautobot/core/api/schema.py +13 -2
  42. nautobot/core/api/serializers.py +45 -259
  43. nautobot/core/api/urls.py +3 -4
  44. nautobot/core/api/utils.py +0 -62
  45. nautobot/core/api/views.py +99 -157
  46. nautobot/core/apps/__init__.py +22 -578
  47. nautobot/core/celery/__init__.py +13 -0
  48. nautobot/core/celery/schedulers.py +47 -2
  49. nautobot/core/choices.py +2 -2
  50. nautobot/core/cli/__init__.py +8 -0
  51. nautobot/core/constants.py +7 -0
  52. nautobot/core/events/__init__.py +116 -0
  53. nautobot/core/events/base.py +27 -0
  54. nautobot/core/events/exceptions.py +10 -0
  55. nautobot/core/events/redis_broker.py +48 -0
  56. nautobot/core/events/syslog_broker.py +19 -0
  57. nautobot/core/exceptions.py +0 -6
  58. nautobot/core/forms/__init__.py +19 -19
  59. nautobot/core/forms/fields.py +57 -9
  60. nautobot/core/forms/forms.py +33 -2
  61. nautobot/core/forms/utils.py +2 -1
  62. nautobot/core/graphql/schema.py +3 -1
  63. nautobot/core/jobs/__init__.py +24 -3
  64. nautobot/core/jobs/bulk_actions.py +248 -0
  65. nautobot/core/jobs/cleanup.py +1 -1
  66. nautobot/core/management/commands/generate_test_data.py +21 -0
  67. nautobot/core/middleware.py +16 -0
  68. nautobot/core/models/fields.py +11 -7
  69. nautobot/core/settings.py +68 -4
  70. nautobot/core/settings.yaml +99 -0
  71. nautobot/core/tables.py +10 -46
  72. nautobot/core/tasks.py +1 -1
  73. nautobot/core/templates/about.html +67 -0
  74. nautobot/core/templates/components/button/default.html +7 -0
  75. nautobot/core/templates/components/button/dropdown.html +20 -0
  76. nautobot/core/templates/components/layout/one_over_two.html +19 -0
  77. nautobot/core/templates/components/layout/two_over_one.html +19 -0
  78. nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
  79. nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
  80. nautobot/core/templates/components/panel/body_content_tags.html +6 -0
  81. nautobot/core/templates/components/panel/body_content_text.html +12 -0
  82. nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
  83. nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
  84. nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
  85. nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
  86. nautobot/core/templates/components/panel/footer_content_table.html +14 -0
  87. nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
  88. nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
  89. nautobot/core/templates/components/panel/panel.html +16 -0
  90. nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
  91. nautobot/core/templates/components/tab/content_wrapper.html +3 -0
  92. nautobot/core/templates/components/tab/label_wrapper.html +5 -0
  93. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
  94. nautobot/core/templates/generic/object_retrieve.html +28 -17
  95. nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
  96. nautobot/core/templates/inc/custom_fields/panel.html +2 -2
  97. nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
  98. nautobot/core/templates/inc/footer.html +1 -0
  99. nautobot/core/templates/inc/nav_menu.html +2 -1
  100. nautobot/core/templates/inc/relationships_panel.html +1 -1
  101. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  102. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  103. nautobot/core/templates/nautobot_config.py.j2 +13 -0
  104. nautobot/core/templates/panel_table.html +12 -0
  105. nautobot/core/templates/utilities/render_jinja2.html +117 -0
  106. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  107. nautobot/core/templates/utilities/theme_preview.html +7 -0
  108. nautobot/core/templatetags/helpers.py +104 -6
  109. nautobot/core/templatetags/ui_framework.py +40 -0
  110. nautobot/core/testing/__init__.py +8 -8
  111. nautobot/core/testing/api.py +187 -137
  112. nautobot/core/testing/context.py +18 -0
  113. nautobot/core/testing/filters.py +41 -35
  114. nautobot/core/testing/forms.py +2 -0
  115. nautobot/core/testing/views.py +65 -148
  116. nautobot/core/tests/integration/test_view_authentication.py +1 -1
  117. nautobot/core/tests/nautobot_config.py +198 -0
  118. nautobot/core/tests/runner.py +2 -2
  119. nautobot/core/tests/test_api.py +154 -176
  120. nautobot/core/tests/test_events.py +214 -0
  121. nautobot/core/tests/test_forms.py +1 -0
  122. nautobot/core/tests/test_jinja_filters.py +1 -0
  123. nautobot/core/tests/test_jobs.py +387 -14
  124. nautobot/core/tests/test_navigations.py +7 -241
  125. nautobot/core/tests/test_settings_schema.py +7 -0
  126. nautobot/core/tests/test_tables.py +100 -0
  127. nautobot/core/tests/test_templatetags_helpers.py +16 -0
  128. nautobot/core/tests/test_ui.py +150 -0
  129. nautobot/core/tests/test_utils.py +55 -18
  130. nautobot/core/tests/test_views.py +124 -5
  131. nautobot/core/ui/__init__.py +0 -0
  132. nautobot/core/ui/base.py +11 -0
  133. nautobot/core/ui/choices.py +44 -0
  134. nautobot/core/ui/homepage.py +167 -0
  135. nautobot/core/ui/nav.py +280 -0
  136. nautobot/core/ui/object_detail.py +1855 -0
  137. nautobot/core/ui/utils.py +36 -0
  138. nautobot/core/urls.py +6 -0
  139. nautobot/core/utils/config.py +30 -3
  140. nautobot/core/utils/lookup.py +12 -2
  141. nautobot/core/utils/querysets.py +64 -0
  142. nautobot/core/utils/requests.py +24 -9
  143. nautobot/core/views/__init__.py +48 -1
  144. nautobot/core/views/generic.py +37 -140
  145. nautobot/core/views/mixins.py +82 -32
  146. nautobot/core/views/paginator.py +8 -5
  147. nautobot/core/views/renderers.py +9 -9
  148. nautobot/core/views/utils.py +11 -0
  149. nautobot/core/wsgi.py +3 -3
  150. nautobot/dcim/api/serializers.py +34 -141
  151. nautobot/dcim/api/urls.py +5 -0
  152. nautobot/dcim/api/views.py +57 -110
  153. nautobot/dcim/apps.py +1 -0
  154. nautobot/dcim/choices.py +28 -0
  155. nautobot/dcim/factory.py +58 -0
  156. nautobot/dcim/filters/__init__.py +204 -2
  157. nautobot/dcim/forms.py +219 -9
  158. nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
  159. nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
  160. nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
  161. nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
  162. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  163. nautobot/dcim/models/__init__.py +5 -1
  164. nautobot/dcim/models/devices.py +180 -2
  165. nautobot/dcim/models/racks.py +2 -2
  166. nautobot/dcim/navigation.py +25 -224
  167. nautobot/dcim/signals.py +44 -0
  168. nautobot/dcim/tables/__init__.py +2 -0
  169. nautobot/dcim/tables/devices.py +103 -7
  170. nautobot/dcim/tables/racks.py +1 -1
  171. nautobot/dcim/templates/dcim/controller/base.html +10 -0
  172. nautobot/dcim/templates/dcim/controller_create.html +2 -7
  173. nautobot/dcim/templates/dcim/controller_retrieve.html +6 -10
  174. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
  175. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -0
  176. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +51 -0
  177. nautobot/dcim/templates/dcim/device/base.html +6 -42
  178. nautobot/dcim/templates/dcim/device/wireless.html +73 -0
  179. nautobot/dcim/templates/dcim/device.html +4 -10
  180. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  181. nautobot/dcim/templates/dcim/interface.html +1 -0
  182. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  183. nautobot/dcim/templates/dcim/location.html +1 -9
  184. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  185. nautobot/dcim/templates/dcim/locationtype.html +0 -107
  186. nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
  187. nautobot/dcim/templates/dcim/rack.html +1 -9
  188. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  189. nautobot/dcim/templates/dcim/rackreservation.html +1 -9
  190. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +68 -0
  191. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +28 -0
  192. nautobot/dcim/tests/integration/test_controller.py +62 -0
  193. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  194. nautobot/dcim/tests/test_api.py +188 -64
  195. nautobot/dcim/tests/test_filters.py +171 -76
  196. nautobot/dcim/tests/test_jobs.py +118 -0
  197. nautobot/dcim/tests/test_models.py +157 -6
  198. nautobot/dcim/tests/test_signals.py +1 -0
  199. nautobot/dcim/tests/test_views.py +118 -88
  200. nautobot/dcim/urls.py +72 -27
  201. nautobot/dcim/utils.py +2 -2
  202. nautobot/dcim/views.py +356 -61
  203. nautobot/extras/api/serializers.py +39 -18
  204. nautobot/extras/api/urls.py +4 -0
  205. nautobot/extras/api/views.py +89 -31
  206. nautobot/extras/choices.py +13 -0
  207. nautobot/extras/constants.py +2 -1
  208. nautobot/extras/context_managers.py +23 -6
  209. nautobot/extras/datasources/git.py +4 -1
  210. nautobot/extras/factory.py +27 -0
  211. nautobot/extras/filters/__init__.py +66 -5
  212. nautobot/extras/forms/base.py +2 -2
  213. nautobot/extras/forms/forms.py +262 -59
  214. nautobot/extras/forms/mixins.py +2 -2
  215. nautobot/extras/graphql/types.py +25 -1
  216. nautobot/extras/jobs.py +109 -15
  217. nautobot/extras/management/__init__.py +1 -0
  218. nautobot/extras/management/commands/runjob.py +7 -79
  219. nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
  220. nautobot/extras/management/utils.py +87 -0
  221. nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
  222. nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
  223. nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
  224. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  225. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  226. nautobot/extras/models/__init__.py +5 -1
  227. nautobot/extras/models/change_logging.py +7 -3
  228. nautobot/extras/models/contacts.py +1 -1
  229. nautobot/extras/models/groups.py +0 -2
  230. nautobot/extras/models/jobs.py +233 -33
  231. nautobot/extras/models/relationships.py +69 -1
  232. nautobot/extras/models/secrets.py +5 -0
  233. nautobot/extras/navigation.py +20 -262
  234. nautobot/extras/plugins/__init__.py +54 -19
  235. nautobot/extras/plugins/marketplace_manifest.yml +455 -0
  236. nautobot/extras/plugins/tables.py +16 -14
  237. nautobot/extras/plugins/urls.py +1 -0
  238. nautobot/extras/plugins/views.py +103 -60
  239. nautobot/extras/registry.py +1 -1
  240. nautobot/extras/secrets/__init__.py +2 -2
  241. nautobot/extras/signals.py +39 -1
  242. nautobot/extras/tables.py +37 -1
  243. nautobot/extras/templates/extras/dynamicgroup.html +1 -9
  244. nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
  245. nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
  246. nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
  247. nautobot/extras/templates/extras/job_detail.html +52 -6
  248. nautobot/extras/templates/extras/job_edit.html +6 -2
  249. nautobot/extras/templates/extras/job_list.html +2 -7
  250. nautobot/extras/templates/extras/jobqueue_retrieve.html +36 -0
  251. nautobot/extras/templates/extras/marketplace.html +296 -0
  252. nautobot/extras/templates/extras/plugin_detail.html +32 -15
  253. nautobot/extras/templates/extras/plugins_list.html +35 -1
  254. nautobot/extras/templates/extras/plugins_tiles.html +90 -0
  255. nautobot/extras/templates/extras/role_retrieve.html +16 -0
  256. nautobot/extras/templates/extras/secret.html +0 -65
  257. nautobot/extras/templates/extras/secret_check.js +16 -0
  258. nautobot/extras/templates/extras/secret_create.html +114 -0
  259. nautobot/extras/templates/extras/secret_edit.html +1 -114
  260. nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
  261. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
  262. nautobot/extras/templatetags/job_buttons.py +5 -4
  263. nautobot/extras/templatetags/plugins.py +69 -6
  264. nautobot/extras/test_jobs/singleton.py +16 -0
  265. nautobot/extras/tests/test_api.py +145 -43
  266. nautobot/extras/tests/test_context_managers.py +4 -1
  267. nautobot/extras/tests/test_filters.py +213 -529
  268. nautobot/extras/tests/test_job_variables.py +73 -152
  269. nautobot/extras/tests/test_jobs.py +181 -51
  270. nautobot/extras/tests/test_models.py +61 -6
  271. nautobot/extras/tests/test_plugins.py +62 -9
  272. nautobot/extras/tests/test_relationships.py +123 -9
  273. nautobot/extras/tests/test_utils.py +23 -2
  274. nautobot/extras/tests/test_views.py +146 -145
  275. nautobot/extras/tests/test_webhooks.py +2 -1
  276. nautobot/extras/urls.py +2 -20
  277. nautobot/extras/utils.py +119 -4
  278. nautobot/extras/views.py +168 -125
  279. nautobot/extras/webhooks.py +5 -2
  280. nautobot/ipam/api/serializers.py +10 -103
  281. nautobot/ipam/api/views.py +31 -49
  282. nautobot/ipam/factory.py +1 -1
  283. nautobot/ipam/filters.py +3 -2
  284. nautobot/ipam/models.py +10 -12
  285. nautobot/ipam/navigation.py +0 -90
  286. nautobot/ipam/tables.py +3 -1
  287. nautobot/ipam/templates/ipam/ipaddress.html +1 -9
  288. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  289. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  290. nautobot/ipam/templates/ipam/prefix.html +1 -9
  291. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  292. nautobot/ipam/templates/ipam/routetarget.html +0 -28
  293. nautobot/ipam/templates/ipam/vlan.html +1 -9
  294. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  295. nautobot/ipam/templates/ipam/vrf.html +0 -47
  296. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  297. nautobot/ipam/tests/test_api.py +7 -5
  298. nautobot/ipam/tests/test_filters.py +39 -119
  299. nautobot/ipam/tests/test_forms.py +0 -2
  300. nautobot/ipam/tests/test_models.py +56 -36
  301. nautobot/ipam/tests/test_views.py +3 -0
  302. nautobot/ipam/urls.py +3 -69
  303. nautobot/ipam/utils/__init__.py +16 -10
  304. nautobot/ipam/views.py +91 -162
  305. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  306. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  307. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  308. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  309. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  310. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  311. nautobot/project-static/css/base.css +38 -3
  312. nautobot/project-static/docs/404.html +461 -17
  313. nautobot/project-static/docs/apps/index.html +461 -17
  314. nautobot/project-static/docs/apps/nautobot-apps.html +462 -19
  315. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  316. nautobot/project-static/docs/assets/extra.css +5 -1
  317. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +477 -23
  318. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +474 -20
  319. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +790 -289
  320. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +505 -31
  321. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +510 -34
  322. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +471 -20
  323. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +467 -18
  324. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +497 -33
  325. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9883 -0
  326. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +523 -75
  327. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +546 -51
  328. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +670 -94
  329. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1030 -177
  330. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +524 -49
  331. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +874 -188
  332. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +955 -235
  333. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +475 -21
  334. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +486 -28
  335. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +661 -99
  336. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +947 -479
  337. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6425 -1234
  338. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +474 -20
  339. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +877 -344
  340. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +828 -171
  341. nautobot/project-static/docs/development/apps/api/configuration-view.html +461 -17
  342. nautobot/project-static/docs/development/apps/api/database-backend-config.html +461 -17
  343. nautobot/project-static/docs/development/apps/api/models/django-admin.html +461 -17
  344. nautobot/project-static/docs/development/apps/api/models/global-search.html +461 -17
  345. nautobot/project-static/docs/development/apps/api/models/graphql.html +461 -17
  346. nautobot/project-static/docs/development/apps/api/models/index.html +461 -17
  347. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +461 -17
  348. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +461 -17
  349. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +461 -17
  350. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +461 -17
  351. nautobot/project-static/docs/development/apps/api/platform-features/index.html +461 -17
  352. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +461 -17
  353. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +461 -17
  354. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +461 -17
  355. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +461 -17
  356. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +461 -17
  357. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +461 -17
  358. nautobot/project-static/docs/development/apps/api/prometheus.html +461 -17
  359. nautobot/project-static/docs/development/apps/api/setup.html +465 -153
  360. nautobot/project-static/docs/development/apps/api/testing.html +461 -17
  361. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +461 -17
  362. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +461 -17
  363. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +461 -17
  364. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +461 -17
  365. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +741 -128
  366. nautobot/project-static/docs/development/apps/api/views/base-template.html +461 -17
  367. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +461 -17
  368. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +461 -17
  369. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +461 -17
  370. nautobot/project-static/docs/development/apps/api/views/index.html +463 -18
  371. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +465 -17
  372. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +491 -17
  373. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +461 -17
  374. nautobot/project-static/docs/development/apps/api/views/notes.html +461 -17
  375. nautobot/project-static/docs/development/apps/api/views/rest-api.html +467 -19
  376. nautobot/project-static/docs/development/apps/api/views/urls.html +461 -17
  377. nautobot/project-static/docs/development/apps/index.html +461 -17
  378. nautobot/project-static/docs/development/apps/migration/code-updates.html +462 -50
  379. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +462 -18
  380. nautobot/project-static/docs/development/apps/migration/from-v1.html +461 -17
  381. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +461 -17
  382. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +461 -17
  383. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +461 -17
  384. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +464 -20
  385. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9261 -0
  386. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9375 -0
  387. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9671 -0
  388. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9559 -0
  389. nautobot/project-static/docs/development/apps/porting-from-netbox.html +464 -20
  390. nautobot/project-static/docs/development/core/application-registry.html +461 -17
  391. nautobot/project-static/docs/development/core/best-practices.html +461 -17
  392. nautobot/project-static/docs/development/core/bootstrap-ui.html +461 -17
  393. nautobot/project-static/docs/development/core/caching.html +461 -17
  394. nautobot/project-static/docs/development/core/controllers.html +463 -17
  395. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +464 -20
  396. nautobot/project-static/docs/development/core/generic-views.html +461 -17
  397. nautobot/project-static/docs/development/core/getting-started.html +539 -127
  398. nautobot/project-static/docs/development/core/homepage.html +472 -28
  399. nautobot/project-static/docs/development/core/index.html +461 -17
  400. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9754 -0
  401. nautobot/project-static/docs/development/core/model-checklist.html +471 -25
  402. nautobot/project-static/docs/development/core/model-features.html +461 -17
  403. nautobot/project-static/docs/development/core/natural-keys.html +461 -17
  404. nautobot/project-static/docs/development/core/navigation-menu.html +478 -24
  405. nautobot/project-static/docs/development/core/release-checklist.html +478 -46
  406. nautobot/project-static/docs/development/core/role-internals.html +461 -17
  407. nautobot/project-static/docs/development/core/settings.html +461 -17
  408. nautobot/project-static/docs/development/core/style-guide.html +464 -20
  409. nautobot/project-static/docs/development/core/templates.html +471 -20
  410. nautobot/project-static/docs/development/core/testing.html +461 -17
  411. nautobot/project-static/docs/development/core/ui-component-framework.html +11116 -0
  412. nautobot/project-static/docs/development/core/user-preferences.html +464 -20
  413. nautobot/project-static/docs/development/index.html +461 -17
  414. nautobot/project-static/docs/development/jobs/index.html +499 -19
  415. nautobot/project-static/docs/development/jobs/migration/from-v1.html +461 -17
  416. nautobot/project-static/docs/index.html +469 -36
  417. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  418. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  419. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  420. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  421. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  422. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  423. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  424. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  425. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  426. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  427. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  428. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  429. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  430. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  431. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  432. nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
  433. nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
  434. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  435. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  436. nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
  437. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
  438. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
  439. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
  440. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  441. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  442. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
  443. nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
  444. nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
  445. nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
  446. nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
  447. nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
  448. nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
  449. nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
  450. nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
  451. nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
  452. nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
  453. nautobot/project-static/docs/objects.inv +0 -0
  454. nautobot/project-static/docs/overview/application_stack.html +467 -21
  455. nautobot/project-static/docs/overview/design_philosophy.html +461 -17
  456. nautobot/project-static/docs/release-notes/index.html +483 -20
  457. nautobot/project-static/docs/release-notes/version-1.0.html +649 -206
  458. nautobot/project-static/docs/release-notes/version-1.1.html +646 -203
  459. nautobot/project-static/docs/release-notes/version-1.2.html +721 -278
  460. nautobot/project-static/docs/release-notes/version-1.3.html +747 -304
  461. nautobot/project-static/docs/release-notes/version-1.4.html +832 -390
  462. nautobot/project-static/docs/release-notes/version-1.5.html +1020 -579
  463. nautobot/project-static/docs/release-notes/version-1.6.html +940 -516
  464. nautobot/project-static/docs/release-notes/version-2.0.html +943 -502
  465. nautobot/project-static/docs/release-notes/version-2.1.html +778 -337
  466. nautobot/project-static/docs/release-notes/version-2.2.html +771 -330
  467. nautobot/project-static/docs/release-notes/version-2.3.html +914 -471
  468. nautobot/project-static/docs/release-notes/version-2.4.html +10323 -0
  469. nautobot/project-static/docs/search/search_index.json +1 -1
  470. nautobot/project-static/docs/sitemap.xml +342 -270
  471. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  472. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +461 -17
  473. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +461 -17
  474. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +461 -17
  475. nautobot/project-static/docs/user-guide/administration/configuration/index.html +473 -30
  476. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +461 -17
  477. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +842 -155
  478. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +461 -17
  479. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +461 -17
  480. nautobot/project-static/docs/user-guide/administration/guides/docker.html +474 -27
  481. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +461 -17
  482. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +461 -17
  483. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +461 -17
  484. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +461 -17
  485. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +461 -17
  486. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +463 -19
  487. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +461 -17
  488. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +461 -17
  489. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +461 -17
  490. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +481 -21
  491. nautobot/project-static/docs/user-guide/administration/installation/index.html +466 -18
  492. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +462 -18
  493. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +461 -17
  494. nautobot/project-static/docs/user-guide/administration/installation/services.html +461 -17
  495. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +461 -17
  496. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +482 -39
  497. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +475 -64
  498. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +475 -64
  499. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +461 -17
  500. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +461 -17
  501. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +461 -17
  502. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +461 -17
  503. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +461 -17
  504. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +464 -21
  505. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +461 -17
  506. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
  507. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +461 -17
  508. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +467 -19
  509. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +461 -17
  510. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +461 -17
  511. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +461 -17
  512. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +461 -17
  513. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +461 -17
  514. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +461 -17
  515. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +461 -17
  516. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +461 -17
  517. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +461 -17
  518. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +461 -17
  519. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +461 -17
  520. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +461 -17
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +461 -17
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +461 -17
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +461 -17
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +461 -17
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +461 -17
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +497 -18
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +487 -20
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +461 -17
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +461 -17
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +461 -17
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +461 -17
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +461 -17
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +461 -17
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +461 -17
  535. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +461 -17
  536. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +461 -17
  537. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +461 -17
  538. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +461 -17
  539. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +461 -17
  540. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +461 -17
  541. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +461 -17
  542. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +461 -17
  543. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +461 -17
  544. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +461 -17
  545. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +461 -17
  546. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +461 -17
  547. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +461 -17
  548. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +461 -17
  549. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +461 -17
  550. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +461 -17
  551. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +461 -17
  552. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +461 -17
  553. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +461 -17
  554. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +461 -17
  555. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +461 -17
  556. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +461 -17
  557. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +461 -17
  558. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +461 -17
  559. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +461 -17
  560. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +461 -17
  561. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +461 -17
  562. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9375 -0
  563. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +468 -28
  564. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +461 -17
  565. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +461 -17
  566. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +461 -17
  567. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +461 -17
  568. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +461 -17
  569. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +461 -17
  570. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +461 -17
  571. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +461 -17
  572. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +461 -17
  573. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +461 -17
  574. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +461 -17
  575. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +461 -17
  576. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +464 -20
  577. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +461 -17
  578. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +461 -17
  579. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +461 -17
  580. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +461 -17
  581. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +461 -17
  582. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +461 -17
  583. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +464 -20
  584. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9313 -0
  585. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9217 -0
  586. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9211 -0
  587. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9277 -0
  588. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +461 -17
  589. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +461 -17
  590. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +461 -17
  591. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +461 -17
  592. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +461 -17
  593. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +461 -17
  594. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +461 -17
  595. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +461 -17
  596. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +461 -17
  597. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +461 -17
  598. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +461 -17
  599. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +466 -20
  600. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +461 -17
  601. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  602. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  603. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  604. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  605. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  606. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  607. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  608. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  609. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  610. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  611. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  612. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  613. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  614. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +461 -17
  615. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +461 -17
  616. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +464 -20
  617. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
  618. nautobot/project-static/docs/user-guide/index.html +461 -17
  619. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +464 -20
  620. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +465 -21
  621. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +461 -17
  622. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +461 -17
  623. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +461 -17
  624. nautobot/project-static/docs/user-guide/platform-functionality/events.html +9617 -0
  625. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +464 -20
  626. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +461 -17
  627. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +461 -17
  628. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +461 -17
  629. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +461 -17
  630. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +461 -17
  631. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +470 -21
  632. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +464 -20
  633. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +464 -20
  634. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +461 -17
  635. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9224 -0
  636. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
  637. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +464 -20
  638. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +461 -17
  639. nautobot/project-static/docs/user-guide/platform-functionality/note.html +461 -17
  640. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +461 -17
  641. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +465 -21
  642. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9292 -0
  643. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +461 -17
  644. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +509 -38
  645. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +492 -21
  646. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +461 -17
  647. nautobot/project-static/docs/user-guide/platform-functionality/role.html +461 -17
  648. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +461 -17
  649. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +461 -17
  650. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +464 -20
  651. nautobot/project-static/docs/user-guide/platform-functionality/status.html +461 -17
  652. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +461 -17
  653. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +529 -54
  654. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +461 -17
  655. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +461 -17
  656. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +461 -17
  657. nautobot/project-static/img/jinja_logo.svg +97 -0
  658. nautobot/project-static/js/forms.js +6 -1
  659. nautobot/project-static/js/nav_menu.js +2 -1
  660. nautobot/tenancy/api/serializers.py +0 -2
  661. nautobot/tenancy/api/views.py +9 -13
  662. nautobot/tenancy/factory.py +1 -1
  663. nautobot/tenancy/navigation.py +0 -29
  664. nautobot/tenancy/templates/tenancy/tenant.html +4 -91
  665. nautobot/tenancy/tests/test_filters.py +29 -134
  666. nautobot/tenancy/views.py +35 -24
  667. nautobot/users/admin.py +2 -0
  668. nautobot/users/api/views.py +2 -2
  669. nautobot/users/forms.py +19 -0
  670. nautobot/users/templates/users/preferences.html +22 -0
  671. nautobot/users/tests/test_filters.py +1 -19
  672. nautobot/users/tests/test_views.py +57 -0
  673. nautobot/users/utils.py +8 -0
  674. nautobot/users/views.py +48 -11
  675. nautobot/virtualization/api/views.py +5 -24
  676. nautobot/virtualization/filters.py +1 -2
  677. nautobot/virtualization/models.py +1 -1
  678. nautobot/virtualization/navigation.py +0 -48
  679. nautobot/virtualization/tables.py +2 -2
  680. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  681. nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
  682. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
  683. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  684. nautobot/virtualization/tests/test_filters.py +57 -166
  685. nautobot/virtualization/views.py +18 -15
  686. nautobot/wireless/__init__.py +0 -0
  687. nautobot/wireless/api/__init__.py +0 -0
  688. nautobot/wireless/api/serializers.py +44 -0
  689. nautobot/wireless/api/urls.py +20 -0
  690. nautobot/wireless/api/views.py +34 -0
  691. nautobot/wireless/apps.py +8 -0
  692. nautobot/wireless/choices.py +345 -0
  693. nautobot/wireless/factory.py +138 -0
  694. nautobot/wireless/filters.py +167 -0
  695. nautobot/wireless/forms.py +283 -0
  696. nautobot/wireless/homepage.py +19 -0
  697. nautobot/wireless/migrations/0001_initial.py +223 -0
  698. nautobot/wireless/migrations/__init__.py +0 -0
  699. nautobot/wireless/models.py +207 -0
  700. nautobot/wireless/navigation.py +105 -0
  701. nautobot/wireless/tables.py +244 -0
  702. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
  703. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
  704. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
  705. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +56 -0
  706. nautobot/wireless/tests/__init__.py +0 -0
  707. nautobot/wireless/tests/integration/__init__.py +0 -0
  708. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  709. nautobot/wireless/tests/test_api.py +247 -0
  710. nautobot/wireless/tests/test_filters.py +82 -0
  711. nautobot/wireless/tests/test_models.py +22 -0
  712. nautobot/wireless/tests/test_views.py +378 -0
  713. nautobot/wireless/urls.py +13 -0
  714. nautobot/wireless/views.py +119 -0
  715. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/METADATA +9 -12
  716. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/RECORD +720 -549
  717. nautobot/core/utils/navigation.py +0 -54
  718. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/LICENSE.txt +0 -0
  719. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/NOTICE +0 -0
  720. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/WHEEL +0 -0
  721. {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/entry_points.txt +0 -0
@@ -1,7 +1,5 @@
1
- from __future__ import annotations # python 3.8
2
-
3
1
  import logging
4
- from typing import Optional
2
+ from typing import ClassVar, Optional
5
3
 
6
4
  from django.contrib import messages
7
5
  from django.contrib.auth.mixins import AccessMixin
@@ -41,6 +39,7 @@ from nautobot.core.forms import (
41
39
  CSVFileField,
42
40
  restrict_form_fields,
43
41
  )
42
+ from nautobot.core.jobs import BulkDeleteObjects, BulkEditObjects
44
43
  from nautobot.core.utils import lookup, permissions
45
44
  from nautobot.core.utils.requests import get_filterable_params_from_filter_params, normalize_querydict
46
45
  from nautobot.core.views.renderers import NautobotHTMLRenderer
@@ -52,7 +51,7 @@ from nautobot.core.views.utils import (
52
51
  )
53
52
  from nautobot.extras.context_managers import deferred_change_logging_for_bulk_operation
54
53
  from nautobot.extras.forms import NoteForm
55
- from nautobot.extras.models import ExportTemplate, SavedView, UserSavedViewAssociation
54
+ from nautobot.extras.models import ExportTemplate, Job, JobResult, SavedView, UserSavedViewAssociation
56
55
  from nautobot.extras.tables import NoteTable, ObjectChangeTable
57
56
  from nautobot.extras.utils import bulk_delete_with_bulk_change_logging, get_base_template, remove_prefix_from_cf_key
58
57
 
@@ -587,11 +586,11 @@ class NautobotViewSetMixin(GenericViewSet, AccessMixin, GetReturnURLMixin, FormV
587
586
  if self.action == "bulk_destroy":
588
587
  queryset = self.get_queryset()
589
588
  bulk_delete_all = bool(self.request.POST.get("_all"))
590
- if bulk_delete_all:
591
- return ConfirmationForm
592
589
 
593
590
  class BulkDestroyForm(ConfirmationForm):
594
- pk = ModelMultipleChoiceField(queryset=queryset, widget=MultipleHiddenInput)
591
+ pk = ModelMultipleChoiceField(
592
+ queryset=queryset, widget=MultipleHiddenInput, required=not bulk_delete_all
593
+ )
595
594
 
596
595
  return BulkDestroyForm
597
596
  else:
@@ -622,12 +621,13 @@ class ObjectDetailViewMixin(NautobotViewSetMixin, mixins.RetrieveModelMixin):
622
621
  UI mixin to retrieve a model instance.
623
622
  """
624
623
 
624
+ object_detail_content = None
625
+
625
626
  def retrieve(self, request, *args, **kwargs):
626
627
  """
627
628
  Retrieve a model instance.
628
629
  """
629
- context = {"use_new_ui": True}
630
- return Response(context)
630
+ return Response({})
631
631
 
632
632
 
633
633
  class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
@@ -713,7 +713,6 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
713
713
  """
714
714
  List the model instances.
715
715
  """
716
- context = {"use_new_ui": True}
717
716
  queryset = self.get_queryset()
718
717
  clear_view = request.GET.get("clear_view", False)
719
718
  if "export" in request.GET: # 3.0 TODO: remove, irrelevant after #4746
@@ -751,7 +750,7 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
751
750
  except ObjectDoesNotExist:
752
751
  pass
753
752
 
754
- return Response(context)
753
+ return Response({})
755
754
 
756
755
 
757
756
  class ObjectDestroyViewMixin(NautobotViewSetMixin, mixins.DestroyModelMixin):
@@ -921,9 +920,9 @@ class ObjectEditViewMixin(NautobotViewSetMixin, mixins.CreateModelMixin, mixins.
921
920
  return self.form_invalid(form)
922
921
 
923
922
 
924
- class EditAndDeleteAllModelMixin:
923
+ class BulkEditAndBulkDeleteModelMixin:
925
924
  """
926
- UI mixin to bulk destroy all and bulk edit all model instances.
925
+ UI mixin to bulk destroy and bulk edit all model instances.
927
926
  """
928
927
 
929
928
  def _get_bulk_edit_delete_all_queryset(self, request):
@@ -951,18 +950,61 @@ class EditAndDeleteAllModelMixin:
951
950
  queryset = model.objects.all()
952
951
  return queryset
953
952
 
954
- def _bulk_delete_all_context(self, request, queryset):
955
- model = queryset.model
956
- return {
957
- "obj_type_plural": model._meta.verbose_name_plural,
958
- "return_url": self.get_return_url(request),
959
- "total_objs_to_delete": queryset.count(),
960
- "delete_all": True,
961
- "table": None,
962
- }
953
+ def send_bulk_delete_objects_to_job(self, request, pk_list, model, delete_all):
954
+ """Prepare and enqueue bulk delete job."""
955
+ job_model = Job.objects.get_for_class_path(BulkDeleteObjects.class_path)
956
+
957
+ if filterset_class := lookup.get_filterset_for_model(model):
958
+ filter_query_params = normalize_querydict(request.GET, filterset=filterset_class())
959
+ else:
960
+ filter_query_params = None
961
+
962
+ job_form = BulkDeleteObjects.as_form(
963
+ data={
964
+ "pk_list": pk_list,
965
+ "content_type": ContentType.objects.get_for_model(model),
966
+ "delete_all": delete_all,
967
+ "filter_query_params": filter_query_params,
968
+ }
969
+ )
970
+ # BulkDeleteObjects job form cannot be invalid; Hence no handling of invalid case.
971
+ job_form.is_valid()
972
+ job_kwargs = BulkDeleteObjects.prepare_job_kwargs(job_form.cleaned_data)
973
+ job_result = JobResult.enqueue_job(
974
+ job_model,
975
+ request.user,
976
+ **BulkDeleteObjects.serialize_data(job_kwargs),
977
+ )
978
+ return redirect("extras:jobresult", pk=job_result.pk)
979
+
980
+ def send_bulk_edit_objects_to_job(self, request, form, model):
981
+ """Prepare and enqueue a bulk edit job."""
982
+ job_model = Job.objects.get_for_class_path(BulkEditObjects.class_path)
983
+ form_data = normalize_querydict(request.POST, form)
984
+ if filterset_class := lookup.get_filterset_for_model(model):
985
+ filter_query_params = normalize_querydict(request.GET, filterset=filterset_class())
986
+ else:
987
+ filter_query_params = None
988
+ job_form = BulkEditObjects.as_form(
989
+ data={
990
+ "form_data": form_data,
991
+ "content_type": ContentType.objects.get_for_model(model),
992
+ "edit_all": request.POST.get("_all") is not None,
993
+ "filter_query_params": filter_query_params,
994
+ }
995
+ )
996
+ # NOTE: BulkEditObjects cant be invalid, so there is no need for handling invalid error
997
+ job_form.is_valid()
998
+ job_kwargs = BulkEditObjects.prepare_job_kwargs(job_form.cleaned_data)
999
+ job_result = JobResult.enqueue_job(
1000
+ job_model,
1001
+ request.user,
1002
+ **BulkEditObjects.serialize_data(job_kwargs),
1003
+ )
1004
+ return redirect("extras:jobresult", pk=job_result.pk)
963
1005
 
964
1006
 
965
- class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, EditAndDeleteAllModelMixin):
1007
+ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, BulkEditAndBulkDeleteModelMixin):
966
1008
  """
967
1009
  UI mixin to bulk destroy model instances.
968
1010
  """
@@ -1012,21 +1054,23 @@ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, Ed
1012
1054
  data = {}
1013
1055
  # Are we deleting *all* objects in the queryset or just a selected subset?
1014
1056
  if delete_all:
1057
+ self.pk_list = []
1015
1058
  queryset = self._get_bulk_edit_delete_all_queryset(self.request)
1016
- data = self._bulk_delete_all_context(request, queryset)
1017
1059
  else:
1018
1060
  self.pk_list = list(request.POST.getlist("pk"))
1061
+ queryset = queryset.filter(pk__in=self.pk_list)
1019
1062
 
1020
- form_class = self.get_form_class(**kwargs)
1021
1063
  if "_confirm" in request.POST:
1064
+ form_class = self.get_form_class(**kwargs)
1022
1065
  form = form_class(request.POST, initial=normalize_querydict(request.GET, form_class=form_class))
1023
1066
  if form.is_valid():
1024
- return self.form_valid(form)
1067
+ return self.send_bulk_delete_objects_to_job(request, self.pk_list, queryset.model, delete_all)
1025
1068
  else:
1026
1069
  return self.form_invalid(form)
1070
+ table = None
1027
1071
  if not delete_all:
1028
1072
  table_class = self.get_table_class()
1029
- table = table_class(queryset.filter(pk__in=self.pk_list), orderable=False)
1073
+ table = table_class(queryset, orderable=False)
1030
1074
  if not table.rows:
1031
1075
  messages.warning(
1032
1076
  request,
@@ -1034,7 +1078,13 @@ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, Ed
1034
1078
  )
1035
1079
  return redirect(self.get_return_url(request))
1036
1080
 
1037
- data.update({"table": table})
1081
+ data.update(
1082
+ {
1083
+ "table": table,
1084
+ "total_objs_to_delete": queryset.count(),
1085
+ "delete_all": delete_all,
1086
+ }
1087
+ )
1038
1088
  return Response(data)
1039
1089
 
1040
1090
 
@@ -1092,14 +1142,14 @@ class ObjectBulkCreateViewMixin(NautobotViewSetMixin): # 3.0 TODO: remove, unus
1092
1142
  return self.form_invalid(form)
1093
1143
 
1094
1144
 
1095
- class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin, EditAndDeleteAllModelMixin):
1145
+ class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin, BulkEditAndBulkDeleteModelMixin):
1096
1146
  """
1097
1147
  UI mixin to bulk update model instances.
1098
1148
  """
1099
1149
 
1100
- filterset_class: Optional[type[FilterSet]] = None
1101
- bulk_update_form_class: Optional[type[Form]] = None
1150
+ filterset_class: ClassVar[Optional[type[FilterSet]]] = None
1102
1151
 
1152
+ # NOTE: Performing BulkEdit Objects has been moved to a system job, but the logic remains here to ensure backward compatibility.
1103
1153
  def _process_bulk_update_form(self, form):
1104
1154
  request = self.request
1105
1155
  queryset = self.get_queryset()
@@ -1210,7 +1260,7 @@ class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin, Edit
1210
1260
  form = form_class(queryset.model, request.POST, edit_all=edit_all)
1211
1261
  restrict_form_fields(form, request.user)
1212
1262
  if form.is_valid():
1213
- return self.form_valid(form)
1263
+ return self.send_bulk_edit_objects_to_job(self.request, form, queryset.model)
1214
1264
  else:
1215
1265
  return self.form_invalid(form)
1216
1266
  table = None
@@ -1,5 +1,6 @@
1
1
  from django.core.paginator import Page, Paginator
2
2
 
3
+ from nautobot.core.constants import MAX_PAGE_SIZE_DEFAULT, PAGINATE_COUNT_DEFAULT
3
4
  from nautobot.core.utils import config
4
5
 
5
6
 
@@ -8,11 +9,11 @@ class EnhancedPaginator(Paginator):
8
9
  try:
9
10
  per_page = int(per_page)
10
11
  if per_page < 1:
11
- per_page = config.get_settings_or_config("PAGINATE_COUNT")
12
+ per_page = config.get_settings_or_config("PAGINATE_COUNT", fallback=PAGINATE_COUNT_DEFAULT)
12
13
  except ValueError:
13
- per_page = config.get_settings_or_config("PAGINATE_COUNT")
14
+ per_page = config.get_settings_or_config("PAGINATE_COUNT", fallback=PAGINATE_COUNT_DEFAULT)
14
15
 
15
- max_page_size = config.get_settings_or_config("MAX_PAGE_SIZE")
16
+ max_page_size = config.get_settings_or_config("MAX_PAGE_SIZE", fallback=MAX_PAGE_SIZE_DEFAULT)
16
17
  if max_page_size:
17
18
  per_page = min(per_page, max_page_size)
18
19
 
@@ -65,5 +66,7 @@ def get_paginate_count(request, saved_view=None):
65
66
  return per_page
66
67
 
67
68
  if request.user.is_authenticated:
68
- return request.user.get_config("pagination.per_page", config.get_settings_or_config("PAGINATE_COUNT"))
69
- return config.get_settings_or_config("PAGINATE_COUNT")
69
+ return request.user.get_config(
70
+ "pagination.per_page", config.get_settings_or_config("PAGINATE_COUNT", fallback=PAGINATE_COUNT_DEFAULT)
71
+ )
72
+ return config.get_settings_or_config("PAGINATE_COUNT", fallback=PAGINATE_COUNT_DEFAULT)
@@ -9,6 +9,7 @@ from django.urls import resolve
9
9
  from django_tables2 import RequestConfig
10
10
  from rest_framework import renderers
11
11
 
12
+ from nautobot.core.constants import MAX_PAGE_SIZE_DEFAULT
12
13
  from nautobot.core.forms import (
13
14
  restrict_form_fields,
14
15
  SearchForm,
@@ -124,7 +125,7 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
124
125
  "paginator_class": EnhancedPaginator,
125
126
  "per_page": get_paginate_count(request, self.saved_view),
126
127
  }
127
- max_page_size = get_settings_or_config("MAX_PAGE_SIZE")
128
+ max_page_size = get_settings_or_config("MAX_PAGE_SIZE", fallback=MAX_PAGE_SIZE_DEFAULT)
128
129
  if max_page_size and paginate["per_page"] > max_page_size:
129
130
  messages.warning(
130
131
  request,
@@ -243,12 +244,11 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
243
244
  restrict_form_fields(form, request.user)
244
245
  elif view.action == "bulk_destroy":
245
246
  pk_list = getattr(view, "pk_list", [])
246
- if pk_list:
247
- initial = {
248
- "pk": pk_list,
249
- "return_url": return_url,
250
- }
251
- form = form_class(initial=initial)
247
+ initial = {
248
+ "pk": pk_list,
249
+ "return_url": return_url,
250
+ }
251
+ form = form_class(initial=initial)
252
252
  delete_all = request.POST.get("_all")
253
253
  if not delete_all:
254
254
  table = self.construct_table(view, pk_list=pk_list)
@@ -294,6 +294,7 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
294
294
  "verbose_name_plural": queryset.model._meta.verbose_name_plural,
295
295
  }
296
296
  if view.action == "retrieve":
297
+ context["object_detail_content"] = view.object_detail_content
297
298
  context.update(common_detail_view_context(request, instance))
298
299
  elif view.action == "list":
299
300
  # Construct valid actions for list view.
@@ -345,6 +346,7 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
345
346
  # Ensure the proper inheritance of context variables is applied: the view's returned data takes priority over the viewset's get_extra_context
346
347
  context.update(view.get_extra_context(request, instance))
347
348
  context.update(self.get_template_context(data, renderer_context))
349
+
348
350
  return context
349
351
 
350
352
  def render(self, data, accepted_media_type=None, renderer_context=None):
@@ -365,6 +367,4 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
365
367
  # See form_valid() for self.action == "bulk_create".
366
368
  self.template = data.get("template", view.get_template_name())
367
369
 
368
- # NautobotUIViewSets pass "use_new_ui" in context as they share the same class and are just different methods
369
- self.use_new_ui = data.get("use_new_ui", False)
370
370
  return super().render(data, accepted_media_type=accepted_media_type, renderer_context=renderer_context)
@@ -98,6 +98,17 @@ def csv_format(data):
98
98
  return ",".join(csv)
99
99
 
100
100
 
101
+ def get_obj_from_context(context, key=None):
102
+ """From the given context, return the `object` that is in the context.
103
+
104
+ If a key is specified, return the value for that key.
105
+ Otherwise return the value for either of the keys `"obj"` or `"object"` as default behavior.
106
+ """
107
+ if key is not None:
108
+ return context.get(key)
109
+ return context.get("obj") or context.get("object")
110
+
111
+
101
112
  def get_csv_form_fields_from_serializer_class(serializer_class):
102
113
  """From the given serializer class, build a list of field dicts suitable for rendering in the CSV import form."""
103
114
  serializer = serializer_class(context={"request": None, "depth": 0})
nautobot/core/wsgi.py CHANGED
@@ -6,6 +6,8 @@ from django.db import connections
6
6
 
7
7
  import nautobot
8
8
 
9
+ logger = logging.getLogger(__name__)
10
+
9
11
  # This is the Django default left here for visibility on how the Nautobot pattern
10
12
  # differs.
11
13
  # os.environ.setdefault("DJANGO_SETTINGS_MODULE", "nautobot.core.settings")
@@ -24,9 +26,7 @@ try:
24
26
  def fix_uwsgi():
25
27
  import uwsgi
26
28
 
27
- logging.getLogger(__name__).info(
28
- f"Closing existing DB and cache connections on worker {uwsgi.worker_id()} after uWSGI forked ..."
29
- )
29
+ logger.info("Closing existing DB and cache connections on worker %s after uWSGI forked ...", uwsgi.worker_id())
30
30
  connections.close_all()
31
31
  cache.close_caches()
32
32
 
@@ -27,6 +27,7 @@ from nautobot.dcim.choices import (
27
27
  CableLengthUnitChoices,
28
28
  CableTypeChoices,
29
29
  ConsolePortTypeChoices,
30
+ ControllerCapabilitiesChoices,
30
31
  DeviceFaceChoices,
31
32
  DeviceRedundancyGroupFailoverStrategyChoices,
32
33
  InterfaceModeChoices,
@@ -69,6 +70,7 @@ from nautobot.dcim.models import (
69
70
  InterfaceRedundancyGroup,
70
71
  InterfaceRedundancyGroupAssociation,
71
72
  InterfaceTemplate,
73
+ InterfaceVDCAssignment,
72
74
  InventoryItem,
73
75
  Location,
74
76
  LocationType,
@@ -93,6 +95,7 @@ from nautobot.dcim.models import (
93
95
  SoftwareImageFile,
94
96
  SoftwareVersion,
95
97
  VirtualChassis,
98
+ VirtualDeviceContext,
96
99
  )
97
100
  from nautobot.extras.api.mixins import (
98
101
  TaggedModelSerializerMixin,
@@ -223,7 +226,6 @@ class LocationTypeSerializer(TreeModelSerializerMixin, NautobotModelSerializer):
223
226
  class Meta:
224
227
  model = LocationType
225
228
  fields = "__all__"
226
- list_display_fields = ["name", "nestable", "content_types", "description"]
227
229
 
228
230
 
229
231
  class LocationSerializer(
@@ -242,38 +244,9 @@ class LocationSerializer(
242
244
  class Meta:
243
245
  model = Location
244
246
  fields = "__all__"
245
- list_display_fields = ["name", "status", "parent", "tenant", "description", "tags"]
246
247
  # https://www.django-rest-framework.org/api-guide/validators/#optional-fields
247
248
  validators = []
248
249
 
249
- detail_view_config = {
250
- "layout": [
251
- {
252
- "Location": {
253
- "fields": [
254
- "location_type",
255
- "tenant",
256
- "facility",
257
- "asn",
258
- "time_zone",
259
- "description",
260
- ]
261
- },
262
- "Contact Info": {
263
- "fields": [
264
- "physical_address",
265
- "shipping_address",
266
- "latitude",
267
- "longitude",
268
- "contact_name",
269
- "contact_phone",
270
- "contact_email",
271
- ]
272
- },
273
- },
274
- ],
275
- }
276
-
277
250
  def validate(self, attrs):
278
251
  # Validate uniqueness of (parent, name) since we omitted the automatically created validator from Meta.
279
252
  if attrs.get("parent") and attrs.get("name"):
@@ -296,7 +269,6 @@ class RackGroupSerializer(TreeModelSerializerMixin, NautobotModelSerializer):
296
269
  class Meta:
297
270
  model = RackGroup
298
271
  fields = "__all__"
299
- list_display_fields = ["name", "location", "rack_count", "description"]
300
272
 
301
273
 
302
274
  class RackSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
@@ -309,24 +281,9 @@ class RackSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
309
281
  class Meta:
310
282
  model = Rack
311
283
  fields = "__all__"
312
- list_display_fields = ["name", "location", "rack_group", "status", "facility_id", "tenant", "role", "u_height"]
313
284
  # Omit the UniqueTogetherValidators that would be automatically added to validate (rack_group, facility_id) and (rack_group, name).
314
285
  # This prevents facility_id and rack_group from being interpreted as required fields.
315
286
  validators = []
316
- detail_view_config = {
317
- "layout": [
318
- {
319
- "Rack": {
320
- "fields": [
321
- "name",
322
- "location",
323
- "rack_group",
324
- ]
325
- },
326
- },
327
- ],
328
- "include_others": True,
329
- }
330
287
 
331
288
  def validate(self, attrs):
332
289
  # Validate uniqueness of (rack_group, name) since we omitted the automatically-created validator above.
@@ -359,7 +316,6 @@ class RackReservationSerializer(TaggedModelSerializerMixin, NautobotModelSeriali
359
316
  class Meta:
360
317
  model = RackReservation
361
318
  fields = "__all__"
362
- list_display_fields = ["pk", "rack", "units", "user", "description"]
363
319
  extra_kwargs = {
364
320
  "units": {"help_text": "List of rack unit numbers to reserve"},
365
321
  "user": {
@@ -392,8 +348,8 @@ class RackElevationDetailFilterSerializer(serializers.Serializer):
392
348
  is_occupied = serializers.BooleanField(required=False, allow_null=True, default=None)
393
349
 
394
350
  def validate(self, attrs):
395
- attrs.setdefault("unit_width", get_settings_or_config("RACK_ELEVATION_DEFAULT_UNIT_WIDTH"))
396
- attrs.setdefault("unit_height", get_settings_or_config("RACK_ELEVATION_DEFAULT_UNIT_HEIGHT"))
351
+ attrs.setdefault("unit_width", get_settings_or_config("RACK_ELEVATION_DEFAULT_UNIT_WIDTH", fallback=230))
352
+ attrs.setdefault("unit_height", get_settings_or_config("RACK_ELEVATION_DEFAULT_UNIT_HEIGHT", fallback=22))
397
353
  return attrs
398
354
 
399
355
 
@@ -411,16 +367,14 @@ class ManufacturerSerializer(NautobotModelSerializer):
411
367
  class Meta:
412
368
  model = Manufacturer
413
369
  fields = "__all__"
414
- list_display_fields = ["name", "device_type_count", "platform_count", "description"]
415
370
 
416
371
 
417
- class DeviceFamilySerializer(NautobotModelSerializer):
372
+ class DeviceFamilySerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
418
373
  device_type_count = serializers.IntegerField(read_only=True)
419
374
 
420
375
  class Meta:
421
376
  model = DeviceFamily
422
377
  fields = "__all__"
423
- list_display_fields = ["name", "device_type_count", "description"]
424
378
 
425
379
 
426
380
  class DeviceTypeSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
@@ -432,28 +386,7 @@ class DeviceTypeSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
432
386
  class Meta:
433
387
  model = DeviceType
434
388
  fields = "__all__"
435
- list_display_fields = ["model", "manufacturer", "part_number", "u_height", "is_full_depth", "device_count"]
436
-
437
- detail_view_config = {
438
- "layout": [
439
- {
440
- "Chassis": {
441
- "fields": [
442
- "manufacturer",
443
- "model",
444
- "part_number",
445
- "u_height",
446
- "is_full_depth",
447
- "subdevice_role",
448
- "front_image",
449
- "rear_image",
450
- "device_count",
451
- ]
452
- },
453
- },
454
- ],
455
- "include_others": True,
456
- }
389
+
457
390
  extra_kwargs = {
458
391
  "device_family": {
459
392
  "required": False,
@@ -579,18 +512,6 @@ class PlatformSerializer(NautobotModelSerializer):
579
512
  class Meta:
580
513
  model = Platform
581
514
  fields = "__all__"
582
- list_display_fields = [
583
- "name",
584
- "manufacturer",
585
- "napalm_driver",
586
- "napalm_args",
587
- "network_driver",
588
- "network_driver_mappings",
589
- "device_count",
590
- "virtual_machine_count",
591
- "napalm_driver",
592
- "description",
593
- ]
594
515
 
595
516
 
596
517
  class DeviceBaySerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
@@ -606,7 +527,6 @@ class DeviceSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
606
527
  class Meta:
607
528
  model = Device
608
529
  fields = "__all__"
609
- list_display_fields = ["name", "status", "tenant", "location", "rack", "role", "device_type", "primary_ip"]
610
530
  validators = []
611
531
  extra_kwargs = {
612
532
  "parent_bay": {"required": False, "allow_null": True},
@@ -614,49 +534,6 @@ class DeviceSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
614
534
  "vc_priority": {"label": "Virtual chassis priority"},
615
535
  }
616
536
 
617
- detail_view_config = {
618
- "layout": [
619
- {
620
- "Device": {
621
- "fields": [
622
- "name",
623
- "location",
624
- "rack",
625
- "face",
626
- "position",
627
- "tenant",
628
- "device_type",
629
- "serial",
630
- "asset_tag",
631
- "cluster",
632
- "parent_bay",
633
- ]
634
- },
635
- "Device Management": {
636
- "fields": [
637
- "role",
638
- "platform",
639
- "primary_ip4",
640
- "primary_ip6",
641
- "secrets_group",
642
- "device_redundancy_group",
643
- "device_redundancy_group_priority",
644
- "controller_managed_device_group",
645
- ]
646
- },
647
- },
648
- ],
649
- "include_others": False, # TODO: config_context, local_config_context_data, local_config_context_schema
650
- }
651
-
652
- def get_additional_detail_view_tabs(self):
653
- """Add "Virtual Chassis" as a separate detail tab."""
654
- tabs = super().get_additional_detail_view_tabs()
655
- tabs["Virtual Chassis"] = [
656
- {"Virtual Chassis": {"fields": ["virtual_chassis", "vc_position", "vc_priority"]}},
657
- ]
658
- return tabs
659
-
660
537
  def get_field_names(self, declared_fields, info):
661
538
  """
662
539
  Add a couple of special fields to the serializer.
@@ -786,12 +663,11 @@ class InterfaceSerializer(
786
663
  type = ChoiceField(choices=InterfaceTypeChoices)
787
664
  mode = ChoiceField(choices=InterfaceModeChoices, allow_blank=True, required=False)
788
665
  mac_address = serializers.CharField(allow_blank=True, allow_null=True, required=False)
789
- ip_address_count = serializers.IntegerField(read_only=True)
666
+ ip_address_count = serializers.IntegerField(read_only=True, source="_ip_address_count")
790
667
 
791
668
  class Meta:
792
669
  model = Interface
793
670
  fields = "__all__"
794
- list_display_fields = ["device", "name", "status", "label", "enabled", "type", "description"]
795
671
  extra_kwargs = {"cable": {"read_only": True}}
796
672
  validators = []
797
673
 
@@ -862,7 +738,6 @@ class DeviceRedundancyGroupSerializer(TaggedModelSerializerMixin, NautobotModelS
862
738
  class Meta:
863
739
  model = DeviceRedundancyGroup
864
740
  fields = "__all__"
865
- list_display_fields = ["name", "status", "failover_strategy", "device_count"]
866
741
 
867
742
 
868
743
  #
@@ -911,13 +786,6 @@ class CableSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
911
786
  extra_kwargs = {
912
787
  "color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
913
788
  }
914
- list_display_fields = [
915
- "label",
916
- "termination_a",
917
- "termination_b",
918
- "status",
919
- "type",
920
- ]
921
789
 
922
790
  def _get_termination(self, obj, side):
923
791
  """
@@ -1058,7 +926,6 @@ class VirtualChassisSerializer(TaggedModelSerializerMixin, NautobotModelSerializ
1058
926
  class Meta:
1059
927
  model = VirtualChassis
1060
928
  fields = "__all__"
1061
- list_display_fields = ["name", "domain", "master", "member_count"]
1062
929
 
1063
930
 
1064
931
  #
@@ -1113,12 +980,20 @@ class DeviceTypeToSoftwareImageFileSerializer(ValidatedModelSerializer):
1113
980
 
1114
981
 
1115
982
  class ControllerSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
983
+ capabilities = serializers.ListField(
984
+ child=ChoiceField(choices=ControllerCapabilitiesChoices, required=False), allow_empty=True
985
+ )
986
+
1116
987
  class Meta:
1117
988
  model = Controller
1118
989
  fields = "__all__"
1119
990
 
1120
991
 
1121
992
  class ControllerManagedDeviceGroupSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
993
+ capabilities = serializers.ListField(
994
+ child=ChoiceField(choices=ControllerCapabilitiesChoices, required=False), allow_empty=True
995
+ )
996
+
1122
997
  class Meta:
1123
998
  model = ControllerManagedDeviceGroup
1124
999
  fields = "__all__"
@@ -1195,3 +1070,21 @@ class ModuleTypeSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
1195
1070
  class Meta:
1196
1071
  model = ModuleType
1197
1072
  fields = "__all__"
1073
+
1074
+
1075
+ class VirtualDeviceContextSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
1076
+ class Meta:
1077
+ model = VirtualDeviceContext
1078
+ fields = "__all__"
1079
+
1080
+ def validate(self, attrs):
1081
+ """Validate device cannot be changed for VirtualDeviceContext."""
1082
+ if attrs.get("device") and self.instance and self.instance.device != attrs.get("device"):
1083
+ raise serializers.ValidationError("Changing the device of a VirtualDeviceContext is not allowed.")
1084
+ return super().validate(attrs)
1085
+
1086
+
1087
+ class InterfaceVDCAssignmentSerializer(ValidatedModelSerializer):
1088
+ class Meta:
1089
+ model = InterfaceVDCAssignment
1090
+ fields = "__all__"