nautobot 2.4.17__py3-none-any.whl → 2.4.19__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 (627) hide show
  1. nautobot/apps/ui.py +6 -0
  2. nautobot/apps/views.py +2 -0
  3. nautobot/circuits/tables.py +1 -1
  4. nautobot/circuits/templates/circuits/circuit_create.html +7 -7
  5. nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -5
  6. nautobot/circuits/templates/circuits/circuittermination_create.html +26 -26
  7. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -8
  8. nautobot/circuits/templates/circuits/inc/circuit_termination.html +20 -20
  9. nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +3 -3
  10. nautobot/circuits/templates/circuits/inc/circuit_termination_speed_fragment.html +9 -0
  11. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +1 -3
  12. nautobot/circuits/tests/integration/test_circuit.py +2 -2
  13. nautobot/circuits/views.py +49 -15
  14. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +1 -4
  15. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +1 -7
  16. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +1 -3
  17. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +1 -5
  18. nautobot/cloud/views.py +45 -0
  19. nautobot/core/filters.py +2 -2
  20. nautobot/core/graphql/generators.py +5 -2
  21. nautobot/core/jobs/bulk_actions.py +48 -85
  22. nautobot/core/models/querysets.py +2 -1
  23. nautobot/core/settings.py +1 -0
  24. nautobot/core/settings.yaml +9 -0
  25. nautobot/core/tables.py +21 -23
  26. nautobot/core/templates/40x.html +15 -15
  27. nautobot/core/templates/500.html +21 -21
  28. nautobot/core/templates/admin/app_index.html +8 -8
  29. nautobot/core/templates/admin/base.html +104 -104
  30. nautobot/core/templates/admin/change_form.html +65 -65
  31. nautobot/core/templates/admin/change_list.html +60 -60
  32. nautobot/core/templates/admin/change_list_results.html +39 -39
  33. nautobot/core/templates/admin/config/config.html +47 -47
  34. nautobot/core/templates/admin/delete_confirmation.html +47 -47
  35. nautobot/core/templates/admin/edit_inline/stacked.html +124 -124
  36. nautobot/core/templates/admin/edit_inline/tabular.html +60 -60
  37. nautobot/core/templates/admin/includes/fieldset.html +4 -4
  38. nautobot/core/templates/admin/index.html +60 -60
  39. nautobot/core/templates/admin/prepopulated_fields_js.html +18 -18
  40. nautobot/core/templates/admin/submit_line.html +4 -4
  41. nautobot/core/templates/base_django.html +46 -46
  42. nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +8 -8
  43. nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +8 -8
  44. nautobot/core/templates/buttons/export.html +3 -3
  45. nautobot/core/templates/components/breadcrumbs.html +19 -0
  46. nautobot/core/templates/components/button/default.html +3 -3
  47. nautobot/core/templates/components/button/dropdown.html +7 -7
  48. nautobot/core/templates/components/button/formbutton.html +4 -4
  49. nautobot/core/templates/components/panel/body_content_data_table.html +1 -1
  50. nautobot/core/templates/components/panel/body_wrapper_generic_table.html +3 -0
  51. nautobot/core/templates/components/panel/footer_content_table.html +3 -1
  52. nautobot/core/templates/components/panel/header_extra_content_table.html +10 -1
  53. nautobot/core/templates/components/tab/content_wrapper.html +1 -1
  54. nautobot/core/templates/components/tab/label_wrapper.html +1 -1
  55. nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +10 -3
  56. nautobot/core/templates/generic/object_bulk_add_component.html +40 -40
  57. nautobot/core/templates/generic/object_bulk_create.html +3 -3
  58. nautobot/core/templates/generic/object_bulk_destroy.html +6 -6
  59. nautobot/core/templates/generic/object_bulk_update.html +52 -52
  60. nautobot/core/templates/generic/object_changelog.html +0 -2
  61. nautobot/core/templates/generic/object_import.html +33 -33
  62. nautobot/core/templates/generic/object_list.html +271 -268
  63. nautobot/core/templates/generic/object_notes.html +0 -2
  64. nautobot/core/templates/generic/object_retrieve.html +264 -257
  65. nautobot/core/templates/graphene/graphiql.html +127 -127
  66. nautobot/core/templates/home.html +62 -62
  67. nautobot/core/templates/inc/computed_fields/panel_data.html +13 -13
  68. nautobot/core/templates/inc/created_updated.html +8 -8
  69. nautobot/core/templates/inc/custom_fields/panel_data.html +13 -13
  70. nautobot/core/templates/inc/dynamic_groups_panel.html +11 -11
  71. nautobot/core/templates/inc/footer.html +19 -19
  72. nautobot/core/templates/inc/javascript.html +1 -1
  73. nautobot/core/templates/inc/media.html +46 -46
  74. nautobot/core/templates/inc/nav_menu.html +1 -1
  75. nautobot/core/templates/inc/relationships_table_rows.html +22 -22
  76. nautobot/core/templates/inc/tenant_table_row.html +1 -1
  77. nautobot/core/templates/login.html +77 -77
  78. nautobot/core/templates/media_failure.html +38 -38
  79. nautobot/core/templates/panel_table.html +1 -1
  80. nautobot/core/templates/rest_framework/api.html +3 -3
  81. nautobot/core/templates/search.html +1 -1
  82. nautobot/core/templates/swagger_ui.html +9 -9
  83. nautobot/core/templates/utilities/confirmation_form.html +18 -18
  84. nautobot/core/templates/utilities/render_field.html +1 -1
  85. nautobot/core/templates/utilities/render_jinja2.html +43 -43
  86. nautobot/core/templates/utilities/templatetags/filter_form_modal.html +56 -56
  87. nautobot/core/templates/utilities/templatetags/utilization_graph.html +1 -1
  88. nautobot/core/templates/utilities/theme_preview.html +799 -799
  89. nautobot/core/templates/utilities/worker_status.html +122 -122
  90. nautobot/core/templates/widgets/clearable_file.html +3 -3
  91. nautobot/core/templates/widgets/sluginput.html +1 -1
  92. nautobot/core/templatetags/buttons.py +8 -2
  93. nautobot/core/templatetags/helpers.py +24 -0
  94. nautobot/core/templatetags/ui_framework.py +40 -5
  95. nautobot/core/testing/filters.py +37 -21
  96. nautobot/core/testing/integration.py +7 -4
  97. nautobot/core/testing/views.py +49 -5
  98. nautobot/core/tests/test_breadcrumbs.py +78 -4
  99. nautobot/core/tests/test_commands.py +7 -4
  100. nautobot/core/tests/test_graphql.py +20 -5
  101. nautobot/core/tests/test_jobs.py +34 -21
  102. nautobot/core/tests/test_tables.py +43 -6
  103. nautobot/core/tests/test_templatetags_ui_framework.py +146 -0
  104. nautobot/core/tests/test_titles.py +2 -2
  105. nautobot/core/tests/test_ui.py +188 -1
  106. nautobot/core/tests/test_utils.py +35 -0
  107. nautobot/core/tests/test_views.py +45 -0
  108. nautobot/core/tests/test_views_generic.py +43 -0
  109. nautobot/core/tests/test_views_utils.py +239 -5
  110. nautobot/core/ui/breadcrumbs.py +220 -28
  111. nautobot/core/ui/bulk_buttons.py +8 -0
  112. nautobot/core/ui/object_detail.py +181 -60
  113. nautobot/core/ui/titles.py +10 -5
  114. nautobot/core/utils/requests.py +27 -2
  115. nautobot/core/views/__init__.py +24 -3
  116. nautobot/core/views/generic.py +70 -35
  117. nautobot/core/views/mixins.py +226 -122
  118. nautobot/core/views/utils.py +270 -1
  119. nautobot/dcim/api/serializers.py +8 -2
  120. nautobot/dcim/constants.py +1 -0
  121. nautobot/dcim/factory.py +4 -3
  122. nautobot/dcim/filters/mixins.py +1 -2
  123. nautobot/dcim/forms.py +5 -1
  124. nautobot/dcim/migrations/0074_alter_rack_u_height.py +21 -0
  125. nautobot/dcim/models/devices.py +30 -1
  126. nautobot/dcim/models/racks.py +2 -2
  127. nautobot/dcim/tables/__init__.py +2 -0
  128. nautobot/dcim/tables/devices.py +24 -0
  129. nautobot/dcim/tables/power.py +2 -2
  130. nautobot/dcim/templates/dcim/cable.html +53 -53
  131. nautobot/dcim/templates/dcim/cable_connect.html +182 -182
  132. nautobot/dcim/templates/dcim/cable_trace.html +1 -1
  133. nautobot/dcim/templates/dcim/console_port_connection_list.html +5 -5
  134. nautobot/dcim/templates/dcim/consoleport.html +86 -86
  135. nautobot/dcim/templates/dcim/consoleserverport.html +86 -86
  136. nautobot/dcim/templates/dcim/controller_create.html +34 -34
  137. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -68
  138. nautobot/dcim/templates/dcim/device/base.html +1 -114
  139. nautobot/dcim/templates/dcim/device/config.html +17 -17
  140. nautobot/dcim/templates/dcim/device/consoleports.html +1 -52
  141. nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -52
  142. nautobot/dcim/templates/dcim/device/devicebays.html +1 -48
  143. nautobot/dcim/templates/dcim/device/frontports.html +1 -52
  144. nautobot/dcim/templates/dcim/device/interfaces.html +1 -56
  145. nautobot/dcim/templates/dcim/device/inventory.html +1 -48
  146. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +64 -64
  147. nautobot/dcim/templates/dcim/device/modulebays.html +1 -48
  148. nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -52
  149. nautobot/dcim/templates/dcim/device/powerports.html +1 -52
  150. nautobot/dcim/templates/dcim/device/rearports.html +1 -52
  151. nautobot/dcim/templates/dcim/device/status.html +66 -66
  152. nautobot/dcim/templates/dcim/device/wireless.html +1 -72
  153. nautobot/dcim/templates/dcim/device.html +4 -422
  154. nautobot/dcim/templates/dcim/device_component.html +0 -19
  155. nautobot/dcim/templates/dcim/device_component_add.html +25 -25
  156. nautobot/dcim/templates/dcim/device_create.html +229 -0
  157. nautobot/dcim/templates/dcim/device_edit.html +2 -227
  158. nautobot/dcim/templates/dcim/devicebay.html +41 -41
  159. nautobot/dcim/templates/dcim/devicebay_populate.html +32 -32
  160. nautobot/dcim/templates/dcim/devicetype_component_add.html +28 -28
  161. nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -3
  162. nautobot/dcim/templates/dcim/frontport.html +84 -84
  163. nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
  164. nautobot/dcim/templates/dcim/inc/device_interface_filter.html +8 -0
  165. nautobot/dcim/templates/dcim/inc/device_napalm_tabs.html +1 -15
  166. nautobot/dcim/templates/dcim/inc/location_hierarchy.html +22 -22
  167. nautobot/dcim/templates/dcim/interface.html +206 -206
  168. nautobot/dcim/templates/dcim/interface_connection_list.html +5 -5
  169. nautobot/dcim/templates/dcim/interfaceredundancygroupassociation_create.html +6 -6
  170. nautobot/dcim/templates/dcim/inventoryitem.html +44 -44
  171. nautobot/dcim/templates/dcim/inventoryitem_add.html +32 -32
  172. nautobot/dcim/templates/dcim/inventoryitem_edit.html +22 -22
  173. nautobot/dcim/templates/dcim/location_migrate_data_to_contact.html +46 -46
  174. nautobot/dcim/templates/dcim/location_retrieve.html +1 -7
  175. nautobot/dcim/templates/dcim/locationtype.html +1 -6
  176. nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -7
  177. nautobot/dcim/templates/dcim/module/base.html +85 -85
  178. nautobot/dcim/templates/dcim/module_interfaces.html +1 -1
  179. nautobot/dcim/templates/dcim/module_modulebays.html +1 -1
  180. nautobot/dcim/templates/dcim/module_retrieve.html +52 -52
  181. nautobot/dcim/templates/dcim/module_update.html +61 -61
  182. nautobot/dcim/templates/dcim/modulebay_destroy.html +1 -1
  183. nautobot/dcim/templates/dcim/modulebay_retrieve.html +83 -99
  184. nautobot/dcim/templates/dcim/modulebay_update.html +33 -33
  185. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
  186. nautobot/dcim/templates/dcim/moduletype_retrieve.html +140 -144
  187. nautobot/dcim/templates/dcim/platform_create.html +38 -38
  188. nautobot/dcim/templates/dcim/power_port_connection_list.html +5 -5
  189. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -8
  190. nautobot/dcim/templates/dcim/poweroutlet.html +85 -85
  191. nautobot/dcim/templates/dcim/powerpanel_retrieve.html +1 -8
  192. nautobot/dcim/templates/dcim/powerport.html +91 -91
  193. nautobot/dcim/templates/dcim/rack_elevation_list.html +18 -18
  194. nautobot/dcim/templates/dcim/rack_retrieve.html +264 -274
  195. nautobot/dcim/templates/dcim/rackreservation_retrieve.html +0 -3
  196. nautobot/dcim/templates/dcim/rearport.html +78 -78
  197. nautobot/dcim/templates/dcim/virtualchassis_retrieve.html +1 -50
  198. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -5
  199. nautobot/dcim/tests/integration/test_device_bulk_operations.py +3 -2
  200. nautobot/dcim/tests/integration/test_location_bulk_operations.py +6 -2
  201. nautobot/dcim/tests/test_api.py +33 -1
  202. nautobot/dcim/tests/test_views.py +189 -4
  203. nautobot/dcim/ui.py +29 -0
  204. nautobot/dcim/urls.py +1 -109
  205. nautobot/dcim/utils.py +30 -0
  206. nautobot/dcim/views.py +1149 -550
  207. nautobot/extras/filters/mixins.py +1 -1
  208. nautobot/extras/forms/forms.py +15 -0
  209. nautobot/extras/models/groups.py +10 -1
  210. nautobot/extras/models/jobs.py +2 -2
  211. nautobot/extras/plugins/views.py +18 -5
  212. nautobot/extras/tables.py +24 -2
  213. nautobot/extras/templates/extras/computedfield_edit.html +4 -4
  214. nautobot/extras/templates/extras/configcontext_update.html +1 -1
  215. nautobot/extras/templates/extras/configcontextschema_retrieve.html +32 -32
  216. nautobot/extras/templates/extras/customfield_retrieve.html +1 -128
  217. nautobot/extras/templates/extras/customfield_update.html +23 -23
  218. nautobot/extras/templates/extras/dynamicgroup.html +2 -99
  219. nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -199
  220. nautobot/extras/templates/extras/dynamicgroup_retrieve.html +99 -0
  221. nautobot/extras/templates/extras/dynamicgroup_update.html +199 -0
  222. nautobot/extras/templates/extras/gitrepository.html +2 -82
  223. nautobot/extras/templates/extras/gitrepository_list.html +10 -10
  224. nautobot/extras/templates/extras/gitrepository_object_edit.html +2 -13
  225. nautobot/extras/templates/extras/gitrepository_retrieve.html +82 -0
  226. nautobot/extras/templates/extras/gitrepository_update.html +13 -0
  227. nautobot/extras/templates/extras/graphqlquery_retrieve.html +73 -73
  228. nautobot/extras/templates/extras/inc/configcontext_format.html +2 -2
  229. nautobot/extras/templates/extras/inc/job_table.html +10 -10
  230. nautobot/extras/templates/extras/inc/jobresult.html +21 -21
  231. nautobot/extras/templates/extras/inc/jobresult_js.html +6 -6
  232. nautobot/extras/templates/extras/inc/tags_panel.html +10 -10
  233. nautobot/extras/templates/extras/job.html +64 -64
  234. nautobot/extras/templates/extras/job_approval_request.html +9 -9
  235. nautobot/extras/templates/extras/job_bulk_edit.html +13 -13
  236. nautobot/extras/templates/extras/job_edit.html +45 -45
  237. nautobot/extras/templates/extras/job_list.html +4 -4
  238. nautobot/extras/templates/extras/jobresult_retrieve.html +0 -25
  239. nautobot/extras/templates/extras/marketplace.html +101 -101
  240. nautobot/extras/templates/extras/metadatatype_create.html +20 -20
  241. nautobot/extras/templates/extras/note_retrieve.html +0 -52
  242. nautobot/extras/templates/extras/object_assign_contact_or_team.html +18 -18
  243. nautobot/extras/templates/extras/object_configcontext.html +1 -3
  244. nautobot/extras/templates/extras/objectchange.html +2 -165
  245. nautobot/extras/templates/extras/objectchange_retrieve.html +165 -0
  246. nautobot/extras/templates/extras/plugin_detail.html +44 -48
  247. nautobot/extras/templates/extras/plugins_list.html +9 -11
  248. nautobot/extras/templates/extras/plugins_tiles.html +26 -26
  249. nautobot/extras/templates/extras/relationship_edit.html +4 -4
  250. nautobot/extras/templates/extras/role_retrieve.html +13 -13
  251. nautobot/extras/templates/extras/scheduled_jobs_approval_queue_list.html +21 -21
  252. nautobot/extras/templates/extras/scheduledjob.html +128 -128
  253. nautobot/extras/templates/extras/secret_create.html +53 -53
  254. nautobot/extras/templates/extras/secretsgroup_update.html +13 -13
  255. nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +3 -3
  256. nautobot/extras/templates/extras/webhook.html +79 -79
  257. nautobot/extras/tests/integration/test_relationships.py +6 -6
  258. nautobot/extras/tests/test_dynamicgroups.py +73 -18
  259. nautobot/extras/tests/test_filters.py +1 -1
  260. nautobot/extras/tests/test_jobs.py +2 -0
  261. nautobot/extras/tests/test_views.py +8 -3
  262. nautobot/extras/urls.py +3 -97
  263. nautobot/extras/views.py +524 -456
  264. nautobot/ipam/filters.py +2 -2
  265. nautobot/ipam/migrations/0053_alter_vrfdeviceassignment_options_and_more.py +20 -0
  266. nautobot/ipam/models.py +34 -0
  267. nautobot/ipam/querysets.py +3 -3
  268. nautobot/ipam/signals.py +6 -1
  269. nautobot/ipam/tables.py +3 -1
  270. nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +4 -0
  271. nautobot/ipam/templates/ipam/inc/toggle_available.html +8 -8
  272. nautobot/ipam/templates/ipam/inc/vlangroup_header.html +4 -4
  273. nautobot/ipam/templates/ipam/ipaddress.html +119 -123
  274. nautobot/ipam/templates/ipam/ipaddress_assign.html +10 -10
  275. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -1
  276. nautobot/ipam/templates/ipam/ipaddress_merge.html +180 -180
  277. nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +48 -48
  278. nautobot/ipam/templates/ipam/prefix.html +2 -115
  279. nautobot/ipam/templates/ipam/prefix_create.html +34 -0
  280. nautobot/ipam/templates/ipam/prefix_edit.html +1 -34
  281. nautobot/ipam/templates/ipam/prefix_retrieve.html +3 -0
  282. nautobot/ipam/templates/ipam/service_retrieve.html +1 -6
  283. nautobot/ipam/templates/ipam/vlan_retrieve.html +1 -7
  284. nautobot/ipam/templates/ipam/vrf_edit.html +1 -1
  285. nautobot/ipam/tests/test_api.py +5 -0
  286. nautobot/ipam/tests/test_models.py +387 -0
  287. nautobot/ipam/tests/test_querysets.py +46 -0
  288. nautobot/ipam/tests/test_views.py +34 -0
  289. nautobot/ipam/ui.py +145 -0
  290. nautobot/ipam/urls.py +1 -46
  291. nautobot/ipam/utils/__init__.py +26 -0
  292. nautobot/ipam/utils/migrations.py +1 -1
  293. nautobot/ipam/views.py +234 -112
  294. nautobot/project-static/docs/404.html +11 -11
  295. nautobot/project-static/docs/apps/index.html +11 -11
  296. nautobot/project-static/docs/apps/nautobot-apps.html +11 -11
  297. nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js → bundle.f55a23d4.min.js} +2 -2
  298. nautobot/project-static/docs/assets/javascripts/{bundle.92b07e13.min.js.map → bundle.f55a23d4.min.js.map} +2 -2
  299. nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css → main.e53b48f4.min.css} +1 -1
  300. nautobot/project-static/docs/assets/stylesheets/{main.7e37652d.min.css.map → main.e53b48f4.min.css.map} +1 -1
  301. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +11 -11
  302. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +11 -11
  303. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +11 -11
  304. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +11 -11
  305. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +11 -11
  306. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +11 -11
  307. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +11 -11
  308. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +11 -11
  309. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +11 -11
  310. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +11 -11
  311. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +11 -11
  312. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +11 -11
  313. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +11 -11
  314. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +11 -11
  315. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +11 -11
  316. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +11 -11
  317. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +11 -11
  318. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +11 -11
  319. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +11 -11
  320. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +83 -11
  321. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1265 -281
  322. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +11 -11
  323. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +12 -12
  324. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +452 -29
  325. nautobot/project-static/docs/development/apps/api/configuration-view.html +11 -11
  326. nautobot/project-static/docs/development/apps/api/database-backend-config.html +11 -11
  327. nautobot/project-static/docs/development/apps/api/models/django-admin.html +11 -11
  328. nautobot/project-static/docs/development/apps/api/models/global-search.html +11 -11
  329. nautobot/project-static/docs/development/apps/api/models/graphql.html +11 -11
  330. nautobot/project-static/docs/development/apps/api/models/index.html +11 -11
  331. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +12 -12
  332. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +11 -11
  333. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +11 -11
  334. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +11 -11
  335. nautobot/project-static/docs/development/apps/api/platform-features/index.html +11 -11
  336. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +11 -11
  337. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +11 -11
  338. nautobot/project-static/docs/development/apps/api/platform-features/prepopulating-data.html +11 -11
  339. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +11 -11
  340. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +11 -11
  341. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +11 -11
  342. nautobot/project-static/docs/development/apps/api/prometheus.html +11 -11
  343. nautobot/project-static/docs/development/apps/api/setup.html +11 -11
  344. nautobot/project-static/docs/development/apps/api/testing.html +11 -11
  345. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +11 -11
  346. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +11 -11
  347. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +11 -11
  348. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +11 -11
  349. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +11 -11
  350. nautobot/project-static/docs/development/apps/api/views/base-template.html +11 -11
  351. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +11 -11
  352. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +11 -11
  353. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +11 -11
  354. nautobot/project-static/docs/development/apps/api/views/index.html +11 -11
  355. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +11 -11
  356. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +11 -11
  357. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +11 -11
  358. nautobot/project-static/docs/development/apps/api/views/notes.html +11 -11
  359. nautobot/project-static/docs/development/apps/api/views/rest-api.html +11 -11
  360. nautobot/project-static/docs/development/apps/api/views/urls.html +11 -11
  361. nautobot/project-static/docs/development/apps/index.html +11 -11
  362. nautobot/project-static/docs/development/apps/migration/code-updates.html +11 -11
  363. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +11 -11
  364. nautobot/project-static/docs/development/apps/migration/from-v1.html +11 -11
  365. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +11 -11
  366. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +11 -11
  367. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +11 -11
  368. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +11 -11
  369. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +11 -11
  370. nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +11 -11
  371. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +11 -11
  372. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +11 -11
  373. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +11 -11
  374. nautobot/project-static/docs/development/apps/porting-from-netbox.html +11 -11
  375. nautobot/project-static/docs/development/core/application-registry.html +11 -11
  376. nautobot/project-static/docs/development/core/best-practices.html +11 -11
  377. nautobot/project-static/docs/development/core/bootstrap-ui.html +11 -11
  378. nautobot/project-static/docs/development/core/caching.html +11 -11
  379. nautobot/project-static/docs/development/core/controllers.html +11 -11
  380. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +11 -11
  381. nautobot/project-static/docs/development/core/generic-views.html +11 -11
  382. nautobot/project-static/docs/development/core/getting-started.html +50 -63
  383. nautobot/project-static/docs/development/core/homepage.html +11 -11
  384. nautobot/project-static/docs/development/core/index.html +11 -11
  385. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +11 -11
  386. nautobot/project-static/docs/development/core/model-checklist.html +11 -11
  387. nautobot/project-static/docs/development/core/model-features.html +11 -11
  388. nautobot/project-static/docs/development/core/natural-keys.html +11 -11
  389. nautobot/project-static/docs/development/core/navigation-menu.html +11 -11
  390. nautobot/project-static/docs/development/core/release-checklist.html +11 -11
  391. nautobot/project-static/docs/development/core/role-internals.html +11 -11
  392. nautobot/project-static/docs/development/core/settings.html +11 -11
  393. nautobot/project-static/docs/development/core/style-guide.html +15 -11
  394. nautobot/project-static/docs/development/core/templates.html +11 -11
  395. nautobot/project-static/docs/development/core/testing.html +11 -11
  396. nautobot/project-static/docs/development/core/ui-component-framework.html +17 -22
  397. nautobot/project-static/docs/development/core/user-preferences.html +11 -11
  398. nautobot/project-static/docs/development/index.html +11 -11
  399. nautobot/project-static/docs/development/jobs/getting-started.html +11 -11
  400. nautobot/project-static/docs/development/jobs/index.html +11 -11
  401. nautobot/project-static/docs/development/jobs/installation.html +11 -11
  402. nautobot/project-static/docs/development/jobs/job-extensions.html +11 -11
  403. nautobot/project-static/docs/development/jobs/job-logging.html +11 -11
  404. nautobot/project-static/docs/development/jobs/job-patterns.html +11 -11
  405. nautobot/project-static/docs/development/jobs/job-structure.html +11 -11
  406. nautobot/project-static/docs/development/jobs/migration/from-v1.html +11 -11
  407. nautobot/project-static/docs/development/jobs/testing.html +11 -11
  408. nautobot/project-static/docs/index.html +11 -11
  409. nautobot/project-static/docs/objects.inv +0 -0
  410. nautobot/project-static/docs/overview/application_stack.html +11 -11
  411. nautobot/project-static/docs/overview/design_philosophy.html +11 -11
  412. nautobot/project-static/docs/release-notes/index.html +11 -11
  413. nautobot/project-static/docs/release-notes/version-1.0.html +11 -11
  414. nautobot/project-static/docs/release-notes/version-1.1.html +11 -11
  415. nautobot/project-static/docs/release-notes/version-1.2.html +11 -11
  416. nautobot/project-static/docs/release-notes/version-1.3.html +11 -11
  417. nautobot/project-static/docs/release-notes/version-1.4.html +11 -11
  418. nautobot/project-static/docs/release-notes/version-1.5.html +11 -11
  419. nautobot/project-static/docs/release-notes/version-1.6.html +11 -11
  420. nautobot/project-static/docs/release-notes/version-2.0.html +11 -11
  421. nautobot/project-static/docs/release-notes/version-2.1.html +11 -11
  422. nautobot/project-static/docs/release-notes/version-2.2.html +11 -11
  423. nautobot/project-static/docs/release-notes/version-2.3.html +11 -11
  424. nautobot/project-static/docs/release-notes/version-2.4.html +418 -11
  425. nautobot/project-static/docs/search/search_index.json +1 -1
  426. nautobot/project-static/docs/sitemap.xml +300 -300
  427. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  428. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +11 -11
  429. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +11 -11
  430. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +11 -11
  431. nautobot/project-static/docs/user-guide/administration/configuration/index.html +11 -11
  432. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +11 -11
  433. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +38 -11
  434. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +11 -11
  435. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +89 -14
  436. nautobot/project-static/docs/user-guide/administration/guides/docker.html +11 -11
  437. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +11 -11
  438. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +11 -11
  439. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +11 -11
  440. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +11 -11
  441. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +11 -11
  442. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +11 -11
  443. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +11 -11
  444. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +11 -11
  445. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +11 -11
  446. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +11 -11
  447. nautobot/project-static/docs/user-guide/administration/installation/index.html +11 -11
  448. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +11 -11
  449. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +11 -11
  450. nautobot/project-static/docs/user-guide/administration/installation/services.html +11 -11
  451. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +11 -11
  452. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +11 -11
  453. nautobot/project-static/docs/user-guide/administration/security/index.html +11 -11
  454. nautobot/project-static/docs/user-guide/administration/security/notices.html +11 -11
  455. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +11 -11
  456. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +11 -11
  457. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +11 -11
  458. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +11 -11
  459. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +11 -11
  460. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +11 -11
  461. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +11 -11
  462. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +11 -11
  463. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +11 -11
  464. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +11 -11
  465. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +11 -11
  466. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +11 -11
  467. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +11 -11
  468. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +11 -11
  469. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +11 -11
  470. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +11 -11
  471. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +11 -11
  472. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +11 -11
  473. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +11 -11
  474. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +11 -11
  475. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +11 -11
  476. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +11 -11
  477. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +11 -11
  478. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +11 -11
  479. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +11 -11
  480. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +11 -11
  481. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +11 -11
  482. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +11 -11
  483. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +11 -11
  484. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +11 -11
  485. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +11 -11
  486. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +11 -11
  487. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +11 -11
  488. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +11 -11
  489. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +11 -11
  490. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +11 -11
  491. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +11 -11
  492. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +11 -11
  493. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +11 -11
  494. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +11 -11
  495. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +11 -11
  496. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +11 -11
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +11 -11
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +11 -11
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +11 -11
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +11 -11
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +11 -11
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +11 -11
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +11 -11
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +11 -11
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +11 -11
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +11 -11
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +11 -11
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +11 -11
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +11 -11
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +11 -11
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +11 -11
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +11 -11
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +11 -11
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +11 -11
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +11 -11
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +11 -11
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +11 -11
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +11 -11
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +11 -11
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +11 -11
  521. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +11 -11
  522. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +11 -11
  523. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +11 -11
  524. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +11 -11
  525. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +11 -11
  526. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +11 -11
  527. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +11 -11
  528. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +11 -11
  529. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +11 -11
  530. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +11 -11
  531. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +11 -11
  532. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +11 -11
  533. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +11 -11
  534. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +11 -11
  535. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +11 -11
  536. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +11 -11
  537. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +11 -11
  538. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +11 -11
  539. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +11 -11
  540. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +11 -11
  541. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +11 -11
  542. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +11 -11
  543. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +11 -11
  544. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +11 -11
  545. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +11 -11
  546. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -11
  547. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +11 -11
  548. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +11 -11
  549. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +11 -11
  550. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +11 -11
  551. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +11 -11
  552. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +11 -11
  553. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +11 -11
  554. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +11 -11
  555. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +11 -11
  556. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +11 -11
  557. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +11 -11
  558. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +11 -11
  559. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +11 -11
  560. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +11 -11
  561. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +11 -11
  562. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +11 -11
  563. nautobot/project-static/docs/user-guide/index.html +11 -11
  564. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +11 -11
  565. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +11 -11
  566. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +11 -11
  567. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +11 -11
  568. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +11 -11
  569. nautobot/project-static/docs/user-guide/platform-functionality/events.html +11 -11
  570. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +11 -11
  571. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +11 -11
  572. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +11 -11
  573. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +11 -11
  574. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +11 -11
  575. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +11 -11
  576. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +11 -11
  577. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +11 -11
  578. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +11 -11
  579. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +11 -11
  580. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +11 -11
  581. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +11 -11
  582. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +11 -11
  583. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +11 -11
  584. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +11 -11
  585. nautobot/project-static/docs/user-guide/platform-functionality/note.html +11 -11
  586. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +11 -11
  587. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +11 -11
  588. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +11 -11
  589. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +11 -11
  590. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +11 -11
  591. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +11 -11
  592. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +11 -11
  593. nautobot/project-static/docs/user-guide/platform-functionality/role.html +11 -11
  594. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +11 -11
  595. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +11 -11
  596. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +11 -11
  597. nautobot/project-static/docs/user-guide/platform-functionality/status.html +11 -11
  598. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +11 -11
  599. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +11 -11
  600. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +11 -11
  601. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +11 -11
  602. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +11 -11
  603. nautobot/project-static/img/nautobot_icon.svg +32 -34
  604. nautobot/project-static/js/table_sorting_indicator.js +0 -2
  605. nautobot/tenancy/templates/tenancy/tenant.html +1 -7
  606. nautobot/tenancy/views.py +13 -0
  607. nautobot/users/templates/users/api_tokens.html +4 -4
  608. nautobot/users/templates/users/base.html +28 -28
  609. nautobot/virtualization/templates/virtualization/cluster.html +64 -64
  610. nautobot/virtualization/templates/virtualization/inc/virtualmachine_vminterface_filter.html +8 -0
  611. nautobot/virtualization/templates/virtualization/virtualmachine_component_add.html +25 -25
  612. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +1 -251
  613. nautobot/virtualization/templates/virtualization/vminterface.html +70 -70
  614. nautobot/virtualization/urls.py +0 -12
  615. nautobot/virtualization/views.py +158 -54
  616. nautobot/wireless/templates/wireless/wirelessnetwork_create.html +13 -13
  617. nautobot/wireless/tests/integration/test_radio_profile.py +1 -1
  618. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/METADATA +4 -4
  619. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/RECORD +623 -607
  620. nautobot/core/templates/inc/breadcrumbs.html +0 -14
  621. nautobot/ipam/templates/ipam/prefix_ipaddresses.html +0 -11
  622. nautobot/ipam/templates/ipam/prefix_prefixes.html +0 -11
  623. nautobot/project-static/docs/requirements.txt +0 -14
  624. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/LICENSE.txt +0 -0
  625. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/NOTICE +0 -0
  626. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/WHEEL +0 -0
  627. {nautobot-2.4.17.dist-info → nautobot-2.4.19.dist-info}/entry_points.txt +0 -0
