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

Potentially problematic release.


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

Files changed (675) hide show
  1. nautobot/__init__.py +15 -0
  2. nautobot/apps/api.py +0 -2
  3. nautobot/apps/config.py +32 -3
  4. nautobot/apps/events.py +19 -0
  5. nautobot/apps/exceptions.py +0 -2
  6. nautobot/apps/ui.py +44 -9
  7. nautobot/apps/utils.py +0 -8
  8. nautobot/apps/views.py +2 -0
  9. nautobot/circuits/navigation.py +0 -57
  10. nautobot/circuits/tables.py +1 -2
  11. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
  12. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
  13. nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
  14. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
  15. nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
  16. nautobot/circuits/tests/integration/test_relationships.py +33 -24
  17. nautobot/circuits/tests/test_filters.py +4 -8
  18. nautobot/circuits/views.py +143 -26
  19. nautobot/cloud/factory.py +4 -1
  20. nautobot/cloud/models.py +1 -1
  21. nautobot/cloud/tests/test_filters.py +5 -4
  22. nautobot/core/api/fields.py +5 -5
  23. nautobot/core/api/metadata.py +28 -256
  24. nautobot/core/api/pagination.py +3 -2
  25. nautobot/core/api/renderers.py +3 -0
  26. nautobot/core/api/serializers.py +24 -244
  27. nautobot/core/api/urls.py +3 -4
  28. nautobot/core/api/utils.py +0 -62
  29. nautobot/core/api/views.py +48 -158
  30. nautobot/core/apps/__init__.py +22 -578
  31. nautobot/core/celery/__init__.py +13 -0
  32. nautobot/core/celery/log.py +4 -4
  33. nautobot/core/celery/schedulers.py +48 -3
  34. nautobot/core/cli/__init__.py +8 -0
  35. nautobot/core/constants.py +7 -0
  36. nautobot/core/events/__init__.py +116 -0
  37. nautobot/core/events/base.py +27 -0
  38. nautobot/core/events/exceptions.py +10 -0
  39. nautobot/core/events/redis_broker.py +48 -0
  40. nautobot/core/events/syslog_broker.py +19 -0
  41. nautobot/core/exceptions.py +0 -6
  42. nautobot/core/filters.py +16 -21
  43. nautobot/core/fixtures/user-data.json +59 -0
  44. nautobot/core/forms/fields.py +53 -8
  45. nautobot/core/forms/utils.py +2 -1
  46. nautobot/core/graphql/schema.py +3 -1
  47. nautobot/core/graphql/types.py +1 -1
  48. nautobot/core/jobs/__init__.py +4 -4
  49. nautobot/core/jobs/cleanup.py +13 -49
  50. nautobot/core/jobs/groups.py +1 -1
  51. nautobot/core/management/commands/generate_test_data.py +21 -0
  52. nautobot/core/management/commands/validate_models.py +1 -1
  53. nautobot/core/middleware.py +16 -0
  54. nautobot/core/models/__init__.py +1 -1
  55. nautobot/core/models/fields.py +11 -7
  56. nautobot/core/models/query_functions.py +2 -2
  57. nautobot/core/models/tree_queries.py +3 -6
  58. nautobot/core/settings.py +44 -7
  59. nautobot/core/settings.yaml +86 -8
  60. nautobot/core/tables.py +15 -65
  61. nautobot/core/tasks.py +1 -1
  62. nautobot/core/templates/components/button/default.html +7 -0
  63. nautobot/core/templates/components/button/dropdown.html +20 -0
  64. nautobot/core/templates/components/layout/one_over_two.html +19 -0
  65. nautobot/core/templates/components/layout/two_over_one.html +19 -0
  66. nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
  67. nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
  68. nautobot/core/templates/components/panel/body_content_tags.html +6 -0
  69. nautobot/core/templates/components/panel/body_content_text.html +12 -0
  70. nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
  71. nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
  72. nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
  73. nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
  74. nautobot/core/templates/components/panel/footer_content_table.html +14 -0
  75. nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
  76. nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
  77. nautobot/core/templates/components/panel/panel.html +16 -0
  78. nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
  79. nautobot/core/templates/components/tab/content_wrapper.html +3 -0
  80. nautobot/core/templates/components/tab/label_wrapper.html +5 -0
  81. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
  82. nautobot/core/templates/generic/object_retrieve.html +28 -17
  83. nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
  84. nautobot/core/templates/inc/custom_fields/panel.html +2 -2
  85. nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
  86. nautobot/core/templates/inc/footer.html +1 -0
  87. nautobot/core/templates/inc/media.html +0 -3
  88. nautobot/core/templates/inc/nav_menu.html +1 -1
  89. nautobot/core/templates/inc/relationships_panel.html +1 -1
  90. nautobot/core/templates/nautobot_config.py.j2 +3 -3
  91. nautobot/core/templates/panel_table.html +12 -0
  92. nautobot/core/templates/search.html +0 -7
  93. nautobot/core/templates/utilities/render_jinja2.html +117 -0
  94. nautobot/core/templatetags/helpers.py +101 -12
  95. nautobot/core/templatetags/ui_framework.py +40 -0
  96. nautobot/core/testing/api.py +23 -128
  97. nautobot/core/testing/context.py +18 -0
  98. nautobot/core/testing/filters.py +41 -58
  99. nautobot/core/testing/mixins.py +2 -7
  100. nautobot/core/testing/views.py +25 -123
  101. nautobot/core/tests/integration/test_app_home.py +1 -0
  102. nautobot/core/tests/integration/test_app_navbar.py +1 -0
  103. nautobot/core/tests/integration/test_filters.py +2 -0
  104. nautobot/core/tests/integration/test_home.py +1 -0
  105. nautobot/core/tests/integration/test_navbar.py +1 -0
  106. nautobot/core/tests/integration/test_view_authentication.py +1 -2
  107. nautobot/core/tests/nautobot_config.py +198 -0
  108. nautobot/core/tests/runner.py +3 -3
  109. nautobot/core/tests/test_api.py +82 -201
  110. nautobot/core/tests/test_csv.py +3 -25
  111. nautobot/core/tests/test_events.py +214 -0
  112. nautobot/core/tests/test_jinja_filters.py +1 -0
  113. nautobot/core/tests/test_jobs.py +84 -13
  114. nautobot/core/tests/test_navigations.py +7 -241
  115. nautobot/core/tests/test_templatetags_helpers.py +16 -0
  116. nautobot/core/tests/test_ui.py +150 -0
  117. nautobot/core/tests/test_utils.py +0 -25
  118. nautobot/core/tests/test_views.py +123 -31
  119. nautobot/core/ui/__init__.py +0 -0
  120. nautobot/core/ui/base.py +11 -0
  121. nautobot/core/ui/choices.py +44 -0
  122. nautobot/core/ui/homepage.py +167 -0
  123. nautobot/core/ui/nav.py +279 -0
  124. nautobot/core/ui/object_detail.py +1841 -0
  125. nautobot/core/ui/utils.py +36 -0
  126. nautobot/core/urls.py +4 -9
  127. nautobot/core/utils/config.py +30 -3
  128. nautobot/core/utils/lookup.py +20 -13
  129. nautobot/core/views/__init__.py +6 -1
  130. nautobot/core/views/generic.py +47 -52
  131. nautobot/core/views/mixins.py +15 -25
  132. nautobot/core/views/paginator.py +8 -5
  133. nautobot/core/views/renderers.py +3 -3
  134. nautobot/core/views/utils.py +11 -0
  135. nautobot/core/wsgi.py +3 -3
  136. nautobot/dcim/api/serializers.py +80 -179
  137. nautobot/dcim/api/urls.py +5 -0
  138. nautobot/dcim/api/views.py +17 -4
  139. nautobot/dcim/apps.py +1 -0
  140. nautobot/dcim/choices.py +28 -0
  141. nautobot/dcim/factory.py +58 -0
  142. nautobot/dcim/filters/__init__.py +197 -24
  143. nautobot/dcim/forms.py +203 -12
  144. nautobot/dcim/graphql/types.py +2 -2
  145. nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
  146. nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
  147. nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
  148. nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
  149. nautobot/dcim/models/__init__.py +4 -0
  150. nautobot/dcim/models/device_component_templates.py +2 -2
  151. nautobot/dcim/models/device_components.py +20 -22
  152. nautobot/dcim/models/devices.py +173 -4
  153. nautobot/dcim/models/locations.py +3 -3
  154. nautobot/dcim/models/power.py +5 -6
  155. nautobot/dcim/models/racks.py +6 -6
  156. nautobot/dcim/navigation.py +25 -224
  157. nautobot/dcim/signals.py +44 -0
  158. nautobot/dcim/tables/__init__.py +5 -3
  159. nautobot/dcim/tables/devices.py +96 -2
  160. nautobot/dcim/tables/devicetypes.py +2 -2
  161. nautobot/dcim/templates/dcim/controller/base.html +10 -0
  162. nautobot/dcim/templates/dcim/controller_create.html +1 -0
  163. nautobot/dcim/templates/dcim/controller_retrieve.html +5 -1
  164. nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
  165. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +66 -0
  166. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +46 -0
  167. nautobot/dcim/templates/dcim/device/base.html +6 -42
  168. nautobot/dcim/templates/dcim/device/wireless.html +73 -0
  169. nautobot/dcim/templates/dcim/device.html +3 -1
  170. nautobot/dcim/templates/dcim/interface.html +1 -0
  171. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  172. nautobot/dcim/templates/dcim/locationtype.html +0 -107
  173. nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
  174. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +76 -0
  175. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +34 -0
  176. nautobot/dcim/tests/test_api.py +172 -61
  177. nautobot/dcim/tests/test_filters.py +171 -109
  178. nautobot/dcim/tests/test_forms.py +2 -51
  179. nautobot/dcim/tests/test_graphql.py +0 -52
  180. nautobot/dcim/tests/test_models.py +126 -4
  181. nautobot/dcim/tests/test_signals.py +1 -0
  182. nautobot/dcim/tests/test_views.py +103 -11
  183. nautobot/dcim/urls.py +72 -27
  184. nautobot/dcim/utils.py +2 -2
  185. nautobot/dcim/views.py +369 -62
  186. nautobot/extras/api/customfields.py +2 -2
  187. nautobot/extras/api/serializers.py +91 -75
  188. nautobot/extras/api/urls.py +4 -0
  189. nautobot/extras/api/views.py +78 -15
  190. nautobot/extras/choices.py +13 -0
  191. nautobot/extras/constants.py +0 -1
  192. nautobot/extras/context_managers.py +23 -6
  193. nautobot/extras/datasources/git.py +4 -1
  194. nautobot/extras/factory.py +27 -0
  195. nautobot/extras/filters/__init__.py +59 -0
  196. nautobot/extras/forms/forms.py +125 -30
  197. nautobot/extras/forms/mixins.py +3 -11
  198. nautobot/extras/graphql/types.py +25 -1
  199. nautobot/extras/group_sync.py +3 -3
  200. nautobot/extras/health_checks.py +2 -1
  201. nautobot/extras/jobs.py +62 -26
  202. nautobot/extras/management/__init__.py +1 -0
  203. nautobot/extras/management/commands/runjob.py +7 -79
  204. nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
  205. nautobot/extras/management/utils.py +87 -0
  206. nautobot/extras/managers.py +1 -3
  207. nautobot/extras/migrations/0018_joblog_data_migration.py +9 -7
  208. nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
  209. nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
  210. nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
  211. nautobot/extras/models/__init__.py +4 -0
  212. nautobot/extras/models/change_logging.py +7 -3
  213. nautobot/extras/models/customfields.py +11 -12
  214. nautobot/extras/models/groups.py +9 -13
  215. nautobot/extras/models/jobs.py +218 -37
  216. nautobot/extras/models/models.py +2 -2
  217. nautobot/extras/models/relationships.py +69 -1
  218. nautobot/extras/models/secrets.py +5 -0
  219. nautobot/extras/navigation.py +20 -262
  220. nautobot/extras/plugins/__init__.py +56 -32
  221. nautobot/extras/plugins/marketplace_manifest.yml +450 -0
  222. nautobot/extras/plugins/urls.py +1 -0
  223. nautobot/extras/plugins/views.py +48 -1
  224. nautobot/extras/signals.py +39 -1
  225. nautobot/extras/tables.py +40 -6
  226. nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
  227. nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
  228. nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
  229. nautobot/extras/templates/extras/job_detail.html +36 -6
  230. nautobot/extras/templates/extras/job_edit.html +5 -2
  231. nautobot/extras/templates/extras/job_list.html +2 -7
  232. nautobot/extras/templates/extras/jobqueue_retrieve.html +44 -0
  233. nautobot/extras/templates/extras/marketplace.html +278 -0
  234. nautobot/extras/templates/extras/plugins_list.html +35 -1
  235. nautobot/extras/templates/extras/plugins_tiles.html +79 -0
  236. nautobot/extras/templates/extras/role_retrieve.html +16 -0
  237. nautobot/extras/templates/extras/secret.html +0 -65
  238. nautobot/extras/templates/extras/secret_check.js +16 -0
  239. nautobot/extras/templates/extras/secret_create.html +114 -0
  240. nautobot/extras/templates/extras/secret_edit.html +1 -114
  241. nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
  242. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
  243. nautobot/extras/templatetags/job_buttons.py +5 -4
  244. nautobot/extras/templatetags/plugins.py +69 -6
  245. nautobot/extras/test_jobs/api_test_job.py +1 -1
  246. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  247. nautobot/extras/test_jobs/dry_run.py +1 -1
  248. nautobot/extras/test_jobs/fail.py +5 -5
  249. nautobot/extras/test_jobs/file_output.py +1 -1
  250. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  251. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  252. nautobot/extras/test_jobs/ipaddress_vars.py +1 -3
  253. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  254. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  255. nautobot/extras/test_jobs/log_redaction.py +1 -1
  256. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  257. nautobot/extras/test_jobs/modify_db.py +1 -1
  258. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  259. nautobot/extras/test_jobs/object_var_required.py +1 -1
  260. nautobot/extras/test_jobs/object_vars.py +1 -1
  261. nautobot/extras/test_jobs/pass.py +3 -3
  262. nautobot/extras/test_jobs/profiling.py +1 -1
  263. nautobot/extras/test_jobs/relative_import.py +3 -3
  264. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  265. nautobot/extras/test_jobs/task_queues.py +1 -1
  266. nautobot/extras/tests/integration/test_plugin_banner.py +2 -0
  267. nautobot/extras/tests/test_api.py +157 -55
  268. nautobot/extras/tests/test_context_managers.py +4 -1
  269. nautobot/extras/tests/test_customfields.py +1 -1
  270. nautobot/extras/tests/test_datasources.py +1 -2
  271. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  272. nautobot/extras/tests/test_filters.py +219 -535
  273. nautobot/extras/tests/test_forms.py +1 -20
  274. nautobot/extras/tests/test_job_variables.py +73 -152
  275. nautobot/extras/tests/test_jobs.py +43 -54
  276. nautobot/extras/tests/test_models.py +71 -16
  277. nautobot/extras/tests/test_relationships.py +5 -2
  278. nautobot/extras/tests/test_utils.py +23 -2
  279. nautobot/extras/tests/test_views.py +183 -43
  280. nautobot/extras/tests/test_webhooks.py +2 -1
  281. nautobot/extras/urls.py +2 -20
  282. nautobot/extras/utils.py +118 -4
  283. nautobot/extras/views.py +203 -92
  284. nautobot/extras/webhooks.py +5 -2
  285. nautobot/ipam/api/fields.py +3 -3
  286. nautobot/ipam/api/serializers.py +36 -137
  287. nautobot/ipam/api/views.py +93 -62
  288. nautobot/ipam/lookups.py +62 -101
  289. nautobot/ipam/models.py +11 -63
  290. nautobot/ipam/navigation.py +0 -90
  291. nautobot/ipam/querysets.py +2 -2
  292. nautobot/ipam/tables.py +6 -20
  293. nautobot/ipam/templates/ipam/routetarget.html +0 -28
  294. nautobot/ipam/templates/ipam/vrf.html +0 -47
  295. nautobot/ipam/tests/test_api.py +8 -419
  296. nautobot/ipam/tests/test_filters.py +39 -119
  297. nautobot/ipam/tests/test_forms.py +47 -51
  298. nautobot/ipam/tests/test_migrations.py +30 -30
  299. nautobot/ipam/tests/test_models.py +0 -41
  300. nautobot/ipam/tests/test_querysets.py +1 -63
  301. nautobot/ipam/urls.py +3 -69
  302. nautobot/ipam/utils/__init__.py +0 -24
  303. nautobot/ipam/views.py +153 -198
  304. nautobot/project-static/css/base.css +38 -3
  305. nautobot/project-static/docs/404.html +421 -19
  306. nautobot/project-static/docs/apps/index.html +421 -19
  307. nautobot/project-static/docs/apps/nautobot-apps.html +421 -19
  308. nautobot/project-static/docs/assets/extra.css +5 -1
  309. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js → bundle.83f73b43.min.js} +2 -2
  310. nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js.map → bundle.83f73b43.min.js.map} +2 -2
  311. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +421 -19
  312. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +421 -19
  313. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +421 -172
  314. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +421 -19
  315. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +421 -19
  316. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +425 -21
  317. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +421 -19
  318. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +424 -22
  319. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9809 -0
  320. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +424 -63
  321. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +421 -19
  322. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +421 -19
  323. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +457 -20
  324. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +421 -19
  325. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +425 -25
  326. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +457 -19
  327. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +421 -19
  328. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +421 -19
  329. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +425 -215
  330. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +430 -342
  331. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5799 -1054
  332. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +421 -19
  333. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +447 -176
  334. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +460 -21
  335. nautobot/project-static/docs/development/apps/api/configuration-view.html +421 -19
  336. nautobot/project-static/docs/development/apps/api/database-backend-config.html +421 -19
  337. nautobot/project-static/docs/development/apps/api/models/django-admin.html +421 -19
  338. nautobot/project-static/docs/development/apps/api/models/global-search.html +421 -19
  339. nautobot/project-static/docs/development/apps/api/models/graphql.html +421 -19
  340. nautobot/project-static/docs/development/apps/api/models/index.html +421 -19
  341. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +421 -19
  342. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +421 -19
  343. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +421 -19
  344. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +421 -19
  345. nautobot/project-static/docs/development/apps/api/platform-features/index.html +421 -19
  346. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +421 -19
  347. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +421 -19
  348. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +421 -19
  349. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +421 -19
  350. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +424 -41
  351. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +421 -19
  352. nautobot/project-static/docs/development/apps/api/prometheus.html +421 -19
  353. nautobot/project-static/docs/development/apps/api/setup.html +425 -155
  354. nautobot/project-static/docs/development/apps/api/testing.html +421 -19
  355. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +421 -19
  356. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +421 -19
  357. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +421 -19
  358. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +421 -19
  359. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +701 -130
  360. nautobot/project-static/docs/development/apps/api/views/base-template.html +421 -19
  361. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +421 -19
  362. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +421 -19
  363. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +421 -19
  364. nautobot/project-static/docs/development/apps/api/views/index.html +423 -20
  365. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +425 -19
  366. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +451 -19
  367. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +421 -19
  368. nautobot/project-static/docs/development/apps/api/views/notes.html +421 -19
  369. nautobot/project-static/docs/development/apps/api/views/rest-api.html +421 -19
  370. nautobot/project-static/docs/development/apps/api/views/urls.html +421 -19
  371. nautobot/project-static/docs/development/apps/index.html +421 -19
  372. nautobot/project-static/docs/development/apps/migration/code-updates.html +422 -52
  373. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +422 -20
  374. nautobot/project-static/docs/development/apps/migration/from-v1.html +421 -19
  375. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +421 -19
  376. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +421 -19
  377. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +421 -19
  378. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +424 -22
  379. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9219 -0
  380. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9333 -0
  381. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9474 -0
  382. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9517 -0
  383. nautobot/project-static/docs/development/apps/porting-from-netbox.html +424 -22
  384. nautobot/project-static/docs/development/core/application-registry.html +421 -19
  385. nautobot/project-static/docs/development/core/best-practices.html +421 -19
  386. nautobot/project-static/docs/development/core/bootstrap-ui.html +421 -19
  387. nautobot/project-static/docs/development/core/caching.html +421 -19
  388. nautobot/project-static/docs/development/core/controllers.html +423 -19
  389. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +490 -45
  390. nautobot/project-static/docs/development/core/generic-views.html +421 -19
  391. nautobot/project-static/docs/development/core/getting-started.html +566 -179
  392. nautobot/project-static/docs/development/core/homepage.html +432 -30
  393. nautobot/project-static/docs/development/core/index.html +421 -19
  394. nautobot/project-static/docs/development/core/local-k8s.html +9453 -0
  395. nautobot/project-static/docs/development/core/model-checklist.html +424 -22
  396. nautobot/project-static/docs/development/core/model-features.html +421 -19
  397. nautobot/project-static/docs/development/core/natural-keys.html +421 -19
  398. nautobot/project-static/docs/development/core/navigation-menu.html +438 -26
  399. nautobot/project-static/docs/development/core/release-checklist.html +435 -45
  400. nautobot/project-static/docs/development/core/role-internals.html +421 -19
  401. nautobot/project-static/docs/development/core/settings.html +421 -19
  402. nautobot/project-static/docs/development/core/style-guide.html +421 -19
  403. nautobot/project-static/docs/development/core/templates.html +431 -22
  404. nautobot/project-static/docs/development/core/testing.html +421 -19
  405. nautobot/project-static/docs/development/core/ui-component-framework.html +11020 -0
  406. nautobot/project-static/docs/development/core/user-preferences.html +424 -22
  407. nautobot/project-static/docs/development/index.html +421 -19
  408. nautobot/project-static/docs/development/jobs/index.html +546 -160
  409. nautobot/project-static/docs/development/jobs/migration/from-v1.html +421 -19
  410. nautobot/project-static/docs/index.html +421 -19
  411. nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
  412. nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
  413. nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
  414. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
  415. nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
  416. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
  417. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
  418. nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
  419. nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
  420. nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
  421. nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
  422. nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
  423. nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
  424. nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
  425. nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
  426. nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
  427. nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
  428. nautobot/project-static/docs/objects.inv +0 -0
  429. nautobot/project-static/docs/overview/application_stack.html +426 -20
  430. nautobot/project-static/docs/overview/design_philosophy.html +421 -19
  431. nautobot/project-static/docs/release-notes/index.html +445 -22
  432. nautobot/project-static/docs/release-notes/version-1.0.html +421 -19
  433. nautobot/project-static/docs/release-notes/version-1.1.html +421 -19
  434. nautobot/project-static/docs/release-notes/version-1.2.html +421 -19
  435. nautobot/project-static/docs/release-notes/version-1.3.html +421 -19
  436. nautobot/project-static/docs/release-notes/version-1.4.html +421 -19
  437. nautobot/project-static/docs/release-notes/version-1.5.html +421 -19
  438. nautobot/project-static/docs/release-notes/version-1.6.html +634 -667
  439. nautobot/project-static/docs/release-notes/version-2.0.html +421 -19
  440. nautobot/project-static/docs/release-notes/version-2.1.html +421 -19
  441. nautobot/project-static/docs/release-notes/version-2.2.html +421 -19
  442. nautobot/project-static/docs/release-notes/version-2.3.html +684 -886
  443. nautobot/project-static/docs/release-notes/version-2.4.html +10007 -0
  444. nautobot/project-static/docs/requirements.txt +2 -2
  445. nautobot/project-static/docs/search/search_index.json +1 -1
  446. nautobot/project-static/docs/sitemap.xml +334 -270
  447. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  448. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +421 -19
  449. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +421 -19
  450. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +423 -21
  451. nautobot/project-static/docs/user-guide/administration/configuration/index.html +433 -32
  452. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +421 -19
  453. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +765 -180
  454. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +421 -19
  455. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +421 -19
  456. nautobot/project-static/docs/user-guide/administration/guides/docker.html +434 -29
  457. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +421 -19
  458. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +421 -19
  459. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +421 -19
  460. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +421 -19
  461. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +421 -19
  462. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +421 -19
  463. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +421 -19
  464. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +421 -19
  465. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +421 -19
  466. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +421 -19
  467. nautobot/project-static/docs/user-guide/administration/installation/index.html +426 -20
  468. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +421 -19
  469. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +421 -19
  470. nautobot/project-static/docs/user-guide/administration/installation/services.html +421 -19
  471. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +421 -19
  472. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +442 -41
  473. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +435 -66
  474. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +435 -66
  475. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +421 -19
  476. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +421 -19
  477. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +421 -19
  478. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +421 -19
  479. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +421 -19
  480. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +421 -19
  481. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +421 -19
  482. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
  483. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +421 -19
  484. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +427 -21
  485. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +421 -19
  486. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +421 -19
  487. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +421 -19
  488. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +421 -19
  489. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +421 -19
  490. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +421 -19
  491. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +421 -19
  492. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +421 -19
  493. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +421 -19
  494. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +421 -19
  495. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +421 -19
  496. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +421 -19
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +421 -19
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +421 -19
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +421 -19
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +421 -19
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +421 -19
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +457 -20
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +447 -22
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +421 -19
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +421 -19
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +421 -19
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +421 -19
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +421 -19
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +421 -19
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +421 -19
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +421 -19
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +421 -19
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +421 -19
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +421 -19
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +421 -19
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +421 -19
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +421 -19
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +421 -19
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +421 -19
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +421 -19
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +421 -19
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +421 -19
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +421 -19
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +421 -19
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +421 -19
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +421 -19
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +421 -19
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +421 -19
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +421 -19
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +421 -19
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +421 -19
  532. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +421 -19
  533. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +421 -19
  534. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +421 -19
  535. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +421 -19
  536. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +421 -19
  537. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +421 -19
  538. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9333 -0
  539. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +424 -22
  540. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +421 -19
  541. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +421 -19
  542. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +421 -19
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +421 -19
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +421 -19
  545. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +421 -19
  546. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +421 -19
  547. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +421 -19
  548. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +421 -19
  549. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +421 -19
  550. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +421 -19
  551. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +421 -19
  552. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +421 -19
  553. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +421 -19
  554. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +421 -19
  555. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +421 -19
  556. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +421 -19
  557. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +421 -19
  558. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +421 -19
  559. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +424 -22
  560. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9271 -0
  561. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9175 -0
  562. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9169 -0
  563. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9235 -0
  564. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +421 -19
  565. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +421 -19
  566. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +421 -19
  567. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +421 -19
  568. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +421 -19
  569. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +421 -19
  570. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +421 -19
  571. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +421 -19
  572. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +421 -19
  573. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +421 -19
  574. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +421 -19
  575. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +421 -19
  576. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +421 -19
  577. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +421 -19
  578. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +421 -19
  579. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +421 -19
  580. nautobot/project-static/docs/user-guide/index.html +421 -19
  581. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +424 -22
  582. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +421 -19
  583. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +421 -19
  584. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +421 -19
  585. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +421 -19
  586. nautobot/project-static/docs/user-guide/platform-functionality/events.html +9575 -0
  587. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +424 -22
  588. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +421 -19
  589. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +421 -19
  590. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +421 -19
  591. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +421 -19
  592. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +421 -19
  593. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +426 -20
  594. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +424 -22
  595. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +421 -19
  596. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +421 -19
  597. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9182 -0
  598. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +424 -22
  599. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +421 -19
  600. nautobot/project-static/docs/user-guide/platform-functionality/note.html +421 -19
  601. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +421 -19
  602. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +424 -22
  603. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9250 -0
  604. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +421 -19
  605. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +421 -19
  606. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +424 -22
  607. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +421 -19
  608. nautobot/project-static/docs/user-guide/platform-functionality/role.html +421 -19
  609. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +421 -19
  610. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +421 -19
  611. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +424 -22
  612. nautobot/project-static/docs/user-guide/platform-functionality/status.html +421 -19
  613. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +421 -19
  614. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +489 -56
  615. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +421 -19
  616. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +421 -19
  617. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +421 -19
  618. nautobot/project-static/img/jinja_logo.svg +97 -0
  619. nautobot/project-static/js/forms.js +5 -0
  620. nautobot/project-static/js/nav_menu.js +2 -1
  621. nautobot/tenancy/api/serializers.py +0 -2
  622. nautobot/tenancy/factory.py +1 -1
  623. nautobot/tenancy/navigation.py +0 -29
  624. nautobot/tenancy/templates/tenancy/tenant.html +4 -91
  625. nautobot/tenancy/tests/test_filters.py +29 -134
  626. nautobot/tenancy/views.py +32 -23
  627. nautobot/users/admin.py +3 -1
  628. nautobot/users/api/serializers.py +4 -5
  629. nautobot/users/api/views.py +1 -1
  630. nautobot/users/forms.py +19 -0
  631. nautobot/users/templates/users/preferences.html +22 -0
  632. nautobot/users/tests/test_filters.py +1 -19
  633. nautobot/users/tests/test_views.py +57 -0
  634. nautobot/users/utils.py +8 -0
  635. nautobot/users/views.py +48 -11
  636. nautobot/virtualization/api/serializers.py +4 -4
  637. nautobot/virtualization/filters.py +2 -20
  638. nautobot/virtualization/navigation.py +0 -48
  639. nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
  640. nautobot/virtualization/tests/test_filters.py +57 -183
  641. nautobot/virtualization/views.py +18 -15
  642. nautobot/wireless/__init__.py +0 -0
  643. nautobot/wireless/api/__init__.py +0 -0
  644. nautobot/wireless/api/serializers.py +44 -0
  645. nautobot/wireless/api/urls.py +20 -0
  646. nautobot/wireless/api/views.py +34 -0
  647. nautobot/wireless/apps.py +8 -0
  648. nautobot/wireless/choices.py +345 -0
  649. nautobot/wireless/factory.py +138 -0
  650. nautobot/wireless/filters.py +167 -0
  651. nautobot/wireless/forms.py +283 -0
  652. nautobot/wireless/homepage.py +19 -0
  653. nautobot/wireless/migrations/0001_initial.py +223 -0
  654. nautobot/wireless/migrations/__init__.py +0 -0
  655. nautobot/wireless/models.py +207 -0
  656. nautobot/wireless/navigation.py +105 -0
  657. nautobot/wireless/tables.py +244 -0
  658. nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
  659. nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
  660. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
  661. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +64 -0
  662. nautobot/wireless/tests/__init__.py +0 -0
  663. nautobot/wireless/tests/test_api.py +247 -0
  664. nautobot/wireless/tests/test_filters.py +54 -0
  665. nautobot/wireless/tests/test_models.py +22 -0
  666. nautobot/wireless/tests/test_views.py +378 -0
  667. nautobot/wireless/urls.py +13 -0
  668. nautobot/wireless/views.py +129 -0
  669. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/METADATA +11 -14
  670. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/RECORD +674 -551
  671. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/WHEEL +1 -1
  672. nautobot/core/utils/navigation.py +0 -54
  673. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/LICENSE.txt +0 -0
  674. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/NOTICE +0 -0
  675. {nautobot-2.3.16.dist-info → nautobot-2.4.0b1.dist-info}/entry_points.txt +0 -0
