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
@@ -65,45 +65,20 @@ class VRFTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterT
65
65
  tenancy_related_name = "vrfs"
66
66
  # skip testing "rd" attribute for generic q filter test as it's not trivially modifiable
67
67
  exclude_q_filter_predicates = ["rd"]
68
+ generic_filter_tests = (
69
+ ("export_targets", "export_targets__id"),
70
+ ("export_targets", "export_targets__name"),
71
+ ("import_targets", "import_targets__id"),
72
+ ("import_targets", "import_targets__name"),
73
+ ("name",),
74
+ ("rd",),
75
+ )
68
76
 
69
77
  @classmethod
70
78
  def setUpTestData(cls):
71
79
  instance = cls.queryset.first()
72
80
  instance.tags.set(Tag.objects.all()[:2])
73
81
 
74
- def test_name(self):
75
- names = list(self.queryset.values_list("name", flat=True))[:2]
76
- params = {"name": names}
77
- self.assertQuerysetEqual(self.filterset(params, self.queryset).qs, self.queryset.filter(name__in=names))
78
-
79
- def test_rd(self):
80
- vrfs = self.queryset.filter(rd__isnull=False)[:2]
81
- params = {"rd": [vrfs[0].rd, vrfs[1].rd]}
82
- self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
83
-
84
- def test_import_targets(self):
85
- route_targets = list(RouteTarget.objects.filter(importing_vrfs__isnull=False).distinct())[:2]
86
- params = {"import_targets": [route_targets[0].pk, route_targets[1].name]}
87
- self.assertQuerysetEqualAndNotEmpty(
88
- self.filterset(params, self.queryset).qs,
89
- self.queryset.filter(import_targets__in=route_targets).distinct(),
90
- ordered=False,
91
- )
92
-
93
- def test_export_targets(self):
94
- route_targets = list(RouteTarget.objects.filter(exporting_vrfs__isnull=False).distinct())[:2]
95
- params = {"export_targets": [route_targets[0].pk, route_targets[1].name]}
96
- self.assertQuerysetEqualAndNotEmpty(
97
- self.filterset(params, self.queryset).qs,
98
- self.queryset.filter(export_targets__in=route_targets).distinct(),
99
- ordered=False,
100
- )
101
-
102
- def test_search(self):
103
- value = self.queryset.values_list("pk", flat=True)[0]
104
- params = {"q": value}
105
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
106
-
107
82
 
108
83
  class RouteTargetTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
109
84
  queryset = RouteTarget.objects.all()