@@ -1,4 +1,5 @@
1
1
  import contextlib
2
+ import inspect
2
3
  import re
3
4
  from typing import Optional, Sequence
4
5
  from unittest import mock, skipIf
@@ -9,8 +10,10 @@ from django.conf import settings
9
10
  from django.contrib.contenttypes.models import ContentType
10
11
  from django.core.exceptions import ObjectDoesNotExist, ValidationError
11
12
  from django.core.validators import URLValidator
13
+ from django.db import connection
12
14
  from django.db.models import ManyToManyField, Model, QuerySet
13
15
  from django.test import override_settings, tag, TestCase as _TestCase
16
+ from django.test.utils import CaptureQueriesContext
14
17
  from django.urls import NoReverseMatch, reverse
15
18
  from django.utils.html import escape
16
19
  from django.utils.http import urlencode
@@ -144,6 +147,10 @@ class ViewTestCases:
144
147
  """
145
148
 
146
149
  custom_action_required_permissions = {}
150
+ # TODO: Expand to other relevant view types, e.g. 'list'.
151
+ allowed_number_of_tree_queries_per_view_type = {
152
+ "retrieve": 0,
153
+ }
147
154
 
148
155
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
149
156
  def test_get_object_anonymous(self):
@@ -180,7 +187,8 @@ class ViewTestCases:
180
187
  self.add_permissions(f"{self.model._meta.app_label}.view_{self.model._meta.model_name}")
181
188
 
182
189
  # Try GET with model-level permission
183
- response = self.client.get(instance.get_absolute_url())
190
+ with CaptureQueriesContext(connection) as capture_queries_context:
191
+ response = self.client.get(instance.get_absolute_url())
184
192
  # The object's display name or string representation should appear in the response body
185
193
  self.assertBodyContains(response, escape(getattr(instance, "display", str(instance))))
186
194
 
@@ -209,6 +217,22 @@ class ViewTestCases:
209
217
  else:
210
218
  self.assertBodyContains(response, escape(str(instance.cf.get(custom_field.key) or "")))
211
219
 
220
+ # Check that no more than the appropriate number of tree CTE queries have been run.
221
+ captured_tree_cte_queries = [
222
+ query["sql"] for query in capture_queries_context.captured_queries if "WITH RECURSIVE" in query["sql"]
223
+ ]
224
+ _query_separator = "\n" + ("-" * 10) + "\n" + "NEXT QUERY" + "\n" + ("-" * 10)
225
+ self.assertEqual(
226
+ len(captured_tree_cte_queries),
227
+ self.allowed_number_of_tree_queries_per_view_type["retrieve"],
228
+ f"This view was expected to execute {self.allowed_number_of_tree_queries_per_view_type['retrieve']}"
229
+ f" recursive database queries but {len(captured_tree_cte_queries)} were executed."
230
+ f" If this is expected, please update the {self.__class__.__name__}.allowed_number_of_tree_queries_per_view_type['retrieve']"
231
+ " property. Care should be taken to only increase these numbers where necessary - recursive queries can become really"
232
+ " slow with bigger datasets."
233
+ f" The following queries were used:\n{_query_separator.join(captured_tree_cte_queries)}",
234
+ )
235
+
212
236
  return response # for consumption by child test cases if desired
213
237
 
214
238
  @override_settings(EXEMPT_VIEW_PERMISSIONS=[])
@@ -776,6 +800,30 @@ class ViewTestCases:
776
800
  response_body = response.content.decode(response.charset)
777
801
  self.assertNotIn('<i class="mdi mdi-circle-small"></i>', response_body)
778
802
 
803
+ def test_model_properties_as_table_columns_are_not_orderable(self):
804
+ """
805
+ Check for table columns that are property-based and not orderable.
806
+ """
807
+ table_class = getattr(self.get_list_view(), "table_class", None)
808
+ if not table_class:
809
+ return
810
+
811
+ queryset = self._get_queryset()
812
+ table = table_class(queryset)
813
+ model_cls = table._meta.model
814
+
815
+ property_fields = {name for name, _ in inspect.getmembers(model_cls, lambda o: isinstance(o, property))}
816
+
817
+ for name, column in table.base_columns.items():
818
+ if hasattr(column, "order_by") and column.order_by:
819
+ continue
820
+ if name in property_fields and name != "pk":
821
+ with self.subTest(column_name=name):
822
+ self.assertFalse(
823
+ column.orderable,
824
+ f"On Table `{table_class.__name__}` the property-based column `{name}` should be orderable=False or use a custom order_by",
825
+ )
826
+
779
827
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
780
828
  def test_list_objects_anonymous(self):
781
829
  # Make the request as an unauthenticated user
@@ -1379,10 +1427,6 @@ class ViewTestCases:
1379
1427
  # Expect a 200 status cause we are only rendering the bulk delete table after pressing Delete Selected button.
1380
1428
  self.assertHttpStatus(response, 200)
1381
1429
  response_body = utils.extract_page_body(response.content.decode(response.charset))
1382
- # Check if all pks is not part of the html.
1383
- self.assertNotIn(str(first_pk), response_body)
1384
- self.assertNotIn(str(second_pk), response_body)
1385
- self.assertNotIn(str(third_pk), response_body)
1386
1430
  self.assertIn("<strong>Warning:</strong> The following operation will delete 2 ", response_body)
1387
1431
  self.assertInHTML('<input type="hidden" name="_all" value="true" />', response_body)
1388
1432
 
@@ -12,11 +12,14 @@ from nautobot.core.testing import TestCase
12
12
  from nautobot.core.ui.breadcrumbs import (
13
13
  BaseBreadcrumbItem,
14
14
  Breadcrumbs,
15
+ context_object_attr,
15
16
  InstanceBreadcrumbItem,
17
+ InstanceParentBreadcrumbItem,
16
18
  ModelBreadcrumbItem,
17
19
  ViewNameBreadcrumbItem,
18
20
  )
19
- from nautobot.dcim.models import Device, LocationType
21
+ from nautobot.dcim.models import Device, Location, LocationType
22
+ from nautobot.extras.models import Status
20
23
 
21
24
 
22
25
  class BreadcrumbItemsTestCase(TestCase):
@@ -150,6 +153,13 @@ class BreadcrumbItemsTestCase(TestCase):
150
153
  self.assertEqual(url, test_case["expected_url"])
151
154
  self.assertEqual(label, test_case["expected_label"])
152
155
 
156
+ def test_model_item_not_format_custom_label(self):
157
+ item = ModelBreadcrumbItem(model_key="object", label="custom LaBeL")
158
+ context = Context({"object": self.location_type})
159
+
160
+ _, label = item.as_pair(context)
161
+ self.assertEqual(label, "custom LaBeL")
162
+
153
163
  def test_model_item_from_context(self):
154
164
  """Test breadcrumb item with model from context."""
155
165
  item = ModelBreadcrumbItem(model_key="object")
@@ -209,6 +219,69 @@ class BreadcrumbItemsTestCase(TestCase):
209
219
  self.assertEqual(url, "")
210
220
  self.assertEqual(label, "")
211
221
 
222
+ def test_instance_item_not_add_title_casing(self):
223
+ context = Context({"object": LocationType.objects.create(name="custom name")})
224
+ item = InstanceBreadcrumbItem()
225
+
226
+ _, label = item.as_pair(context)
227
+ self.assertEqual(label, "custom name")
228
+
229
+ def test_instance_item_is_working_with_directly_passed_instance(self):
230
+ context = Context({})
231
+ instance = LocationType.objects.create(name="cUsToM CoUnTrY")
232
+ item = InstanceBreadcrumbItem(instance=instance)
233
+
234
+ url, label = item.as_pair(context)
235
+ self.assertEqual(url, f"/dcim/location-types/{instance.pk}/")
236
+ self.assertEqual(label, "cUsToM CoUnTrY")
237
+
238
+ def test_context_object_attr_works_with_various_breadcrumb_items(self):
239
+ parent_location_type = LocationType.objects.create(name="Country", nestable=True)
240
+ location_type = LocationType.objects.create(name="State", parent=parent_location_type)
241
+ status = Status.objects.get_for_model(Location).first()
242
+ location = Location.objects.create(name="Pomorskie", location_type=location_type, status=status)
243
+
244
+ context = Context({"object": location, "status": status})
245
+
246
+ item = InstanceBreadcrumbItem(instance=context_object_attr("location_type"))
247
+ url, label = item.as_pair(context)
248
+ self.assertEqual(url, f"/dcim/location-types/{location_type.pk}/")
249
+ self.assertEqual(label, "Country → State")
250
+
251
+ item = BaseBreadcrumbItem(label=context_object_attr("name", context_key="status"))
252
+ url, label = item.as_pair(context)
253
+ self.assertEqual(url, "")
254
+ self.assertEqual(label, status.name)
255
+
256
+ item = InstanceBreadcrumbItem(instance=context_object_attr("location_type.parent"))
257
+ url, label = item.as_pair(context)
258
+ self.assertEqual(url, f"/dcim/location-types/{parent_location_type.pk}/")
259
+ self.assertEqual(label, "Country")
260
+
261
+ def test_instance_parent_not_add_title_casing(self):
262
+ parent_location_type = LocationType.objects.create(name="cUsToM CoUnTrY", nestable=True)
263
+ context = Context({"object": LocationType.objects.create(name="custom name", parent=parent_location_type)})
264
+ item = InstanceParentBreadcrumbItem()
265
+
266
+ _, label = item.as_pair(context)
267
+ self.assertEqual(label, "cUsToM CoUnTrY")
268
+
269
+ def test_instance_parent_is_create_proper_url(self):
270
+ parent_location_type = LocationType.objects.create(name="Country", nestable=True)
271
+ location_type = LocationType.objects.create(name="State", parent=parent_location_type)
272
+
273
+ context = Context({"object": location_type})
274
+
275
+ item = InstanceParentBreadcrumbItem()
276
+ url, label = item.as_pair(context)
277
+ self.assertEqual(url, f"/dcim/location-types/?parent={parent_location_type.pk}")
278
+ self.assertEqual(label, "Country")
279
+
280
+ item = InstanceParentBreadcrumbItem(parent_query_param="location", parent_lookup_key="name")
281
+ url, label = item.as_pair(context)
282
+ self.assertEqual(url, "/dcim/location-types/?location=Country")
283
+ self.assertEqual(label, "Country")
284
+
212
285
 
213
286
  class BreadcrumbsTestCase(TestCase):
214
287
  """Test cases for Breadcrumbs class."""
@@ -260,19 +333,20 @@ class BreadcrumbsTestCase(TestCase):
260
333
  "list": [ViewNameBreadcrumbItem(view_name="", label="List Item")],
261
334
  "detail": [ViewNameBreadcrumbItem(view_name="", label="Detail Item")],
262
335
  }
336
+ context = Context({})
263
337
 
264
338
  # Test specific action found
265
- result = Breadcrumbs.get_items_for_action(test_items, "list", False)
339
+ result = Breadcrumbs().get_items_for_action(test_items, "list", False, context)
266
340
  self.assertEqual(len(result), 1)
267
341
  self.assertEqual(result[0].label, "List Item")
268
342
 
269
343
  # Test fallback to detail when action not found and detail=True
270
- result = Breadcrumbs.get_items_for_action(test_items, "nonexistent", True)
344
+ result = Breadcrumbs().get_items_for_action(test_items, "nonexistent", True, context)
271
345
  self.assertEqual(len(result), 1)
272
346
  self.assertEqual(result[0].label, "Detail Item")
273
347
 
274
348
  # Test no fallback when detail=False
275
- result = Breadcrumbs.get_items_for_action(test_items, "nonexistent", False)
349
+ result = Breadcrumbs().get_items_for_action(test_items, "nonexistent", False, context)
276
350
  self.assertEqual(len(result), 0)
277
351
  self.assertEqual(result, [])
278
352
 
@@ -29,10 +29,13 @@ class ManagementCommandTestCase(TestCase):
29
29
  # status_code_to_endpoints = collections.defaultdict(list)
30
30
  for view_name, value in endpoints_dict.items():
31
31
  for endpoint in value:
32
- response = self.client.get(endpoint, follow=True)
33
- self.assertHttpStatus(
34
- response, 200, f"{view_name}: {endpoint} returns status Code {response.status_code} instead of 200"
35
- )
32
+ with self.subTest(endpoint=endpoint):
33
+ response = self.client.get(endpoint, follow=True)
34
+ self.assertHttpStatus(
35
+ response,
36
+ 200,
37
+ f"{view_name}: {endpoint} returns status Code {response.status_code} instead of 200",
38
+ )
36
39
 
37
40
  def test_check_job_approval_status_no_jobs(self):
38
41
  out = StringIO()
@@ -11,7 +11,7 @@ from django.contrib.auth.models import Group
11
11
  from django.contrib.contenttypes.models import ContentType
12
12
  from django.core.cache import cache
13
13
  from django.db.models import Count, Q
14
- from django.test import override_settings, TestCase
14
+ from django.test import override_settings
15
15
  from django.test.client import RequestFactory
16
16
  from django.urls import reverse
17
17
  import graphene.types
@@ -38,7 +38,7 @@ from nautobot.core.graphql.schema import (
38
38
  )
39
39
  from nautobot.core.graphql.types import DateType, OptimizedNautobotObjectType
40
40
  from nautobot.core.graphql.utils import str_to_var_name
41
- from nautobot.core.testing import create_test_user, NautobotTestClient
41
+ from nautobot.core.testing import create_test_user, NautobotTestClient, TestCase
42
42
  from nautobot.dcim.choices import ConsolePortTypeChoices, InterfaceModeChoices, InterfaceTypeChoices, PortTypeChoices
43
43
  from nautobot.dcim.filters import DeviceFilterSet, LocationFilterSet
44
44
  from nautobot.dcim.graphql.types import DeviceType as DeviceTypeGraphQL
@@ -1453,9 +1453,7 @@ query {
1453
1453
  # Assert GraphQL returned properties match those expected
1454
1454
  self.assertEqual(console_server_port_entry["connected_console_port"], connected_console_port)
1455
1455
 
1456
- @skip(
1457
- "Works in isolation, fails as part of the overall test suite due to issue #446, also something is broken with content types"
1458
- )
1456
+ @skip("Works in isolation, fails as part of the overall test suite due to issue #446")
1459
1457
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1460
1458
  def test_query_relationship_associations(self):
1461
1459
  """Test queries involving relationship associations."""
@@ -2442,6 +2440,23 @@ query {
2442
2440
  expected_interfaces_first = {"ip_addresses": [{"primary_ip4_for": [{"id": str(self.device1.id)}]}]}
2443
2441
  self.assertEqual(result.data["device"]["interfaces"][0], expected_interfaces_first)
2444
2442
 
2443
+ @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
2444
+ def test_query_optimizer_reverse_lookup(self):
2445
+ """
2446
+ Test query optimization in the case of a query mixing reverse and forward nested lookups.
2447
+
2448
+ See https://github.com/nautobot/nautobot/issues/7651.
2449
+ """
2450
+ query = """query { tenant_groups { name tenants { name } } }"""
2451
+ # Prewarm caches of Relationships and such to reduce variation in the number of queries below
2452
+ result = self.execute_query(query)
2453
+ self.assertNotIn("error", str(result))
2454
+ # Run it again and assert that the optimized query is run.
2455
+ # Before the fix for #7651 this would result in N+1 queries where N is the number of tenant-groups!
2456
+ with self.assertNumQueries(2):
2457
+ result = self.execute_query(query)
2458
+ self.assertNotIn("error", str(result))
2459
+
2445
2460
 
2446
2461
  class GraphQLTypeTestCase(UnitTestTestCase):
2447
2462
  def test_date_type(self):
@@ -798,7 +798,8 @@ class BulkEditTestCase(TransactionTestCase):
798
798
  "BulkEditObjects",
799
799
  content_type=self.role_ct.id,
800
800
  edit_all=False,
801
- filter_query_params={"per_page": 2},
801
+ filter_query_params={"per_page": [2]},
802
+ pk_list=pk_list,
802
803
  form_data={"pk": pk_list, "color": "aa1409"},
803
804
  username=self.user.username,
804
805
  )
@@ -818,7 +819,8 @@ class BulkEditTestCase(TransactionTestCase):
818
819
  "BulkEditObjects",
819
820
  content_type=self.role_ct.id,
820
821
  edit_all=False,
821
- filter_query_params={"sort": "name"},
822
+ pk_list=pk_list,
823
+ filter_query_params={"sort": ["name"]},
822
824
  form_data={"pk": pk_list, "color": "aa1409"},
823
825
  username=self.user.username,
824
826
  )
@@ -872,6 +874,7 @@ class BulkEditTestCase(TransactionTestCase):
872
874
  content_type=self.namespace_ct.id,
873
875
  edit_all=False,
874
876
  filter_query_params={},
877
+ pk_list=pk_list,
875
878
  form_data={
876
879
  "pk": pk_list,
877
880
  "description": "Example description for bulk edit",
@@ -969,15 +972,16 @@ class BulkEditTestCase(TransactionTestCase):
969
972
  "nautobot.core.jobs.bulk_actions",
970
973
  "BulkEditObjects",
971
974
  content_type=self.status_ct.id,
972
- edit_all=False,
973
- filter_query_params={"name__isw": "A", "sort": "name"},
975
+ edit_all=True,
976
+ filter_query_params={"name__isw": ["A"], "sort": ["name"]},
977
+ pk_list=[str(statuses[0].pk)],
974
978
  form_data={
975
979
  "pk": [str(statuses[0].pk)],
976
980
  "color": "aa1409",
977
981
  },
978
982
  username=self.user.username,
979
983
  )
980
- self._common_no_error_test_assertion(Status, job_result, 1, name__istartswith="A", color="aa1409")
984
+ self._common_no_error_test_assertion(Status, job_result, len(statuses), name__istartswith="A", color="aa1409")
981
985
  self.assertNotEqual(status_to_ignore.color, "aa1409")
982
986
 
983
987
  def test_bulk_edit_objects_passing_in_both_pk_list_and_edit_all(self):
@@ -994,7 +998,7 @@ class BulkEditTestCase(TransactionTestCase):
994
998
  "BulkEditObjects",
995
999
  content_type=self.status_ct.id,
996
1000
  edit_all=True,
997
- filter_query_params={"name__isw": "A"},
1001
+ filter_query_params={"name__isw": ["A"]},
998
1002
  # pk ignored if edit_all is True
999
1003
  form_data={
1000
1004
  "pk": [str(statuses[0].pk)],
@@ -1110,9 +1114,12 @@ class BulkDeleteTestCase(TransactionTestCase):
1110
1114
  job_result = create_job_result_and_run_job(
1111
1115
  "nautobot.core.jobs.bulk_actions",
1112
1116
  "BulkDeleteObjects",
1117
+ username=self.user.username,
1113
1118
  content_type=self.status_ct.id,
1119
+ delete_all=False,
1120
+ filter_query_params={},
1114
1121
  pk_list=statuses_to_delete,
1115
- username=self.user.username,
1122
+ saved_view_id=None,
1116
1123
  )
1117
1124
  self.assertJobResultStatus(job_result, JobResultStatusChoices.STATUS_FAILURE)
1118
1125
  job_log = JobLogEntry.objects.get(job_result=job_result, log_level=LogLevelChoices.LOG_ERROR)
@@ -1129,19 +1136,19 @@ class BulkDeleteTestCase(TransactionTestCase):
1129
1136
  obj_perm.save()
1130
1137
  obj_perm.users.add(self.user)
1131
1138
  obj_perm.object_types.add(ContentType.objects.get_for_model(Status))
1132
-
1133
1139
  job_result = create_job_result_and_run_job(
1134
1140
  "nautobot.core.jobs.bulk_actions",
1135
1141
  "BulkDeleteObjects",
1142
+ username=self.user.username,
1136
1143
  content_type=self.status_ct.id,
1144
+ delete_all=False,
1145
+ filter_query_params={},
1137
1146
  pk_list=statuses_to_delete,
1138
- username=self.user.username,
1147
+ saved_view_id=None,
1139
1148
  )
1140
1149
  self.assertJobResultStatus(job_result, JobResultStatusChoices.STATUS_FAILURE)
1141
1150
  error_log = JobLogEntry.objects.get(job_result=job_result, log_level=LogLevelChoices.LOG_ERROR)
1142
- self.assertEqual(
1143
- error_log.message, "You do not have permissions to delete some of the objects provided in `pk_list`."
1144
- )
1151
+ self.assertIn("Cannot delete some instances of model", error_log.message)
1145
1152
  self.assertEqual(Status.objects.filter(pk__in=statuses_to_delete).count(), len(statuses_to_delete))
1146
1153
 
1147
1154
  def test_bulk_delete_objects_select_all(self):
@@ -1155,11 +1162,12 @@ class BulkDeleteTestCase(TransactionTestCase):
1155
1162
  job_result = create_job_result_and_run_job(
1156
1163
  "nautobot.core.jobs.bulk_actions",
1157
1164
  "BulkDeleteObjects",
1165
+ username=self.user.username,
1158
1166
  content_type=ContentType.objects.get_for_model(Circuit).id,
1159
1167
  delete_all=True,
1160
- filter_query_params={"per_page": 10},
1168
+ filter_query_params={"per_page": [10]},
1161
1169
  pk_list=[],
1162
- username=self.user.username,
1170
+ saved_view_id=None,
1163
1171
  )
1164
1172
  self._common_no_error_test_assertion(Circuit, job_result)
1165
1173
 
@@ -1174,11 +1182,12 @@ class BulkDeleteTestCase(TransactionTestCase):
1174
1182
  job_result = create_job_result_and_run_job(
1175
1183
  "nautobot.core.jobs.bulk_actions",
1176
1184
  "BulkDeleteObjects",
1185
+ username=self.user.username,
1177
1186
  content_type=self.role_ct.id,
1178
1187
  delete_all=False,
1179
1188
  filter_query_params={},
1180
1189
  pk_list=roles_pks,
1181
- username=self.user.username,
1190
+ saved_view_id=None,
1182
1191
  )
1183
1192
  self._common_no_error_test_assertion(Role, job_result, pk__in=roles_pks)
1184
1193
  self.assertTrue(Role.objects.filter(name=roles_to_ignore.name).exists())
@@ -1192,10 +1201,12 @@ class BulkDeleteTestCase(TransactionTestCase):
1192
1201
  job_result = create_job_result_and_run_job(
1193
1202
  "nautobot.core.jobs.bulk_actions",
1194
1203
  "BulkDeleteObjects",
1204
+ username=self.user.username,
1195
1205
  content_type=self.status_ct.id,
1196
1206
  delete_all=True,
1197
- filter_query_params={"name__isw": "Example Status", "sort": "name"},
1198
- username=self.user.username,
1207
+ filter_query_params={"name__isw": ["Example Status"], "sort": ["name"]},
1208
+ pk_list=[],
1209
+ saved_view_id=None,
1199
1210
  )
1200
1211
  self._common_no_error_test_assertion(Status, job_result, name__istartswith="Example Status")
1201
1212
  self.assertTrue(Status.objects.filter(name=status_to_ignore.name).exists())
@@ -1211,11 +1222,12 @@ class BulkDeleteTestCase(TransactionTestCase):
1211
1222
  job_result = create_job_result_and_run_job(
1212
1223
  "nautobot.core.jobs.bulk_actions",
1213
1224
  "BulkDeleteObjects",
1225
+ username=self.user.username,
1214
1226
  content_type=self.role_ct.id,
1215
1227
  delete_all=False,
1216
- filter_query_params={"name__isw": "Example Status"},
1228
+ filter_query_params={"name__isw": ["Example Status"]},
1217
1229
  pk_list=roles_pks,
1218
- username=self.user.username,
1230
+ saved_view_id=None,
1219
1231
  )
1220
1232
  self._common_no_error_test_assertion(Role, job_result, pk__in=roles_pks)
1221
1233
  self.assertTrue(Role.objects.filter(name=roles_to_ignore.name).exists())
@@ -1228,10 +1240,11 @@ class BulkDeleteTestCase(TransactionTestCase):
1228
1240
  job_result = create_job_result_and_run_job(
1229
1241
  "nautobot.core.jobs.bulk_actions",
1230
1242
  "BulkDeleteObjects",
1243
+ username=self.user.username,
1231
1244
  content_type=self.status_ct.pk,
1232
1245
  delete_all=True,
1233
- filter_query_params={"name__isw": "Example Status", "sort": "name"},
1246
+ filter_query_params={"name__isw": ["Example Status"]},
1234
1247
  pk_list=[str(Status.objects.first().pk)],
1235
- username=self.user.username,
1248
+ saved_view_id=None,
1236
1249
  )
1237
1250
  self._common_no_error_test_assertion(Role, job_result, name__istartswith="Example Status")
@@ -18,8 +18,18 @@ class TableTestCase(TestCase):
18
18
  def _validate_sorted_tree_queryset_same_with_table_queryset(self, queryset, table_class, field_name):
19
19
  with self.subTest(f"Assert sorting {table_class.__name__} on '{field_name}'"):
20
20
  table = table_class(queryset.with_tree_fields(), order_by=field_name)
21
- table_queryset_data = table.data.data.values_list("pk", flat=True)
22
- sorted_queryset = queryset.with_tree_fields().extra(order_by=[field_name]).values_list("pk", flat=True)
21
+ table_queryset_data = table.data.data.values_list(field_name, flat=True)
22
+ sorted_queryset = (
23
+ queryset.with_tree_fields().extra(order_by=[field_name]).values_list(field_name, flat=True)
24
+ )
25
+ self.assertEqual(list(table_queryset_data), list(sorted_queryset))
26
+
27
+ with self.subTest(f"Assert sorting {table_class.__name__} on '-{field_name}'"):
28
+ table = table_class(queryset.with_tree_fields(), order_by=f"-{field_name}")
29
+ table_queryset_data = table.data.data.values_list(field_name, flat=True)
30
+ sorted_queryset = (
31
+ queryset.with_tree_fields().extra(order_by=[f"-{field_name}"]).values_list(field_name, flat=True)
32
+ )
23
33
  self.assertEqual(list(table_queryset_data), list(sorted_queryset))
24
34
 
25
35
  def test_tree_model_table_orderable(self):
@@ -61,14 +71,41 @@ class TableTestCase(TestCase):
61
71
  table_avail_fields = set(model_field_names) & set(table_class.Meta.fields)
62
72
  for table_field_name in table_avail_fields:
63
73
  self._validate_sorted_tree_queryset_same_with_table_queryset(queryset, table_class, table_field_name)
64
- self._validate_sorted_tree_queryset_same_with_table_queryset(
65
- queryset, table_class, f"-{table_field_name}"
66
- )
67
74
 
68
75
  # Test for `rack_count`
69
76
  queryset = RackGroupTable.Meta.model.objects.annotate(rack_count=count_related(Rack, "rack_group")).all()
70
77
  self._validate_sorted_tree_queryset_same_with_table_queryset(queryset, RackGroupTable, "rack_count")
71
- self._validate_sorted_tree_queryset_same_with_table_queryset(queryset, RackGroupTable, "-rack_count")
78
+
79
+ # https://github.com/nautobot/nautobot/issues/7330 - sorting by custom field
80
+ l1 = Location.objects.first()
81
+ l1._custom_field_data["example_app_auto_custom_field"] = "alpha"
82
+ l1.validated_save()
83
+ l2 = Location.objects.last()
84
+ l2._custom_field_data["example_app_auto_custom_field"] = "omega"
85
+ l2.validated_save()
86
+ table = LocationTable(
87
+ Location.objects.exclude(_custom_field_data__example_app_auto_custom_field="Default value")
88
+ )
89
+
90
+ table.order_by = ["cf_example_app_auto_custom_field"]
91
+ table_queryset_data = table.data.data.values_list("pk", flat=True)
92
+ sorted_queryset = (
93
+ Location.objects.with_tree_fields()
94
+ .exclude(_custom_field_data__example_app_auto_custom_field="Default value")
95
+ .extra(order_by=["_custom_field_data__example_app_auto_custom_field"])
96
+ .values_list("pk", flat=True)
97
+ )
98
+ self.assertEqual(list(table_queryset_data), list(sorted_queryset))
99
+
100
+ table.order_by = ["-cf_example_app_auto_custom_field"]
101
+ table_queryset_data = table.data.data.values_list("pk", flat=True)
102
+ sorted_queryset = (
103
+ Location.objects.with_tree_fields()
104
+ .exclude(_custom_field_data__example_app_auto_custom_field="Default value")
105
+ .extra(order_by=["-_custom_field_data__example_app_auto_custom_field"])
106
+ .values_list("pk", flat=True)
107
+ )
108
+ self.assertEqual(list(table_queryset_data), list(sorted_queryset))
72
109
 
73
110
  def test_base_table_apis(self):
74
111
  """