@@ -0,0 +1,36 @@
1
+ from django.template import Context
2
+ from django.template.loader import get_template
3
+
4
+
5
+ def flatten_context(context) -> dict:
6
+ """
7
+ If the given context is already a dict, return it unmodified; if it is a Context, flatten it to a dict.
8
+
9
+ This is working around a bug (not sure if in Django or in our code) where, if a `Context`'s `dicts` contain
10
+ a `RequestContext`, calling `Context.flatten()` throws an exception.
11
+ """
12
+ if isinstance(context, dict):
13
+ return context
14
+ flat = {}
15
+ for d in context.dicts:
16
+ if isinstance(d, dict):
17
+ flat.update(d)
18
+ else:
19
+ flat.update(flatten_context(d))
20
+ return flat
21
+
22
+
23
+ def render_component_template(template_path: str, context: Context, **kwargs) -> str:
24
+ """
25
+ Render the template located at the given path with the given context, possibly augmented via additional kwargs.
26
+
27
+ Args:
28
+ template_path (str): Path to the template to render, for example `"components/tab/label_wrapper.html"`.
29
+ context (Context): Rendering context for the template
30
+ **kwargs (dict): Additional key/value pairs to extend the context with for this specific template.
31
+
32
+ Examples:
33
+ >>> render_component_template(self.label_wrapper_template_path, context, tab_id=self.tab_id, label="Hello")
34
+ """
35
+ with context.update(kwargs):
36
+ return get_template(template_path).render(flatten_context(context))
nautobot/core/urls.py CHANGED
@@ -1,5 +1,4 @@
1
1
  from django.conf import settings