@@ -111,44 +86,27 @@ class RouteTargetTestCase(FilterTestCases.FilterTestCase, FilterTestCases.Tenanc
111
86
  tenancy_related_name = "route_targets"
112
87
  # skip testing "name" attribute for generic q filter test as it's not trivially modifiable
113
88
  exclude_q_filter_predicates = ["name"]
89
+ generic_filter_tests = (
90
+ ("exporting_vrfs", "exporting_vrfs__id"),
91
+ ("exporting_vrfs", "exporting_vrfs__rd"),
92
+ ("importing_vrfs", "importing_vrfs__id"),
93
+ ("importing_vrfs", "importing_vrfs__rd"),
94
+ ("name",),
95
+ )
114
96
 
115
97
  @classmethod
116
98
  def setUpTestData(cls):
117
99
  instance = cls.queryset.first()
118
100
  instance.tags.set(Tag.objects.all()[:2])
119
101
 
120
- def test_name(self):
121
- params = {"name": [self.queryset[0].name, self.queryset[1].name, self.queryset[2].name]}
122
- self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
123
-
124
- def test_importing_vrfs(self):
125
- vrfs = list(VRF.objects.filter(import_targets__isnull=False, rd__isnull=False).distinct())[:2]
126
- params = {"importing_vrfs": [vrfs[0].pk, vrfs[1].rd]}
127
- self.assertQuerysetEqualAndNotEmpty(
128
- self.filterset(params, self.queryset).qs, self.queryset.filter(importing_vrfs__in=vrfs).distinct()
129
- )
130
102
 
131
- def test_exporting_vrfs(self):
132
- vrfs = list(VRF.objects.filter(export_targets__isnull=False, rd__isnull=False).distinct())[:2]
133
- params = {"exporting_vrfs": [vrfs[0].pk, vrfs[1].rd]}
134
- self.assertQuerysetEqualAndNotEmpty(
135
- self.filterset(params, self.queryset).qs, self.queryset.filter(exporting_vrfs__in=vrfs).distinct()
136
- )
137
-
138
- def test_search(self):
139
- value = self.queryset.values_list("pk", flat=True)[0]
140
- params = {"q": value}
141
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
142
-
143
-
144
- class RIRTestCase(FilterTestCases.NameOnlyFilterTestCase):
103
+ class RIRTestCase(FilterTestCases.FilterTestCase):
145
104
  queryset = RIR.objects.all()
146
105
  filterset = RIRFilterSet
147
-
148
- def test_description(self):
149
- descriptions = self.queryset.exclude(description="").values_list("description", flat=True)[:2]
150
- params = {"description": list(descriptions)}
151
- self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
106
+ generic_filter_tests = (
107
+ ("description",),
108
+ ("name",),
109
+ )
152
110
 
153
111
  def test_is_private(self):
154
112
  params = {"is_private": "true"}
@@ -224,8 +182,8 @@ class PrefixTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilt
224
182
  class PrefixLocationAssignmentTestCase(FilterTestCases.FilterTestCase):
225
183
  queryset = PrefixLocationAssignment.objects.all()
226
184
  filterset = PrefixLocationAssignmentFilterSet
227
-
228
185
  # NOTE: No generic logic in place yet to test TreeNodeMultipleChoiceFilter
186
+ generic_filter_tests = ()
229
187
  # generic_filter_tests = (
230
188
  # ["location", "location__name"],
231
189
  # ["location", "location__id"],
@@ -1022,9 +980,16 @@ class IPAddressToInterfaceTestCase(FilterTestCases.FilterTestCase):
1022
980
  )
1023
981
 
1024
982
 
1025
- class VLANGroupTestCase(FilterTestCases.NameOnlyFilterTestCase):
983
+ class VLANGroupTestCase(FilterTestCases.FilterTestCase):
1026
984
  queryset = VLANGroup.objects.all()
1027
985
  filterset = VLANGroupFilterSet
986
+ generic_filter_tests = (
987
+ ("description",),
988
+ # NOTE: No generic logic in place yet to test TreeNodeMultipleChoiceFilter
989
+ # ("location", "location__id"),
990
+ # ("location", "location__name"),
991
+ ("name",),
992
+ )
1028
993
 
1029
994
  @classmethod
1030
995
  def setUpTestData(cls):
@@ -1044,26 +1009,21 @@ class VLANGroupTestCase(FilterTestCases.NameOnlyFilterTestCase):
1044
1009
  VLANGroup.objects.create(name="VLAN Group 3", location=cls.locations[2], description="C")
1045
1010
  VLANGroup.objects.create(name="VLAN Group 4", location=None)
1046
1011
 
1047
- def test_description(self):
1048
- descriptions = list(VLANGroup.objects.exclude(description="").values_list("description", flat=True)[:2])
1049
- params = {"description": descriptions}
1050
- self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
1051
-
1052
- def test_location(self):
1053
- params = {"location": [self.locations[0].pk, self.locations[1].pk]}
1054
- self.assertQuerysetEqual(
1055
- self.filterset(params, self.queryset).qs, self.queryset.filter(location__in=params["location"])
1056
- )
1057
- params = {"location": [self.locations[0].name, self.locations[1].name]}
1058
- self.assertQuerysetEqual(
1059
- self.filterset(params, self.queryset).qs, self.queryset.filter(location__name__in=params["location"])
1060
- )
1061
-
1062
1012
 
1063
1013
  class VLANTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
1064
1014
  queryset = VLAN.objects.all()
1065
1015
  filterset = VLANFilterSet
1066
1016
  tenancy_related_name = "vlans"
1017
+ generic_filter_tests = (
1018
+ ("name",),
1019
+ ("role", "role__id"),
1020
+ ("role", "role__name"),
1021
+ ("status", "status__id"),
1022
+ ("status", "status__name"),
1023
+ ("vid",),
1024
+ ("vlan_group", "vlan_group__id"),
1025
+ ("vlan_group", "vlan_group__name"),
1026
+ )
1067
1027
 