2
- from django.http import HttpResponse, HttpResponseNotFound
3
2
  from django.urls import include, path
4
3
  from django.views.generic import TemplateView
5
4
  from django.views.static import serve
@@ -10,6 +9,7 @@ from nautobot.core.views import (
10
9
  HomeView,
11
10
  NautobotMetricsView,
12
11
  NautobotMetricsViewAuth,
12
+ RenderJinjaView,
13
13
  SearchView,
14
14
  StaticMediaFailureView,
15
15
  ThemePreviewView,
@@ -42,6 +42,7 @@ urlpatterns = [
42
42
  path("user/", include("nautobot.users.urls")),
43
43
  path("users/", include("nautobot.users.urls", "users")),
44
44
  path("virtualization/", include("nautobot.virtualization.urls")),
45
+ path("wireless/", include("nautobot.wireless.urls")),
45
46
  # API
46
47
  path("api/", include("nautobot.core.api.urls")),
47
48
  # GraphQL
@@ -69,18 +70,12 @@ urlpatterns = [
69
70
  ),
70
71
  # Celery worker status page
71
72
  path("worker-status/", WorkerStatusView.as_view(), name="worker_status"),
73
+ # Jinja template renderer tool
74
+ path("render-jinja-template/", RenderJinjaView.as_view(), name="render_jinja_template"),
72
75
  # Templated css file
73
76
  path(
74
77
  "template.css", TemplateView.as_view(template_name="template.css", content_type="text/css"), name="template_css"
75
78
  ),
76
- # The response is conditional as opposed to wrapping the path() call in an if statement to be able to test the setting with current test setup
77
- path(
78
- "robots.txt",
79
- lambda x: HttpResponse("User-Agent: *\nDisallow: /", content_type="text/plain")
80
- if settings.PUBLISH_ROBOTS_TXT
81
- else HttpResponseNotFound(),
82
- name="robots_txt",
83
- ),
84
79
  ]
85
80
 
86
81
 
@@ -1,12 +1,39 @@
1
1
  """Helper code for loading values that may be defined in settings.py/nautobot_config.py *or* in django-constance."""
2
2
 
3
+ import contextlib
4
+ import logging
5
+
3
6
  from constance import config
4
7
  from django.conf import settings
8
+ from django.core.exceptions import ObjectDoesNotExist
9
+ from django.db import OperationalError, ProgrammingError
10
+
11
+ logger = logging.getLogger(__name__)
12
+
5
13
 
14
+ def get_settings_or_config(variable_name, fallback=None):
15
+ """
16
+ Get a value from Django settings (if specified there) or Constance configuration (otherwise).
6
17
 
7
- def get_settings_or_config(variable_name):
8
- """Get a value from Django settings (if specified there) or Constance configuration (otherwise)."""
18
+ The fallback value is returned *only* if the requested variable cannot be found at all - this is an error case,
19
+ and will generate warning logs.
20
+ """
9
21
  # Explicitly set in settings.py or nautobot_config.py takes precedence, for now
10
22
  if hasattr(settings, variable_name):
11
23
  return getattr(settings, variable_name)
12
- return getattr(config, variable_name)
24
+ # django-constance 4.x removed some built-in error handling here, so we have to do it ourselves now
25
+ with contextlib.suppress(ObjectDoesNotExist, OperationalError, ProgrammingError):
26
+ return getattr(config, variable_name)
27
+ logger.warning(
28
+ 'Configuration "%s" is not in settings, and could not read from the Constance database table '
29
+ "(perhaps not initialized yet?)",
30
+ variable_name,
31
+ )
32
+ if variable_name in settings.CONSTANCE_CONFIG:
33
+ default = settings.CONSTANCE_CONFIG[variable_name][0]
34
+ logger.warning('Using default value of "%s" from Constance configuration for "%s"', default, variable_name)
35
+ return default
36
+ logger.warning(
37
+ 'Constance configuration does not include an entry for "%s" - must return %s', variable_name, fallback
38
+ )
39
+ return fallback
@@ -8,8 +8,9 @@ from django.conf import settings
8
8
  from django.contrib.auth.models import Group
9
9
  from django.contrib.contenttypes.models import ContentType
10
10
  from django.db.models import Model
11
- from django.urls import get_resolver, resolve, reverse, URLPattern, URLResolver
11
+ from django.urls import get_resolver, URLPattern, URLResolver
12
12
  from django.utils.module_loading import import_string
13
+ from django.views.generic.base import RedirectView
13
14
 
14
15
 
15
16
  def get_changes_for_model(model):
@@ -212,7 +213,7 @@ def get_related_field_for_models(from_model, to_model):
212
213
  return matching_field
213
214
 
214
215
 
215
- def get_table_for_model(model, suffix=None):
216
+ def get_table_for_model(model):
216
217
  """Return the `Table` class associated with a given `model`.
217
218
 
218
219
  The `Table` class is expected to be in the `tables` module within the application
@@ -222,12 +223,11 @@ def get_table_for_model(model, suffix=None):
222
223
 
223
224
  Args:
224
225
  model (BaseModel): A model class
225
- suffix (str): A replacement suffix for the table name (e.g. `DetailTable`, such as to retrieve `FooDetailTable`)
226
226
 
227
227
  Returns:
228
228
  (Union[Table, None]): Either the `Table` class or `None`
229
229
  """
230
- return get_related_class_for_model(model, module_name="tables", object_suffix=suffix or "Table")
230
+ return get_related_class_for_model(model, module_name="tables", object_suffix="Table")
231
231
 
232
232
 
233
233
  def get_view_for_model(model, view_type=""):
@@ -276,13 +276,11 @@ def get_table_class_string_from_view_name(view_name):
276
276
  Returns:
277
277
  table_class_name (String): The name of the model table class or None e.g. LocationTable, CircuitTable
278
278
  """
279
-
280
- view_func = resolve(reverse(view_name)).func
281
- view_class = getattr(view_func, "cls", getattr(view_func, "view_class", None))
282
- if hasattr(view_class, "table_class"):
283
- return view_class.table_class.__name__
284
- if hasattr(view_class, "table"):
285
- return view_class.table.__name__
279
+ model = get_model_for_view_name(view_name)
280
+ if model:
281
+ table_class = get_table_for_model(model)
282
+ if table_class:
283
+ return table_class.__name__
286
284
  return None
287
285
 
288
286
 
@@ -315,7 +313,7 @@ def get_created_and_last_updated_usernames_for_model(instance):
315
313
  return created_by, last_updated_by
316
314
 
317
315
 
318
- def get_url_patterns(urlconf=None, patterns_list=None, base_path="/"):
316
+ def get_url_patterns(urlconf=None, patterns_list=None, base_path="/", ignore_redirects=False):
319
317
  """
320
318
  Recursively yield a list of registered URL patterns.
321
319
 
@@ -326,6 +324,7 @@ def get_url_patterns(urlconf=None, patterns_list=None, base_path="/"):
326
324
  Default if unspecified is the `url_patterns` attribute of the given `urlconf` module.
327
325
  base_path (str): String to prepend to all URL patterns yielded.
328
326
  Default if unspecified is the string `"/"`.
327
+ ignore_redirects (bool): If True, skip URL patterns that correspond to RedirectViews.
329
328
 
330
329
  Yields:
331
330
  (str): Each URL pattern defined in the given urlconf and its descendants
@@ -384,10 +383,18 @@ def get_url_patterns(urlconf=None, patterns_list=None, base_path="/"):
384
383
 
385
384
  for item in patterns_list:
386
385
  if isinstance(item, URLPattern):
386
+ if (
387
+ ignore_redirects
388
+ and hasattr(item.callback, "view_class")
389
+ and issubclass(item.callback.view_class, RedirectView)
390
+ ):
391
+ continue
387
392
  yield base_path + str(item.pattern)
388
393
  elif isinstance(item, URLResolver):
389
394
  # Recurse!
390
- yield from get_url_patterns(urlconf, item.url_patterns, base_path + str(item.pattern))
395
+ yield from get_url_patterns(
396
+ urlconf, item.url_patterns, base_path + str(item.pattern), ignore_redirects=ignore_redirects
397
+ )
391
398
 
392
399
 
393
400
  def get_url_for_url_pattern(url_pattern):
@@ -56,7 +56,6 @@ logger = logging.getLogger(__name__)
56
56
 
57
57
  class HomeView(AccessMixin, TemplateView):
58
58
  template_name = "home.html"
59
- use_new_ui = True
60
59
 
61
60
  def render_additional_content(self, request, context, details):
62
61
  # Collect all custom data using callback functions.
@@ -479,3 +478,9 @@ def get_file_with_authorization(request, *args, **kwargs):
479
478
  get_object_or_404(queryset, file=request.GET.get("name"))
480
479
 
481
480
  return get_file(request, *args, **kwargs)
481
+
482
+
483
+ class RenderJinjaView(LoginRequiredMixin, TemplateView):
484
+ """Render a Jinja template with context data."""
485
+
486
+ template_name = "utilities/render_jinja2.html"
@@ -1,9 +1,6 @@
1
- from __future__ import annotations # python 3.8
2
-
3
1
  from copy import deepcopy
4
2
  import logging
5
3
  import re
6
- from typing import Optional
7
4
 
8
5
  from django.conf import settings
9
6
  from django.contrib import messages
@@ -16,7 +13,7 @@ from django.core.exceptions import (
16
13
  ValidationError,
17
14
  )
18
15
  from django.db import IntegrityError, transaction
19
- from django.db.models import ManyToManyField, Model, ProtectedError, Q, QuerySet
16
+ from django.db.models import ManyToManyField, ProtectedError, Q
20
17
  from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput
21
18
  from django.http import HttpResponse
22
19
  from django.shortcuts import get_object_or_404, redirect, render
@@ -25,10 +22,10 @@ from django.utils.encoding import iri_to_uri
25
22
  from django.utils.html import format_html
26
23
  from django.utils.http import url_has_allowed_host_and_scheme
27
24
  from django.views.generic import View
28
- from django_filters import FilterSet
29
- from django_tables2 import RequestConfig, Table
25
+ from django_tables2 import RequestConfig
30
26
 
31
27
  from nautobot.core.api.utils import get_serializer_for_model
28
+ from nautobot.core.constants import MAX_PAGE_SIZE_DEFAULT
32
29
  from nautobot.core.exceptions import AbortTransaction
33
30
  from nautobot.core.forms import (
34
31
  BootstrapMixin,
@@ -82,8 +79,9 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
82
79
  template_name: Name of the template to use
83
80
  """
84
81
 
85
- queryset: QuerySet
86
- template_name: Optional[str] = None
82
+ queryset = None
83
+ template_name = None
84
+ object_detail_content = None
87
85
 
88
86
  def get_required_permission(self):
89
87
  return get_permission_for_model(self.queryset.model, "view")
@@ -123,6 +121,7 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
123
121
  "content_type": content_type,
124
122
  "verbose_name": self.queryset.model._meta.verbose_name,
125
123
  "verbose_name_plural": self.queryset.model._meta.verbose_name_plural,
124
+ "object_detail_content": self.object_detail_content,
126
125
  **common_detail_view_context(request, instance),
127
126
  **self.get_extra_context(request, instance),
128
127
  }
@@ -143,10 +142,10 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
143
142
  non_filter_params: List of query parameters that are **not** used for queryset filtering
144
143
  """
145
144
 
146
- queryset: QuerySet
147
- filterset: Optional[type[FilterSet]] = None
148
- filterset_form: Optional[type[Form]] = None
149
- table: Optional[type[Table]] = None
145
+ queryset = None
146
+ filterset = None
147
+ filterset_form = None
148
+ table = None
150
149
  template_name = "generic/object_list.html"
151
150
  action_buttons = ("add", "import", "export")
152
151
  non_filter_params = (
@@ -163,11 +162,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
163
162
  def get_filter_params(self, request):
164
163
  """Helper function - take request.GET and discard any parameters that are not used for queryset filtering."""
165
164
  params = request.GET.copy()
166
- filter_params = get_filterable_params_from_filter_params(
167
- params,
168
- self.non_filter_params,
169
- self.filterset(), # pylint: disable=not-callable # this fn is only called if filterset is not None
170
- )
165
+ filter_params = get_filterable_params_from_filter_params(params, self.non_filter_params, self.filterset())
171
166
  if params.get("saved_view") and not filter_params and not params.get("all_filters_removed"):
172
167
  return SavedView.objects.get(pk=params.get("saved_view")).config.get("filter_params", {})
173
168
  return filter_params
@@ -241,9 +236,9 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
241
236
  except ObjectDoesNotExist:
242
237
  pass
243
238
 
244
- if self.filterset is not None:
239
+ if self.filterset:
245
240
  filter_params = self.get_filter_params(request)
246
- filterset = self.filterset(filter_params, self.queryset) # pylint:disable=not-callable # only if not None
241
+ filterset = self.filterset(filter_params, self.queryset)
247
242
  self.queryset = filterset.qs
248
243
  if not filterset.is_valid():
249
244
  messages.error(
@@ -271,7 +266,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
271
266
  else:
272
267
  dynamic_filter_form = DynamicFilterFormSet(filterset=filterset)
273
268
 
274
- if self.filterset_form is not None:
269
+ if self.filterset_form:
275
270
  filter_form = self.filterset_form(filter_params, label_suffix="")
276
271
 
277
272
  # Check for export template rendering
@@ -331,14 +326,14 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
331
326
  messages.error(request, f"Saved view {current_saved_view_pk} not found")
332
327
 
333
328
  # Construct the objects table
334
- if self.table is not None:
329
+ if self.table:
335
330
  if self.request.GET.getlist("sort") or (
336
331
  current_saved_view is not None and current_saved_view.config.get("sort_order")
337
332
  ):
338
333
  hide_hierarchy_ui = True # hide tree hierarchy if custom sort is used
339
334
  table_changes_pending = self.request.GET.get("table_changes_pending", False)
340
335
 
341
- table = self.table( # pylint: disable=not-callable # we confirmed that self.table is not None
336
+ table = self.table(
342
337
  self.queryset,
343
338
  table_changes_pending=table_changes_pending,
344
339
  saved_view=current_saved_view,
@@ -355,7 +350,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
355
350
  }
356
351
  RequestConfig(request, paginate).configure(table)
357
352
  table_config_form = TableConfigForm(table=table)
358
- max_page_size = get_settings_or_config("MAX_PAGE_SIZE")
353
+ max_page_size = get_settings_or_config("MAX_PAGE_SIZE", fallback=MAX_PAGE_SIZE_DEFAULT)
359
354
  if max_page_size and paginate["per_page"] > max_page_size:
360
355
  messages.warning(
361
356
  request,
@@ -415,8 +410,8 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
415
410
  template_name: The name of the template
416
411
  """
417
412
 
418
- queryset: QuerySet
419
- model_form: type[Form]
413
+ queryset = None
414
+ model_form = None
420
415
  template_name = "generic/object_create.html"
421
416
 
422
417
  def get_required_permission(self):
@@ -558,7 +553,7 @@ class ObjectDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
558
553
  template_name: The name of the template
559
554
  """
560
555
 
561
- queryset: QuerySet
556
+ queryset = None
562
557
  template_name = "generic/object_delete.html"
563
558
 
564
559
  def get_required_permission(self):
@@ -638,9 +633,9 @@ class BulkCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
638
633
  template_name: The name of the template
639
634
  """
640
635
 
641
- queryset: QuerySet
642
- form: type[Form]
643
- model_form: type[Form]
636
+ queryset = None
637
+ form = None
638
+ model_form = None
644
639
  pattern_target = ""
645
640
  template_name = None
646
641
 
@@ -747,8 +742,8 @@ class ObjectImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
747
742
  template_name: The name of the template
748
743
  """
749
744
 
750
- queryset: QuerySet
751
- model_form: type[Form]
745
+ queryset = None
746
+ model_form = None
752
747
  related_object_forms = {}
753
748
  template_name = "generic/object_import.html"
754
749
 
@@ -892,8 +887,8 @@ class BulkImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): #
892
887
  template_name: The name of the template
893
888
  """
894
889
 
895
- queryset: QuerySet
896
- table: type[Table]
890
+ queryset = None
891
+ table = None
897
892
  template_name = "generic/object_bulk_import.html"
898
893
 
899
894
  def __init__(self, *args, **kwargs):
@@ -998,10 +993,10 @@ class BulkEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, EditAndDele
998
993
  template_name: The name of the template
999
994
  """
1000
995
 
1001
- queryset: QuerySet
1002
- filterset: Optional[type[FilterSet]] = None
1003
- table: type[Table]
1004
- form: type[Form]
996
+ queryset = None
997
+ filterset = None
998
+ table = None
999
+ form = None
1005
1000
  template_name = "generic/object_bulk_edit.html"
1006
1001
 
1007
1002
  def get_required_permission(self):
@@ -1172,7 +1167,7 @@ class BulkRenameView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
1172
1167
  An extendable view for renaming objects in bulk.
1173
1168
  """
1174
1169
 
1175
- queryset: QuerySet
1170
+ queryset = None
1176
1171
  template_name = "generic/object_bulk_rename.html"
1177
1172
 
1178
1173
  def __init__(self, *args, **kwargs):
@@ -1278,10 +1273,10 @@ class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, EditAndDe
1278
1273
  template_name: The name of the template
1279
1274
  """
1280
1275
 
1281
- queryset: QuerySet
1282
- filterset: Optional[type[FilterSet]] = None
1283
- table: type[Table]
1284
- form: Optional[type[Form]] = None
1276
+ queryset = None
1277
+ filterset = None
1278
+ table = None
1279
+ form = None
1285
1280
  template_name = "generic/object_bulk_delete.html"
1286
1281
 
1287
1282
  def get_required_permission(self):
@@ -1396,9 +1391,9 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
1396
1391
  Add one or more components (e.g. interfaces, console ports, etc.) to a Device or VirtualMachine.
1397
1392
  """
1398
1393
 
1399
- queryset: QuerySet
1400
- form: type[Form]
1401
- model_form: type[Form]
1394
+ queryset = None
1395
+ form = None
1396
+ model_form = None
1402
1397
  template_name = "dcim/device_component_add.html"
1403
1398
 
1404
1399
  def get_required_permission(self):
@@ -1498,13 +1493,13 @@ class BulkComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin,
1498
1493
  Add one or more components (e.g. interfaces, console ports, etc.) to a set of Devices or VirtualMachines.
1499
1494
  """
1500
1495
 
1501
- parent_model: type[Model]
1496
+ parent_model = None
1502
1497
  parent_field = None
1503
- form: type[Form]
1504
- queryset: QuerySet
1505
- model_form: type[Form]
1506
- filterset: Optional[type[FilterSet]] = None
1507
- table: type[Table]
1498
+ form = None
1499
+ queryset = None
1500
+ model_form = None
1501
+ filterset = None
1502
+ table = None
1508
1503
  template_name = "generic/object_bulk_add_component.html"
1509
1504
 
1510
1505
  def get_required_permission(self):
@@ -1518,7 +1513,7 @@ class BulkComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin,
1518
1513
 
1519
1514
  # Are we editing *all* objects in the queryset or just a selected subset?
1520
1515
  if request.POST.get("_all") and self.filterset is not None:
1521
- pk_list = [obj.pk for obj in self.filterset(request.GET, self.parent_model.objects.only("pk")).qs] # pylint: disable=not-callable
1516
+ pk_list = [obj.pk for obj in self.filterset(request.GET, self.parent_model.objects.only("pk")).qs]
1522
1517
  else:
1523
1518
  pk_list = request.POST.getlist("pk")
1524
1519
 
@@ -1,7 +1,4 @@
1
- from __future__ import annotations # python 3.8
2
-
3
1
  import logging
4
- from typing import Optional
5
2
 
6
3
  from django.contrib import messages
7
4
  from django.contrib.auth.mixins import AccessMixin
@@ -25,7 +22,6 @@ from django.utils.encoding import iri_to_uri
25
22
  from django.utils.html import format_html
26
23
  from django.utils.http import url_has_allowed_host_and_scheme
27
24
  from django.views.generic.edit import FormView
28
- from django_filters import FilterSet
29
25
  from drf_spectacular.utils import extend_schema
30
26
  from rest_framework import exceptions, mixins
31
27
  from rest_framework.decorators import action as drf_action
@@ -227,7 +223,7 @@ class NautobotViewSetMixin(GenericViewSet, AccessMixin, GetReturnURLMixin, FormV
227
223
  # filterset and filter_params will be initialized in filter_queryset() in ObjectListViewMixin
228
224
  filter_params = None
229
225
  filterset = None
230
- filterset_class: Optional[type[FilterSet]] = None
226
+ filterset_class = None
231
227
  filterset_form_class = None
232
228
  form_class = None
233
229
  create_form_class = None
@@ -477,11 +473,7 @@ class NautobotViewSetMixin(GenericViewSet, AccessMixin, GetReturnURLMixin, FormV
477
473
  def get_filter_params(self, request):
478
474
  """Helper function - take request.GET and discard any parameters that are not used for queryset filtering."""
479
475
  params = request.GET.copy()
480
- filter_params = get_filterable_params_from_filter_params(
481
- params,
482
- self.non_filter_params,
483
- self.filterset_class(), # pylint: disable=not-callable # only called if filterset_class is not None
484
- )
476
+ filter_params = get_filterable_params_from_filter_params(params, self.non_filter_params, self.filterset_class())
485
477
  if params.get("saved_view") and not filter_params and not params.get("all_filters_removed"):
486
478
  return SavedView.objects.get(pk=params.get("saved_view")).config.get("filter_params", {})
487
479
  return filter_params
@@ -622,12 +614,13 @@ class ObjectDetailViewMixin(NautobotViewSetMixin, mixins.RetrieveModelMixin):
622
614
  UI mixin to retrieve a model instance.
623
615
  """
624
616
 
617
+ object_detail_content = None
618
+
625
619
  def retrieve(self, request, *args, **kwargs):
626
620
  """
627
621
  Retrieve a model instance.
628
622
  """
629
- context = {"use_new_ui": True}
630
- return Response(context)
623
+ return Response({})
631
624
 
632
625
 
633
626
  class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
@@ -636,8 +629,8 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
636
629
  """
637
630
 
638
631
  action_buttons = ("add", "import", "export")
639
- filterset_class: Optional[type[FilterSet]] = None
640
- filterset_form_class: Optional[type[Form]] = None
632
+ filterset_class = None
633
+ filterset_form_class = None
641
634
  hide_hierarchy_ui = False
642
635
  non_filter_params = (
643
636
  "export", # trigger for CSV/export-template/YAML export # 3.0 TODO: remove, irrelevant after #4746
@@ -713,7 +706,6 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
713
706
  """
714
707
  List the model instances.
715
708
  """
716
- context = {"use_new_ui": True}
717
709
  queryset = self.get_queryset()
718
710
  clear_view = request.GET.get("clear_view", False)
719
711
  if "export" in request.GET: # 3.0 TODO: remove, irrelevant after #4746
@@ -751,7 +743,7 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
751
743
  except ObjectDoesNotExist:
752
744
  pass
753
745
 
754
- return Response(context)
746
+ return Response({})
755
747
 
756
748
 
757
749
  class ObjectDestroyViewMixin(NautobotViewSetMixin, mixins.DestroyModelMixin):
@@ -788,8 +780,7 @@ class ObjectDestroyViewMixin(NautobotViewSetMixin, mixins.DestroyModelMixin):
788
780
  return self.perform_destroy(request, **kwargs)
789
781
  return Response(context)
790
782
 
791
- # TODO: this conflicts with DRF's DestroyModelMixin.perform_destroy(self, instance) API
792
- def perform_destroy(self, request, **kwargs): # pylint:disable=arguments-renamed
783
+ def perform_destroy(self, request, **kwargs):
793
784
  """
794
785
  Function to validate the ObjectDeleteConfirmationForm and to delete the object.
795
786
  """
@@ -943,7 +934,7 @@ class EditAndDeleteAllModelMixin:
943
934
  filterset_class = getattr(self, "filterset_class", None)
944
935
 
945
936
  if request.GET and filterset_class is not None:
946
- queryset = filterset_class(request.GET, model.objects.all()).qs # pylint: disable=not-callable
937
+ queryset = filterset_class(request.GET, model.objects.all()).qs
947
938
  # We take this approach because filterset.qs has already applied .distinct(),
948
939
  # and performing a .delete directly on a queryset with .distinct applied is not allowed.
949
940
  queryset = self.queryset.filter(pk__in=queryset)
@@ -967,8 +958,8 @@ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, Ed
967
958
  UI mixin to bulk destroy model instances.
968
959
  """
969
960
 
970
- bulk_destroy_form_class: Optional[type[Form]] = None
971
- filterset_class: Optional[type[FilterSet]] = None
961
+ bulk_destroy_form_class = None
962
+ filterset_class = None
972
963
 
973
964
  def _process_bulk_destroy_form(self, form):
974
965
  request = self.request
@@ -1001,8 +992,7 @@ class ObjectBulkDestroyViewMixin(NautobotViewSetMixin, BulkDestroyModelMixin, Ed
1001
992
  """
1002
993
  return self.perform_bulk_destroy(request, **kwargs)
1003
994
 
1004
- # TODO: this conflicts with BulkDestroyModelMixin.perform_bulk_destroy(self, objects)
1005
- def perform_bulk_destroy(self, request, **kwargs): # pylint:disable=arguments-renamed
995
+ def perform_bulk_destroy(self, request, **kwargs):
1006
996
  """
1007
997
  request.POST "_delete": Function to render the user selection of objects in a table form/BulkDestroyConfirmationForm via Response that is passed to NautobotHTMLRenderer.
1008
998
  request.POST "_confirm": Function to validate the table form/BulkDestroyConfirmationForm and to perform the action of bulk destroy. Render the form with errors if exceptions are raised.
@@ -1097,8 +1087,8 @@ class ObjectBulkUpdateViewMixin(NautobotViewSetMixin, BulkUpdateModelMixin, Edit
1097
1087
  UI mixin to bulk update model instances.
1098
1088
  """
1099
1089
 
1100
- filterset_class: Optional[type[FilterSet]] = None
1101
- bulk_update_form_class: Optional[type[Form]] = None
1090
+ filterset_class = None
1091
+ bulk_update_form_class = None
1102
1092
 
1103
1093
  def _process_bulk_update_form(self, form):
1104
1094
  request = self.request
@@ -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)