1068
1028
  @classmethod
1069
1029
  def setUpTestData(cls):
@@ -1149,16 +1109,6 @@ class VLANTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilter
1149
1109
  vlans[0].tags.set(Tag.objects.all()[:2])
1150
1110
  vlans[1].tags.set(Tag.objects.all()[:2])
1151
1111
 
1152
- def test_name(self):
1153
- names = list(VLAN.objects.all().values_list("name", flat=True)[:2])
1154
- params = {"name": names}
1155
- self.assertQuerysetEqual(self.filterset(params, self.queryset).qs, self.queryset.filter(name__in=names))
1156
-
1157
- def test_vid(self):
1158
- vids = list(VLAN.objects.all().values_list("vid", flat=True)[:3])
1159
- params = {"vid": vids}
1160
- self.assertQuerysetEqual(self.filterset(params, self.queryset).qs, self.queryset.filter(vid__in=vids))
1161
-
1162
1112
  def test_location(self):
1163
1113
  params = {"location": [self.locations[0].pk, self.locations[1].pk]}
1164
1114
  self.assertQuerysetEqual(
@@ -1181,31 +1131,6 @@ class VLANTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilter
1181
1131
  self.queryset.filter(locations__name__in=params["locations"]).distinct(),
1182
1132
  )
1183
1133
 
1184
- def test_vlan_group(self):
1185
- groups = list(VLANGroup.objects.filter(vlans__isnull=False).distinct())[:2]
1186
- filter_params = [{"vlan_group": [groups[0].pk, groups[1].pk]}, {"vlan_group": [groups[0].pk, groups[1].name]}]
1187
- for params in filter_params:
1188
- self.assertQuerysetEqualAndNotEmpty(
1189
- self.filterset(params, self.queryset).qs, self.queryset.filter(vlan_group__in=groups)
1190
- )
1191
-
1192
- def test_role(self):
1193
- roles = Role.objects.get_for_model(VLAN)[:2]
1194
- params = {"role": [roles[0].pk, roles[1].name]}
1195
- self.assertQuerysetEqualAndNotEmpty(
1196
- self.filterset(params, self.queryset).qs, self.queryset.filter(role__in=[roles[0], roles[1]])
1197
- )
1198
-
1199
- def test_status(self):
1200
- statuses = list(Status.objects.get_for_model(VLAN).filter(vlans__isnull=False).distinct())[:2]
1201
- params = {"status": [statuses[0].name, statuses[1].id]}
1202
- self.assertQuerysetEqual(self.filterset(params, self.queryset).qs, self.queryset.filter(status__in=statuses))
1203
-
1204
- def test_search(self):
1205
- value = self.queryset.values_list("pk", flat=True)[0]
1206
- params = {"q": value}
1207
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
1208
-
1209
1134
  def test_available_on_device(self):
1210
1135
  manufacturer = Manufacturer.objects.first()
1211
1136
  devicetype = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1")
@@ -1361,8 +1286,3 @@ class ServiceTestCase(FilterTestCases.FilterTestCase):
1361
1286
  def test_ports(self):
1362
1287
  params = {"ports": "1001"}
1363
1288
  self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
1364
-
1365
- def test_search(self):
1366
- value = self.queryset.values_list("pk", flat=True)[0]
1367
- params = {"q": value}
1368
- self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
@@ -1,8 +1,5 @@
1
1
  """Test IPAM forms."""
2
2
 
3
- from __future__ import annotations # python 3.8
4
-
5
- from django.forms import Form
6
3
  from django.test import TestCase
7
4
 
8
5
  from nautobot.core.testing.forms import FormTestCases
@@ -12,63 +9,62 @@ from nautobot.ipam.choices import IPAddressTypeChoices
12
9
  from nautobot.ipam.models import IPAddress, Namespace, Prefix
13
10
 
14
11
 
15
- class NetworkFormTestCases:
16
- class BaseNetworkFormTest(TestCase):
17
- form_class: type[Form]
18
- field_name: str
19
- object_name: str
20
- extra_data = {}
21
-
22
- def setUp(self):
23
- super().setUp()
24
- self.namespace = Namespace.objects.create(name="IPAM Form Test")
25
- self.status = Status.objects.get(name="Active")
26
- self.prefix_status = Status.objects.get_for_model(Prefix).first()
27
- self.ip_status = Status.objects.get_for_model(IPAddress).first()
28
- self.parent = Prefix.objects.create(
29
- prefix="192.168.1.0/24", namespace=self.namespace, status=self.prefix_status
30
- )
31
- self.parent2 = Prefix.objects.create(
32
- prefix="192.168.0.0/16", namespace=self.namespace, status=self.prefix_status
33
- )
34
- self.parent6 = Prefix.objects.create(
35
- prefix="2001:0db8::/40", namespace=self.namespace, status=self.prefix_status
36
- )
12
+ class BaseNetworkFormTest:
13
+ form_class = None
14
+ field_name = None
15
+ object_name = None
16
+ extra_data = {}
37
17
 
38
- def test_valid_ip_address(self):
39
- data = {self.field_name: "192.168.2.0/24", "namespace": self.namespace, "status": self.status}
40
- data.update(self.extra_data)
41
- form = self.form_class(data)
18
+ def setUp(self):
19
+ super().setUp()
20
+ self.namespace = Namespace.objects.create(name="IPAM Form Test")
21
+ self.status = Status.objects.get(name="Active")
22
+ self.prefix_status = Status.objects.get_for_model(Prefix).first()
23
+ self.ip_status = Status.objects.get_for_model(IPAddress).first()
24
+ self.parent = Prefix.objects.create(
25
+ prefix="192.168.1.0/24", namespace=self.namespace, status=self.prefix_status
26
+ )
27
+ self.parent2 = Prefix.objects.create(
28
+ prefix="192.168.0.0/16", namespace=self.namespace, status=self.prefix_status
29
+ )
30
+ self.parent6 = Prefix.objects.create(
31
+ prefix="2001:0db8::/40", namespace=self.namespace, status=self.prefix_status
32
+ )
42
33
 
43
- self.assertTrue(form.is_valid())
44
- self.assertTrue(form.save())
34
+ def test_valid_ip_address(self):
35
+ data = {self.field_name: "192.168.2.0/24", "namespace": self.namespace, "status": self.status}
36
+ data.update(self.extra_data)
37
+ form = self.form_class(data)
45
38
 
46
- def test_address_invalid_ipv4(self):
47
- data = {self.field_name: "192.168.0.1/64", "namespace": self.namespace, "status": self.status}
48
- data.update(self.extra_data)
49
- form = self.form_class(data)
39
+ self.assertTrue(form.is_valid())
40
+ self.assertTrue(form.save())
50
41
 
51
- self.assertFalse(form.is_valid())
52
- self.assertEqual("Please specify a valid IPv4 or IPv6 address.", form.errors[self.field_name][0])
42
+ def test_address_invalid_ipv4(self):
43
+ data = {self.field_name: "192.168.0.1/64", "namespace": self.namespace, "status": self.status}
44
+ data.update(self.extra_data)
45
+ form = self.form_class(data)
53
46
 
54
- def test_address_zero_mask(self):
55
- data = {self.field_name: "192.168.0.1/0", "namespace": self.namespace, "status": self.status}
56
- data.update(self.extra_data)
57
- form = self.form_class(data)
47
+ self.assertFalse(form.is_valid())
48
+ self.assertEqual("Please specify a valid IPv4 or IPv6 address.", form.errors[self.field_name][0])
58
49
 
59
- # With the advent of `Prefix.parent`, it's now possible to create a /0 .
60
- self.assertTrue(form.is_valid())
50
+ def test_address_zero_mask(self):
51
+ data = {self.field_name: "192.168.0.1/0", "namespace": self.namespace, "status": self.status}
52
+ data.update(self.extra_data)
53
+ form = self.form_class(data)
61
54
 
62
- def test_address_missing_mask(self):
63
- data = {self.field_name: "192.168.0.1", "namespace": self.namespace, "status": self.status}
64
- data.update(self.extra_data)
65
- form = self.form_class(data)
55
+ # With the advent of `Prefix.parent`, it's now possible to create a /0 .
56
+ self.assertTrue(form.is_valid())
66
57
 
67
- self.assertFalse(form.is_valid())
68
- self.assertEqual("CIDR mask (e.g. /24) is required.", form.errors[self.field_name][0])
58
+ def test_address_missing_mask(self):
59
+ data = {self.field_name: "192.168.0.1", "namespace": self.namespace, "status": self.status}
60
+ data.update(self.extra_data)
61
+ form = self.form_class(data)
62
+
63
+ self.assertFalse(form.is_valid())
64
+ self.assertEqual("CIDR mask (e.g. /24) is required.", form.errors[self.field_name][0])
69
65
 
70
66
 
71
- class PrefixFormTest(NetworkFormTestCases.BaseNetworkFormTest, FormTestCases.BaseFormTestCase):
67
+ class PrefixFormTest(BaseNetworkFormTest, FormTestCases.BaseFormTestCase):
72
68
  form_class = forms.PrefixForm
73
69
  field_name = "prefix"
74
70
  object_name = "prefix"
@@ -83,7 +79,7 @@ class PrefixFormTest(NetworkFormTestCases.BaseNetworkFormTest, FormTestCases.Bas
83
79
  }
84
80
 
85
81
 
86
- class IPAddressFormTest(NetworkFormTestCases.BaseNetworkFormTest):
82
+ class IPAddressFormTest(BaseNetworkFormTest, TestCase):
87
83
  form_class = forms.IPAddressForm
88
84
  field_name = "address"
89
85
  object_name = "IP address"
@@ -29,29 +29,29 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
29
29
  request_id=uuid.uuid4(),
30
30
  )
31
31
 
32
- def populateDataBeforeMigration(self, installed_apps):
32
+ def populateDataBeforeMigration(self, apps):
33
33
  """Populate Aggregate data before migrating to Prefixes"""
34
34
 
35
- self.aggregate = installed_apps.get_model("ipam", "Aggregate")
35
+ self.aggregate = apps.get_model("ipam", "Aggregate")
36
36
  # Workaround for django-taggit manager not working in migrations.
37
37
  # https://github.com/jazzband/django-taggit/issues/101
38
38
  # https://github.com/jazzband/django-taggit/issues/454
39
39
  self.aggregate.tags = TagsField()
40
- self.computed_field = installed_apps.get_model("extras", "computedfield")
41
- self.content_type = installed_apps.get_model("contenttypes", "ContentType")
42
- self.custom_field = installed_apps.get_model("extras", "customfield")
43
- self.custom_link = installed_apps.get_model("extras", "customlink")
44
- self.dynamic_group = installed_apps.get_model("extras", "DynamicGroup")
45
- self.note = installed_apps.get_model("extras", "note")
46
- self.object_change = installed_apps.get_model("extras", "objectchange")
47
- self.object_permission = installed_apps.get_model("users", "objectpermission")
48
- self.prefix = installed_apps.get_model("ipam", "prefix")
40
+ self.computed_field = apps.get_model("extras", "computedfield")
41
+ self.content_type = apps.get_model("contenttypes", "ContentType")
42
+ self.custom_field = apps.get_model("extras", "customfield")
43
+ self.custom_link = apps.get_model("extras", "customlink")
44
+ self.dynamic_group = apps.get_model("extras", "DynamicGroup")
45
+ self.note = apps.get_model("extras", "note")
46
+ self.object_change = apps.get_model("extras", "objectchange")
47
+ self.object_permission = apps.get_model("users", "objectpermission")
48
+ self.prefix = apps.get_model("ipam", "prefix")
49
49
  self.prefix.tags = TagsField()
50
- self.relationship = installed_apps.get_model("extras", "relationship")
51
- self.relationship_association = installed_apps.get_model("extras", "relationshipassociation")
52
- self.rir = installed_apps.get_model("ipam", "RIR")
53
- self.status = installed_apps.get_model("extras", "status")
54
- self.tag = installed_apps.get_model("extras", "tag")
50
+ self.relationship = apps.get_model("extras", "relationship")
51
+ self.relationship_association = apps.get_model("extras", "relationshipassociation")
52
+ self.rir = apps.get_model("ipam", "RIR")
53
+ self.status = apps.get_model("extras", "status")
54
+ self.tag = apps.get_model("extras", "tag")
55
55
 
56
56
  self.aggregate_ct = self.content_type.objects.get_for_model(self.aggregate)
57
57
  self.prefix_ct = self.content_type.objects.get_for_model(self.prefix)
@@ -114,8 +114,8 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
114
114
  self.aggregate1.tags.add("AggregateTagA", "AggregateTagB")
115
115
  self.aggregate2.tags.add("AggregateTagA")
116
116
  self.aggregate3.tags.add("AggregateTagB")
117
- self.aggregate5.tags.add("AggregateTagA", "AggregateTagB") # pylint: disable=no-member
118
- self.aggregate6.tags.add("AggregateTagB") # pylint: disable=no-member
117
+ self.aggregate5.tags.add("AggregateTagA", "AggregateTagB")
118
+ self.aggregate6.tags.add("AggregateTagB")
119
119
 
120
120
  # notes
121
121
  self.note.objects.create(
@@ -141,7 +141,7 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
141
141
  self.note.objects.create(
142
142
  note="Aggregate5 test note",
143
143
  assigned_object_type=self.aggregate_ct,
144
- assigned_object_id=self.aggregate5.id, # pylint: disable=no-member
144
+ assigned_object_id=self.aggregate5.id,
145
145
  )
146
146
 
147
147
  # object permissions
@@ -157,8 +157,8 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
157
157
  # object changes
158
158
  self._create_objectchange(self.prefix1, "Pre-migration object change for prefix1")
159
159
  self._create_objectchange(self.prefix4, "Pre-migration object change for prefix4")
160
- self._create_objectchange(self.prefix5, "Pre-migration object change for prefix5") # pylint: disable=no-member
161
- self._create_objectchange(self.aggregate5, "Pre-migration object change for aggregate5") # pylint: disable=no-member
160
+ self._create_objectchange(self.prefix5, "Pre-migration object change for prefix5")
161
+ self._create_objectchange(self.aggregate5, "Pre-migration object change for aggregate5")
162
162
 
163
163
  # custom fields
164
164
  prefix_cf1 = self.custom_field.objects.create(name="prefixcf1")
@@ -179,24 +179,24 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
179
179
 
180
180
  self.aggregate3._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate3"
181
181
 
182
- self.prefix5._custom_field_data["prefixcf1"] = "testdata prefixcf1 prefix5" # pylint: disable=no-member
183
- self.prefix5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 prefix5" # pylint: disable=no-member
182
+ self.prefix5._custom_field_data["prefixcf1"] = "testdata prefixcf1 prefix5"
183
+ self.prefix5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 prefix5"
184
184
 
185
- self.aggregate5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate5" # pylint: disable=no-member
186
- self.aggregate5._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate5" # pylint: disable=no-member
185
+ self.aggregate5._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate5"
186
+ self.aggregate5._custom_field_data["aggregatecf1"] = "testdata aggregatecf1 aggregate5"
187
187
 
188
- self.aggregate6._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate6" # pylint: disable=no-member
188
+ self.aggregate6._custom_field_data["prefixaggregatecf1"] = "testdata prefixaggregatecf1 aggregate6"
189
189
 
190
190
  self.prefix1.save()
191
191
  self.prefix2.save()
192
192
  self.prefix3.save()
193
193
  self.prefix4.save()
194
- self.prefix5.save() # pylint: disable=no-member
194
+ self.prefix5.save()
195
195
  self.aggregate1.save()
196
196
  self.aggregate2.save()
197
197
  self.aggregate3.save()
198
- self.aggregate5.save() # pylint: disable=no-member
199
- self.aggregate6.save() # pylint: disable=no-member
198
+ self.aggregate5.save()
199
+ self.aggregate6.save()
200
200
 
201
201
  @skipIf(
202
202
  connection.vendor != "postgresql",
@@ -390,7 +390,7 @@ class AggregateToPrefixMigrationTestCase(NautobotDataMigrationTest):
390
390
  2,
391
391
  )
392
392
 
393
- for prefix in (self.prefix2, self.prefix3, self.prefix5): # pylint: disable=no-member
393
+ for prefix in (self.prefix2, self.prefix3, self.prefix5):
394
394
  self.assertEqual(
395
395
  self.object_change.objects.filter(changed_object_id=prefix.id).count(),
396
396
  1,
@@ -1,5 +1,4 @@
1
1
  from unittest import skipIf
2
- from unittest.mock import patch
3
2
 
4
3
  from django.contrib.contenttypes.models import ContentType
5
4
  from django.core.exceptions import ValidationError
@@ -414,39 +413,6 @@ class TestPrefix(ModelTestCases.BaseModelTestCase):
414
413
  self.child1 = Prefix.objects.create(prefix="101.102.0.0/26", status=self.status, namespace=self.namespace)
415
414
  self.child2 = Prefix.objects.create(prefix="101.102.0.64/26", status=self.status, namespace=self.namespace)
416
415
 
417
- def test_parent_exists_after_model_clean(self):
418
- prefix = Prefix(
419
- prefix="101.102.0.2/26", status=self.status, namespace=self.namespace, type=PrefixTypeChoices.TYPE_CONTAINER
420
- )
421
- prefix.clean()
422
- self.assertEqual(prefix.parent, self.child1)
423
-
424
- def test_reparent_subnets_and_reparent_ips_call(self):
425
- """Assert reparent_subnets and reparent_ips are only called if there is an update to either of network, namespace or prefix_length"""
426
- prefix_ip = "101.102.0.0/28"
427
- with self.subTest("Assert reparent_subnets"):
428
- with patch.object(Prefix, "reparent_subnets", return_value=None) as mock_reparent_subnets:
429
- Prefix.objects.create(prefix=prefix_ip, status=self.status, namespace=self.namespace)
430
- mock_reparent_subnets.assert_called_once()
431
-
432
- with patch.object(Prefix, "reparent_subnets", return_value=None) as mock_reparent_subnets:
433
- prefix = Prefix.objects.get(prefix=prefix_ip)
434
- prefix.description = "Sample Description"
435
- prefix.save()
436
- mock_reparent_subnets.assert_not_called()
437
- prefix.delete()
438
-
439
- with self.subTest("Assert reparent_ips"):
440
- with patch.object(Prefix, "reparent_ips", return_value=None) as reparent_ips:
441
- Prefix.objects.create(prefix=prefix_ip, status=self.status, namespace=self.namespace)
442
- reparent_ips.assert_called_once()
443
-
444
- with patch.object(Prefix, "reparent_ips", return_value=None) as reparent_ips:
445
- prefix = Prefix.objects.get(prefix=prefix_ip)
446
- prefix.description = "Sample Description"
447
- prefix.save()
448
- reparent_ips.assert_not_called()
449
-
450
416
  def test_location_queries(self):
451
417
  locations = Location.objects.all()[:4]
452
418
  for location in locations:
@@ -800,13 +766,6 @@ class TestPrefix(ModelTestCases.BaseModelTestCase):
800
766
  IPAddress.objects.create(address="10.0.0.4/24", status=self.status, namespace=self.namespace)
801
767
  self.assertEqual(parent_prefix.get_first_available_ip(), "10.0.0.5/24")
802
768
 
803
- def test_get_first_available_ip_calculate_child_ips(self):
804
- parent_prefix = Prefix.objects.create(prefix="10.0.3.0/29", status=self.status, namespace=self.namespace)
805
- Prefix.objects.create(prefix="10.0.3.0/30", status=self.status, namespace=self.namespace)
806
- IPAddress(address="10.0.3.1/30", status=self.status, namespace=self.namespace).save()
807
-
808
- self.assertEqual(parent_prefix.get_first_available_ip(), "10.0.3.2/29")
809
-
810
769
  def test_get_utilization(self):
811
770
  # Container Prefix
812
771
  prefix = Prefix.objects.create(
@@ -1,15 +1,13 @@
1
1
  import re
2
2
  from unittest import skipIf
3
3
 
4
- from django.contrib.contenttypes.models import ContentType
5
- from django.db import connection, transaction
4
+ from django.db import connection
6
5
  import netaddr
7
6
 
8
7
  from nautobot.core.testing import TestCase
9
8
  from nautobot.extras.models import Status
10
9
  from nautobot.ipam import choices
11
10
  from nautobot.ipam.models import IPAddress, Namespace, Prefix
12
- from nautobot.users.models import ObjectPermission
13
11
 
14
12
 
15
13
  class IPAddressQuerySet(TestCase):
@@ -268,28 +266,6 @@ class IPAddressQuerySet(TestCase):
268
266
  [instance for ip, instance in self.ips.items() if "10.0.0" in ip],
269
267
  )
270
268
 
271
- def test_lookup_not_ambiguous(self):
272
- """Check for issues like https://github.com/nautobot/nautobot/issues/5166."""
273
- obj_perm = ObjectPermission.objects.create(name="Test Permission", constraints={}, actions=["view"])
274
- obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress))
275
- obj_perm.users.add(self.user)
276
- queryset = IPAddress.objects.select_related("parent", "nat_inside", "status")
277
-
278
- for permission_constraint in (
279
- {"host__family": 4},
280
- {"host__net_host": "10.0.0.1"},
281
- {"host__net_host_contained": "10.0.0.0/24"},
282
- {"host__net_in": ["10.0.0.0/24"]},
283
- ):
284
- with self.subTest(permission_type=next(iter(permission_constraint.keys()))):
285
- try:
286
- with transaction.atomic():
287
- obj_perm.constraints = permission_constraint
288
- obj_perm.save()
289
- list(queryset.restrict(self.user, "view"))
290
- finally:
291
- delattr(self.user, "_object_perm_cache")
292
-
293
269
  @skipIf(
294
270
  connection.vendor == "postgresql",
295
271
  "Not currently supported on postgresql",
@@ -478,20 +454,6 @@ class IPAddressQuerySet(TestCase):
478
454
  [instance for ip, instance in self.ips.items() if re.match(r"2001(.*)1", ip)],
479
455
  )
480
456
 
481
- def test_get_or_create(self):
482
- # https://github.com/nautobot/nautobot/issues/6676
483
- ip_obj, created = IPAddress.objects.update_or_create(
484
- defaults={
485
- "status": self.ipaddr_status,
486
- },
487
- host="10.0.0.1",
488
- mask_length="24",
489
- namespace=self.namespace,
490
- )
491
- self.assertFalse(created)
492
- self.assertEqual(str(ip_obj.address), "10.0.0.1/24")
493
- self.assertEqual(ip_obj.parent.namespace, self.namespace)
494
-
495
457
 
496
458
  class PrefixQuerysetTestCase(TestCase):
497
459
  queryset = Prefix.objects.all()
@@ -686,30 +648,6 @@ class PrefixQuerysetTestCase(TestCase):
686
648
  prefix = Prefix.objects.filter(network__net_equals="192.168.0.0/16")[0]
687
649
  self.assertEqual(Prefix.objects.filter(prefix="192.168.0.0/16")[0], prefix)
688
650
 
689
- def test_lookup_not_ambiguous(self):
690
- """Check for issues like https://github.com/nautobot/nautobot/issues/5166."""
691
- obj_perm = ObjectPermission.objects.create(name="Test Permission", constraints={}, actions=["view"])
692
- obj_perm.object_types.add(ContentType.objects.get_for_model(Prefix))
693
- obj_perm.users.add(self.user)
694
- queryset = Prefix.objects.select_related("parent", "rir", "role", "status", "namespace")
695
-
696
- for permission_constraint in (
697
- {"network__family": 4},
698
- {"network__net_equals": "192.168.0.0/16"},
699
- {"network__net_contained": "192.0.0.0/8"},
700
- {"network__net_contained_or_equal": "192.0.0.0/8"},
701
- {"network__net_contains": "192.168.3.192/32"},
702
- {"network__net_contains_or_equals": "192.168.3.192/32"},
703
- ):
704
- with self.subTest(permission_type=next(iter(permission_constraint.keys()))):
705
- try:
706
- with transaction.atomic():
707
- obj_perm.constraints = permission_constraint
708
- obj_perm.save()
709
- list(queryset.restrict(self.user, "view"))
710
- finally:
711
- delattr(self.user, "_object_perm_cache")
712
-
713
651
  @skipIf(
714
652
  connection.vendor == "postgresql",
715
653
  "Not currently supported on postgresql",