nautobot 2.4.13__py3-none-any.whl → 2.4.15__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 (463) hide show
  1. nautobot/apps/choices.py +8 -0
  2. nautobot/apps/ui.py +14 -0
  3. nautobot/core/api/views.py +2 -0
  4. nautobot/core/choices.py +4 -0
  5. nautobot/core/filters.py +21 -41
  6. nautobot/core/graphql/generators.py +8 -0
  7. nautobot/core/graphql/schema.py +30 -30
  8. nautobot/core/management/commands/check_job_approval_status.py +47 -0
  9. nautobot/core/management/commands/generate_test_data.py +1 -1
  10. nautobot/core/management/commands/migrate.py +90 -1
  11. nautobot/core/models/tree_queries.py +17 -0
  12. nautobot/core/settings.py +2 -2
  13. nautobot/core/settings.yaml +3 -3
  14. nautobot/core/tables.py +29 -6
  15. nautobot/core/templates/base_django.html +1 -1
  16. nautobot/core/templates/components/panel/header_extra_content_table.html +1 -1
  17. nautobot/core/templates/generic/object_list.html +17 -20
  18. nautobot/core/templates/inc/breadcrumbs.html +14 -0
  19. nautobot/core/templatetags/buttons.py +2 -4
  20. nautobot/core/templatetags/helpers.py +29 -6
  21. nautobot/core/templatetags/ui_framework.py +21 -0
  22. nautobot/core/testing/api.py +7 -0
  23. nautobot/core/testing/filters.py +20 -3
  24. nautobot/core/testing/forms.py +1 -1
  25. nautobot/core/tests/integration/test_filters.py +2 -2
  26. nautobot/core/tests/test_breadcrumbs.py +366 -0
  27. nautobot/core/tests/test_commands.py +40 -0
  28. nautobot/core/tests/test_filters.py +51 -1
  29. nautobot/core/tests/test_forms.py +1 -1
  30. nautobot/core/tests/test_graphql.py +4 -4
  31. nautobot/core/tests/test_titles.py +183 -0
  32. nautobot/core/tests/test_tree_queries.py +30 -0
  33. nautobot/core/tests/test_views.py +2 -2
  34. nautobot/core/tests/test_views_utils.py +1 -1
  35. nautobot/core/ui/breadcrumbs.py +538 -0
  36. nautobot/core/ui/bulk_buttons.py +53 -0
  37. nautobot/core/ui/object_detail.py +31 -8
  38. nautobot/core/ui/titles.py +127 -0
  39. nautobot/core/ui/utils.py +25 -0
  40. nautobot/core/utils/migrations.py +1 -1
  41. nautobot/core/views/__init__.py +1 -1
  42. nautobot/core/views/mixins.py +26 -1
  43. nautobot/core/views/renderers.py +20 -2
  44. nautobot/core/views/utils.py +14 -13
  45. nautobot/dcim/api/serializers.py +9 -0
  46. nautobot/dcim/choices.py +55 -0
  47. nautobot/dcim/constants.py +0 -16
  48. nautobot/dcim/factory.py +1 -1
  49. nautobot/dcim/filters/__init__.py +15 -3
  50. nautobot/dcim/forms.py +120 -7
  51. nautobot/dcim/management/commands/trace_paths.py +1 -1
  52. nautobot/dcim/migrations/0072_alter_powerfeed_options_and_more.py +97 -0
  53. nautobot/dcim/models/device_component_templates.py +8 -0
  54. nautobot/dcim/models/device_components.py +31 -12
  55. nautobot/dcim/models/devices.py +1 -1
  56. nautobot/dcim/models/power.py +171 -10
  57. nautobot/dcim/models/racks.py +7 -4
  58. nautobot/dcim/tables/devices.py +2 -0
  59. nautobot/dcim/tables/devicetypes.py +1 -0
  60. nautobot/dcim/tables/power.py +30 -2
  61. nautobot/dcim/templates/dcim/device.html +2 -2
  62. nautobot/dcim/templates/dcim/devicetype_retrieve.html +1 -214
  63. nautobot/dcim/templates/dcim/location_retrieve.html +2 -2
  64. nautobot/dcim/templates/dcim/powerfeed_edit.html +8 -0
  65. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -1
  66. nautobot/dcim/templates/dcim/rack.html +2 -318
  67. nautobot/dcim/templates/dcim/rack_edit.html +2 -47
  68. nautobot/dcim/templates/dcim/rack_retrieve.html +318 -0
  69. nautobot/dcim/templates/dcim/rack_update.html +47 -0
  70. nautobot/dcim/tests/integration/test_device_bulk_operations.py +61 -0
  71. nautobot/dcim/tests/test_api.py +24 -4
  72. nautobot/dcim/tests/test_filters.py +91 -13
  73. nautobot/dcim/tests/test_models.py +262 -0
  74. nautobot/dcim/tests/test_views.py +20 -12
  75. nautobot/dcim/urls.py +2 -27
  76. nautobot/dcim/utils.py +13 -30
  77. nautobot/dcim/views.py +428 -146
  78. nautobot/extras/choices.py +12 -4
  79. nautobot/extras/factory.py +19 -20
  80. nautobot/extras/filters/__init__.py +3 -2
  81. nautobot/extras/filters/mixins.py +23 -7
  82. nautobot/extras/forms/__init__.py +2 -1
  83. nautobot/extras/forms/forms.py +71 -0
  84. nautobot/extras/forms/mixins.py +4 -2
  85. nautobot/extras/managers.py +4 -1
  86. nautobot/extras/migrations/0062_collect_roles_from_related_apps_roles.py +30 -7
  87. nautobot/extras/migrations/0124_add_joblogentry_index.py +16 -0
  88. nautobot/extras/migrations/0125_jobresult_date_started.py +18 -0
  89. nautobot/extras/models/customfields.py +53 -5
  90. nautobot/extras/models/datasources.py +1 -2
  91. nautobot/extras/models/jobs.py +13 -3
  92. nautobot/extras/models/relationships.py +55 -6
  93. nautobot/extras/plugins/views.py +24 -1
  94. nautobot/extras/secrets/__init__.py +1 -1
  95. nautobot/extras/tables.py +9 -0
  96. nautobot/extras/templates/extras/customfield.html +2 -129
  97. nautobot/extras/templates/extras/customfield_edit.html +2 -108
  98. nautobot/extras/templates/extras/customfield_retrieve.html +129 -0
  99. nautobot/extras/templates/extras/customfield_update.html +108 -0
  100. nautobot/extras/templates/extras/graphqlquery.html +2 -97
  101. nautobot/extras/templates/extras/graphqlquery_list.html +1 -0
  102. nautobot/extras/templates/extras/graphqlquery_retrieve.html +97 -0
  103. nautobot/extras/templates/extras/inc/jobresult.html +7 -3
  104. nautobot/extras/templates/extras/jobresult.html +2 -155
  105. nautobot/extras/templates/extras/jobresult_retrieve.html +155 -0
  106. nautobot/extras/templates/extras/marketplace.html +5 -6
  107. nautobot/extras/templates/extras/note.html +2 -53
  108. nautobot/extras/templates/extras/note_retrieve.html +53 -0
  109. nautobot/extras/templates/extras/plugins_list.html +5 -6
  110. nautobot/extras/templates/extras/secretsgroup.html +2 -29
  111. nautobot/extras/templates/extras/secretsgroup_edit.html +2 -82
  112. nautobot/extras/templates/extras/secretsgroup_retrieve.html +29 -0
  113. nautobot/extras/templates/extras/secretsgroup_update.html +82 -0
  114. nautobot/extras/templatetags/custom_links.py +2 -2
  115. nautobot/extras/templatetags/job_buttons.py +1 -1
  116. nautobot/extras/templatetags/plugins.py +1 -1
  117. nautobot/extras/tests/integration/test_computedfields.py +2 -2
  118. nautobot/extras/tests/integration/test_customfields.py +14 -11
  119. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  120. nautobot/extras/tests/integration/test_notes.py +1 -1
  121. nautobot/extras/tests/integration/test_plugins.py +6 -6
  122. nautobot/extras/tests/integration/test_relationships.py +2 -2
  123. nautobot/extras/tests/test_customfields.py +115 -7
  124. nautobot/extras/tests/test_filters.py +9 -0
  125. nautobot/extras/tests/test_forms.py +2 -2
  126. nautobot/extras/tests/test_plugins.py +2 -3
  127. nautobot/extras/tests/test_relationships.py +14 -8
  128. nautobot/extras/tests/test_views.py +285 -2
  129. nautobot/extras/urls.py +5 -110
  130. nautobot/extras/utils.py +5 -2
  131. nautobot/extras/views.py +116 -311
  132. nautobot/ipam/api/views.py +69 -6
  133. nautobot/ipam/tables.py +8 -15
  134. nautobot/ipam/tests/migration/test_migrations.py +8 -8
  135. nautobot/ipam/tests/test_api.py +352 -2
  136. nautobot/ipam/tests/test_models.py +1 -1
  137. nautobot/project-static/docs/404.html +34 -34
  138. nautobot/project-static/docs/apps/index.html +34 -34
  139. nautobot/project-static/docs/apps/nautobot-apps.html +34 -34
  140. nautobot/project-static/docs/assets/_mkdocstrings.css +44 -6
  141. nautobot/project-static/docs/assets/javascripts/{bundle.56ea9cef.min.js → bundle.50899def.min.js} +2 -2
  142. nautobot/project-static/docs/assets/javascripts/{bundle.56ea9cef.min.js.map → bundle.50899def.min.js.map} +2 -2
  143. nautobot/project-static/docs/assets/stylesheets/{main.342714a4.min.css → main.7e37652d.min.css} +1 -1
  144. nautobot/project-static/docs/assets/stylesheets/{main.342714a4.min.css.map → main.7e37652d.min.css.map} +1 -1
  145. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +39 -34
  146. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +36 -34
  147. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +139 -54
  148. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +48 -38
  149. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +50 -40
  150. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +36 -34
  151. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +35 -34
  152. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +43 -39
  153. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +52 -42
  154. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +50 -41
  155. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +54 -44
  156. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +85 -93
  157. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +154 -62
  158. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +54 -46
  159. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +146 -87
  160. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +240 -70
  161. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +38 -35
  162. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +41 -35
  163. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +173 -52
  164. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +269 -85
  165. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +5987 -2643
  166. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +36 -34
  167. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +165 -89
  168. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +161 -69
  169. nautobot/project-static/docs/development/apps/api/configuration-view.html +34 -34
  170. nautobot/project-static/docs/development/apps/api/database-backend-config.html +34 -34
  171. nautobot/project-static/docs/development/apps/api/models/django-admin.html +34 -34
  172. nautobot/project-static/docs/development/apps/api/models/global-search.html +34 -34
  173. nautobot/project-static/docs/development/apps/api/models/graphql.html +34 -34
  174. nautobot/project-static/docs/development/apps/api/models/index.html +34 -34
  175. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +34 -34
  176. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +34 -34
  177. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +34 -34
  178. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +34 -34
  179. nautobot/project-static/docs/development/apps/api/platform-features/index.html +34 -34
  180. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +34 -34
  181. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +34 -34
  182. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +34 -34
  183. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +34 -34
  184. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +34 -34
  185. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +34 -34
  186. nautobot/project-static/docs/development/apps/api/prometheus.html +34 -34
  187. nautobot/project-static/docs/development/apps/api/setup.html +34 -34
  188. nautobot/project-static/docs/development/apps/api/testing.html +34 -34
  189. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +34 -34
  190. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +34 -34
  191. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +34 -34
  192. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +34 -34
  193. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +34 -34
  194. nautobot/project-static/docs/development/apps/api/views/base-template.html +34 -34
  195. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +34 -34
  196. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +34 -34
  197. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +34 -34
  198. nautobot/project-static/docs/development/apps/api/views/index.html +34 -34
  199. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +34 -34
  200. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +42 -36
  201. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +34 -34
  202. nautobot/project-static/docs/development/apps/api/views/notes.html +34 -34
  203. nautobot/project-static/docs/development/apps/api/views/rest-api.html +34 -34
  204. nautobot/project-static/docs/development/apps/api/views/urls.html +34 -34
  205. nautobot/project-static/docs/development/apps/index.html +34 -34
  206. nautobot/project-static/docs/development/apps/migration/code-updates.html +34 -34
  207. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +34 -34
  208. nautobot/project-static/docs/development/apps/migration/from-v1.html +34 -34
  209. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +34 -34
  210. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +34 -34
  211. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +34 -34
  212. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +34 -34
  213. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +37 -37
  214. nautobot/project-static/docs/development/apps/migration/ui-component-framework/breadcrumbs-titles.html +10544 -0
  215. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +34 -34
  216. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +34 -34
  217. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +34 -34
  218. nautobot/project-static/docs/development/apps/porting-from-netbox.html +37 -37
  219. nautobot/project-static/docs/development/core/application-registry.html +162 -133
  220. nautobot/project-static/docs/development/core/best-practices.html +34 -34
  221. nautobot/project-static/docs/development/core/bootstrap-ui.html +34 -34
  222. nautobot/project-static/docs/development/core/caching.html +34 -34
  223. nautobot/project-static/docs/development/core/controllers.html +34 -34
  224. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +34 -34
  225. nautobot/project-static/docs/development/core/generic-views.html +34 -34
  226. nautobot/project-static/docs/development/core/getting-started.html +34 -34
  227. nautobot/project-static/docs/development/core/homepage.html +34 -34
  228. nautobot/project-static/docs/development/core/index.html +34 -34
  229. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +34 -34
  230. nautobot/project-static/docs/development/core/model-checklist.html +34 -34
  231. nautobot/project-static/docs/development/core/model-features.html +34 -34
  232. nautobot/project-static/docs/development/core/natural-keys.html +34 -34
  233. nautobot/project-static/docs/development/core/navigation-menu.html +34 -34
  234. nautobot/project-static/docs/development/core/release-checklist.html +34 -34
  235. nautobot/project-static/docs/development/core/role-internals.html +34 -34
  236. nautobot/project-static/docs/development/core/settings.html +34 -34
  237. nautobot/project-static/docs/development/core/style-guide.html +34 -34
  238. nautobot/project-static/docs/development/core/templates.html +34 -34
  239. nautobot/project-static/docs/development/core/testing.html +34 -34
  240. nautobot/project-static/docs/development/core/ui-component-framework.html +724 -289
  241. nautobot/project-static/docs/development/core/user-preferences.html +34 -34
  242. nautobot/project-static/docs/development/index.html +34 -34
  243. nautobot/project-static/docs/development/jobs/getting-started.html +34 -34
  244. nautobot/project-static/docs/development/jobs/index.html +34 -34
  245. nautobot/project-static/docs/development/jobs/installation.html +34 -34
  246. nautobot/project-static/docs/development/jobs/job-extensions.html +34 -34
  247. nautobot/project-static/docs/development/jobs/job-logging.html +34 -34
  248. nautobot/project-static/docs/development/jobs/job-patterns.html +34 -34
  249. nautobot/project-static/docs/development/jobs/job-structure.html +34 -34
  250. nautobot/project-static/docs/development/jobs/migration/from-v1.html +34 -34
  251. nautobot/project-static/docs/development/jobs/testing.html +34 -34
  252. nautobot/project-static/docs/index.html +34 -34
  253. nautobot/project-static/docs/media/development/core/ui-component-framework/breadcrumbs-titles-data-flow.png +0 -0
  254. nautobot/project-static/docs/media/power_distribution.png +0 -0
  255. nautobot/project-static/docs/objects.inv +0 -0
  256. nautobot/project-static/docs/overview/application_stack.html +34 -34
  257. nautobot/project-static/docs/overview/design_philosophy.html +34 -34
  258. nautobot/project-static/docs/release-notes/index.html +34 -34
  259. nautobot/project-static/docs/release-notes/version-1.0.html +34 -34
  260. nautobot/project-static/docs/release-notes/version-1.1.html +34 -34
  261. nautobot/project-static/docs/release-notes/version-1.2.html +34 -34
  262. nautobot/project-static/docs/release-notes/version-1.3.html +34 -34
  263. nautobot/project-static/docs/release-notes/version-1.4.html +34 -34
  264. nautobot/project-static/docs/release-notes/version-1.5.html +34 -34
  265. nautobot/project-static/docs/release-notes/version-1.6.html +34 -34
  266. nautobot/project-static/docs/release-notes/version-2.0.html +34 -34
  267. nautobot/project-static/docs/release-notes/version-2.1.html +34 -34
  268. nautobot/project-static/docs/release-notes/version-2.2.html +34 -34
  269. nautobot/project-static/docs/release-notes/version-2.3.html +34 -34
  270. nautobot/project-static/docs/release-notes/version-2.4.html +402 -34
  271. nautobot/project-static/docs/requirements.txt +3 -3
  272. nautobot/project-static/docs/search/search_index.json +1 -1
  273. nautobot/project-static/docs/sitemap.xml +303 -299
  274. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  275. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +34 -34
  276. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +34 -34
  277. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +34 -34
  278. nautobot/project-static/docs/user-guide/administration/configuration/index.html +34 -34
  279. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +34 -34
  280. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +37 -37
  281. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +34 -34
  282. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +34 -34
  283. nautobot/project-static/docs/user-guide/administration/guides/docker.html +34 -34
  284. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +34 -34
  285. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +34 -34
  286. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +34 -34
  287. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +34 -34
  288. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +34 -34
  289. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +34 -34
  290. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +34 -34
  291. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +34 -34
  292. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +34 -34
  293. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +34 -34
  294. nautobot/project-static/docs/user-guide/administration/installation/index.html +34 -34
  295. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +34 -34
  296. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +34 -34
  297. nautobot/project-static/docs/user-guide/administration/installation/services.html +34 -34
  298. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +34 -34
  299. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +34 -34
  300. nautobot/project-static/docs/user-guide/administration/security/index.html +34 -34
  301. nautobot/project-static/docs/user-guide/administration/security/notices.html +34 -34
  302. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +296 -251
  303. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +34 -34
  304. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +34 -34
  305. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +34 -34
  306. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +34 -34
  307. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +34 -34
  308. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +34 -34
  309. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +34 -34
  310. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +34 -34
  311. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +34 -34
  312. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +34 -34
  313. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +34 -34
  314. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +34 -34
  315. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +34 -34
  316. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +34 -34
  317. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +34 -34
  318. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +34 -34
  319. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +34 -34
  320. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +34 -34
  321. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +34 -34
  322. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +34 -34
  323. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +34 -34
  324. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +34 -34
  325. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +34 -34
  326. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +34 -34
  327. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +34 -34
  328. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +34 -34
  329. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +34 -34
  330. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +34 -34
  331. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +34 -34
  332. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +34 -34
  333. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +34 -34
  334. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +34 -34
  335. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +34 -34
  336. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +34 -34
  337. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +34 -34
  338. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +34 -34
  339. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +34 -34
  340. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +37 -37
  341. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +34 -34
  342. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +34 -34
  343. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +42 -52
  344. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +34 -34
  345. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +34 -34
  346. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +34 -34
  347. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +34 -34
  348. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +37 -37
  349. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +34 -34
  350. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +34 -34
  351. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +34 -34
  352. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +34 -34
  353. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +316 -39
  354. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +35 -35
  355. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +34 -34
  356. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +147 -37
  357. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +52 -35
  358. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +51 -34
  359. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +34 -34
  360. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +34 -34
  361. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +34 -34
  362. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +34 -34
  363. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +34 -34
  364. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +34 -34
  365. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +34 -34
  366. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +34 -34
  367. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +34 -34
  368. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +34 -34
  369. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +34 -34
  370. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +34 -34
  371. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +34 -34
  372. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +34 -34
  373. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +34 -34
  374. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +34 -34
  375. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +34 -34
  376. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +34 -34
  377. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +34 -34
  378. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +34 -34
  379. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +34 -34
  380. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +34 -34
  381. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +34 -34
  382. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +34 -34
  383. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +34 -34
  384. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +34 -34
  385. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +34 -34
  386. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +34 -34
  387. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +34 -34
  388. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +34 -34
  389. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +34 -34
  390. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +34 -34
  391. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +34 -34
  392. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +34 -34
  393. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +34 -34
  394. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +34 -34
  395. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +34 -34
  396. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +34 -34
  397. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +34 -34
  398. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +34 -34
  399. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +34 -34
  400. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +34 -34
  401. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +34 -34
  402. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +34 -34
  403. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +34 -34
  404. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +34 -34
  405. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +34 -34
  406. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +34 -34
  407. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +34 -34
  408. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +34 -34
  409. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +34 -34
  410. nautobot/project-static/docs/user-guide/index.html +34 -34
  411. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +34 -34
  412. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +34 -34
  413. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +34 -34
  414. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +34 -34
  415. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +34 -34
  416. nautobot/project-static/docs/user-guide/platform-functionality/events.html +34 -34
  417. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +34 -34
  418. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +34 -34
  419. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +34 -34
  420. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +34 -34
  421. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +34 -34
  422. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +34 -34
  423. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +34 -34
  424. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +35 -35
  425. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +34 -34
  426. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +34 -34
  427. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +34 -34
  428. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +34 -34
  429. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +34 -34
  430. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +34 -34
  431. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +34 -34
  432. nautobot/project-static/docs/user-guide/platform-functionality/note.html +34 -34
  433. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +34 -34
  434. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +34 -34
  435. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +34 -34
  436. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +34 -34
  437. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +34 -34
  438. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +34 -34
  439. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +34 -34
  440. nautobot/project-static/docs/user-guide/platform-functionality/role.html +34 -34
  441. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +34 -34
  442. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +34 -34
  443. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +34 -34
  444. nautobot/project-static/docs/user-guide/platform-functionality/status.html +34 -34
  445. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +34 -34
  446. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +34 -34
  447. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +34 -34
  448. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +34 -34
  449. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +34 -34
  450. nautobot/tenancy/api/views.py +2 -1
  451. nautobot/users/tests/test_api.py +2 -2
  452. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -252
  453. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -75
  454. nautobot/virtualization/templates/virtualization/virtualmachine_retrieve.html +252 -0
  455. nautobot/virtualization/templates/virtualization/virtualmachine_update.html +75 -0
  456. nautobot/virtualization/urls.py +3 -61
  457. nautobot/virtualization/views.py +48 -72
  458. {nautobot-2.4.13.dist-info → nautobot-2.4.15.dist-info}/METADATA +27 -27
  459. {nautobot-2.4.13.dist-info → nautobot-2.4.15.dist-info}/RECORD +463 -439
  460. {nautobot-2.4.13.dist-info → nautobot-2.4.15.dist-info}/LICENSE.txt +0 -0
  461. {nautobot-2.4.13.dist-info → nautobot-2.4.15.dist-info}/NOTICE +0 -0
  462. {nautobot-2.4.13.dist-info → nautobot-2.4.15.dist-info}/WHEEL +0 -0
  463. {nautobot-2.4.13.dist-info → nautobot-2.4.15.dist-info}/entry_points.txt +0 -0
nautobot/apps/choices.py CHANGED
@@ -18,11 +18,15 @@ from nautobot.dcim.choices import (
18
18
  InterfaceRedundancyGroupProtocolChoices,
19
19
  InterfaceTypeChoices,
20
20
  PortTypeChoices,
21
+ PowerFeedBreakerPoleChoices,
21
22
  PowerFeedPhaseChoices,
23
+ PowerFeedStatusChoices,
22
24
  PowerFeedSupplyChoices,
23
25
  PowerFeedTypeChoices,
24
26
  PowerOutletFeedLegChoices,
25
27
  PowerOutletTypeChoices,
28
+ PowerPanelTypeChoices,
29
+ PowerPathChoices,
26
30
  PowerPortTypeChoices,
27
31
  RackDimensionUnitChoices,
28
32
  RackElevationDetailRenderChoices,
@@ -89,11 +93,15 @@ __all__ = (
89
93
  "ObjectChangeActionChoices",
90
94
  "ObjectChangeEventContextChoices",
91
95
  "PortTypeChoices",
96
+ "PowerFeedBreakerPoleChoices",
92
97
  "PowerFeedPhaseChoices",
98
+ "PowerFeedStatusChoices",
93
99
  "PowerFeedSupplyChoices",
94
100
  "PowerFeedTypeChoices",
95
101
  "PowerOutletFeedLegChoices",
96
102
  "PowerOutletTypeChoices",
103
+ "PowerPanelTypeChoices",
104
+ "PowerPathChoices",
97
105
  "PowerPortTypeChoices",
98
106
  "PrefixTypeChoices",
99
107
  "RackDimensionUnitChoices",
nautobot/apps/ui.py CHANGED
@@ -2,6 +2,13 @@
2
2
 
3
3
  from nautobot.core.choices import ButtonColorChoices
4
4
  from nautobot.core.ui.base import PermissionsMixin
5
+ from nautobot.core.ui.breadcrumbs import (
6
+ BaseBreadcrumbItem,
7
+ Breadcrumbs,
8
+ InstanceBreadcrumbItem,
9
+ ModelBreadcrumbItem,
10
+ ViewNameBreadcrumbItem,
11
+ )
5
12
  from nautobot.core.ui.choices import LayoutChoices, SectionChoices
6
13
  from nautobot.core.ui.homepage import (
7
14
  HomePageBase,
@@ -36,6 +43,7 @@ from nautobot.core.ui.object_detail import (
36
43
  Tab,
37
44
  TextPanel,
38
45
  )
46
+ from nautobot.core.ui.titles import Titles
39
47
  from nautobot.core.ui.utils import render_component_template
40
48
  from nautobot.extras.choices import BannerClassChoices
41
49
  from nautobot.extras.plugins import Banner, TemplateExtension
@@ -43,7 +51,9 @@ from nautobot.extras.plugins import Banner, TemplateExtension
43
51
  __all__ = (
44
52
  "Banner",
45
53
  "BannerClassChoices",
54
+ "BaseBreadcrumbItem",
46
55
  "BaseTextPanel",
56
+ "Breadcrumbs",
47
57
  "Button",
48
58
  "ButtonColorChoices",
49
59
  "Component",
@@ -55,8 +65,10 @@ __all__ = (
55
65
  "HomePageGroup",
56
66
  "HomePageItem",
57
67
  "HomePagePanel",
68
+ "InstanceBreadcrumbItem",
58
69
  "KeyValueTablePanel",
59
70
  "LayoutChoices",
71
+ "ModelBreadcrumbItem",
60
72
  "NavMenuAddButton",
61
73
  "NavMenuBase",
62
74
  "NavMenuButton",
@@ -75,5 +87,7 @@ __all__ = (
75
87
  "Tab",
76
88
  "TemplateExtension",
77
89
  "TextPanel",
90
+ "Titles",
91
+ "ViewNameBreadcrumbItem",
78
92
  "render_component_template",
79
93
  )
@@ -519,6 +519,8 @@ class StatusView(NautobotAPIVersionMixin, APIView):
519
519
  if version:
520
520
  if isinstance(version, tuple):
521
521
  version = ".".join(str(n) for n in version)
522
+ else:
523
+ version = str(version)
522
524
  installed_apps[app_config.name] = version
523
525
  installed_apps = dict(sorted(installed_apps.items()))
524
526
 
nautobot/core/choices.py CHANGED
@@ -194,6 +194,7 @@ class ButtonActionColorChoices(ChoiceSet):
194
194
  EXPORT = "success"
195
195
  IMPORT = "primary"
196
196
  INFO = "info"
197
+ RENAME = "warning"
197
198
  SUBMIT = "primary"
198
199
  SWAP = "primary"
199
200
 
@@ -210,6 +211,7 @@ class ButtonActionColorChoices(ChoiceSet):
210
211
  (EXPORT, "Export"),
211
212
  (IMPORT, "Import"),
212
213
  (INFO, "Info"),
214
+ (RENAME, "Rename"),
213
215
  (SUBMIT, "Submit"),
214
216
  (SWAP, "Swap"),
215
217
  )
@@ -236,6 +238,7 @@ class ButtonActionIconChoices(ChoiceSet):
236
238
  LOCK = "mdi-lock"
237
239
  MAGNIFY = "mdi-magnify"
238
240
  NOTE = "mdi-note-text"
241
+ RENAME = "mdi-pencil"
239
242
  SWAP = "mdi-swap-vertical"
240
243
  TRASH = "mdi-trash-can-outline"
241
244
 
@@ -256,6 +259,7 @@ class ButtonActionIconChoices(ChoiceSet):
256
259
  (LOCK, "Lock"),
257
260
  (MAGNIFY, "Magnify"),
258
261
  (NOTE, "Note"),
262
+ (RENAME, "Rename"),
259
263
  (SWAP, "Swap"),
260
264
  (TRASH, "Trash"),
261
265
  )
nautobot/core/filters.py CHANGED
@@ -209,14 +209,12 @@ class ContentTypeFilterMixin:
209
209
  return qs
210
210
 
211
211
  if value.isdigit():
212
- return qs.filter(**{f"{self.field_name}__pk": value})
213
-
212
+ return self.get_method(qs)(**{f"{self.field_name}__pk": value})
214
213
  try:
215
214
  app_label, model = value.lower().split(".")
216
215
  except ValueError:
217
216
  return qs.none()
218
-
219
- return qs.filter(
217
+ return self.get_method(qs)(
220
218
  **{
221
219
  f"{self.field_name}__app_label": app_label,
222
220
  f"{self.field_name}__model": model,
@@ -244,6 +242,8 @@ class ContentTypeChoiceFilter(ContentTypeFilterMixin, django_filters.ChoiceFilte
244
242
  content_type = ContentTypeChoiceFilter(
245
243
  choices=FeatureQuery("dynamic_groups").get_choices,
246
244
  )
245
+
246
+ In most cases you should use `ContentTypeMultipleChoiceFilter` instead.
247
247
  """
248
248
 
249
249
 
@@ -251,6 +251,9 @@ class ContentTypeMultipleChoiceFilter(django_filters.MultipleChoiceFilter):
251
251
  """
252
252
  Allows multiple-choice ContentType filtering by <app_label>.<model> (e.g. "dcim.location").
253
253
 
254
+ Does NOT allow filtering by PK at this time; it would need to be reimplemented similar to
255
+ NaturalKeyOrPKMultipleChoiceFilter as a breaking change.
256
+
254
257
  Defaults to joining multiple options with "AND". Pass `conjoined=False` to
255
258
  override this behavior to join with "OR" instead.
256
259
 
@@ -265,43 +268,14 @@ class ContentTypeMultipleChoiceFilter(django_filters.MultipleChoiceFilter):
265
268
  kwargs.setdefault("conjoined", True)
266
269
  super().__init__(*args, **kwargs)
267
270
 
268
- def filter(self, qs, value):
269
- """Filter on value, which should be list of content-type names.
270
-
271
- e.g. `['dcim.device', 'dcim.rack']`
272
- """
273
- if not self.conjoined:
274
- q = models.Q()
275
-
276
- for v in value:
277
- if self.conjoined:
278
- qs = ContentTypeFilter.filter(self, qs, v)
279
- else:
280
- if v.isdigit():
281
- q |= models.Q(**{f"{self.field_name}__pk": value})
282
- continue
283
- # Similar to the ContentTypeFilter.filter() call above, but instead of narrowing the query each time
284
- # (a AND b AND c ...) we broaden the query each time (a OR b OR c ...).
285
- # Specifically, we're mapping a value like ['dcim.device', 'ipam.vlan'] to a query like
286
- # Q((field__app_label="dcim" AND field__model="device") OR (field__app_label="ipam" AND field__model="VLAN"))
287
- try:
288
- app_label, model = v.lower().split(".")
289
- except ValueError:
290
- continue
291
- q |= models.Q(
292
- **{
293
- f"{self.field_name}__app_label": app_label,
294
- f"{self.field_name}__model": model,
295
- }
296
- )
297
-
298
- if not self.conjoined:
299
- qs = qs.filter(q)
300
-
301
- if self.distinct:
302
- qs = qs.distinct()
303
-
304
- return qs
271
+ def get_filter_predicate(self, v):
272
+ if v.isdigit():
273
+ return {f"{self.field_name}__pk": v}
274
+ try:
275
+ app_label, model = v.lower().split(".")
276
+ except ValueError:
277
+ return {f"{self.field_name}__pk": v}
278
+ return {f"{self.field_name}__app_label": app_label, f"{self.field_name}__model": model}
305
279
 
306
280
 
307
281
  class MappedPredicatesFilterMixin:
@@ -642,6 +616,9 @@ class BaseFilterSet(django_filters.FilterSet):
642
616
  (
643
617
  django_filters.ModelChoiceFilter,
644
618
  django_filters.ModelMultipleChoiceFilter,
619
+ ContentTypeFilter,
620
+ ContentTypeChoiceFilter,
621
+ ContentTypeMultipleChoiceFilter,
645
622
  MultiValueUUIDFilter,
646
623
  TagFilter,
647
624
  TreeNodeMultipleChoiceFilter,
@@ -820,6 +797,7 @@ class BaseFilterSet(django_filters.FilterSet):
820
797
  to_field_name="name",
821
798
  label="Contacts (name or ID)",
822
799
  )
800
+ cls.declared_filters["contacts"] = filters["contacts"] # pylint: disable=no-member
823
801
 
824
802
  if "teams" not in filters:
825
803
  filters["teams"] = NaturalKeyOrPKMultipleChoiceFilter(
@@ -828,6 +806,7 @@ class BaseFilterSet(django_filters.FilterSet):
828
806
  to_field_name="name",
829
807
  label="Teams (name or ID)",
830
808
  )
809
+ cls.declared_filters["teams"] = filters["teams"] # pylint: disable=no-member
831
810
 
832
811
  if "dynamic_groups" not in filters and getattr(cls._meta.model, "is_dynamic_group_associable_model", False): # pylint: disable=no-member
833
812
  if not hasattr(cls._meta.model, "static_group_association_set"): # pylint: disable=no-member
@@ -848,6 +827,7 @@ class BaseFilterSet(django_filters.FilterSet):
848
827
  query_params={"content_type": cls._meta.model._meta.label_lower}, # pylint: disable=no-member
849
828
  label="Dynamic groups (name or ID)",
850
829
  )
830
+ cls.declared_filters["dynamic_groups"] = filters["dynamic_groups"] # pylint: disable=no-member
851
831
 
852
832
  # django-filters has no concept of "abstract" filtersets, so we have to fake it
853
833
  if cls._meta.model is not None: # pylint: disable=no-member
@@ -16,6 +16,9 @@ logger = logging.getLogger(__name__)
16
16
  RESOLVER_PREFIX = "resolve_"
17
17
 
18
18
 
19
+ LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE = {}
20
+
21
+
19
22
  def generate_restricted_queryset():
20
23
  """
21
24
  Generate a function to return a restricted queryset compatible with the internal permissions system.
@@ -248,6 +251,9 @@ def generate_schema_type(app_name: str, model: object) -> OptimizedNautobotObjec
248
251
  def generate_list_search_parameters(schema_type):
249
252
  """Generate list of query parameters for the list resolver based on a filterset."""
250
253
 
254
+ if schema_type in LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE:
255
+ return LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE[schema_type]
256
+
251
257
  search_params = {
252
258
  "limit": graphene.Int(),
253
259
  "offset": graphene.Int(),
@@ -259,6 +265,8 @@ def generate_list_search_parameters(schema_type):
259
265
  )
260
266
  )
261
267
 
268
+ LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE[schema_type] = search_params
269
+
262
270
  return search_params
263
271
 
264
272
 
@@ -243,12 +243,12 @@ def extend_schema_type_custom_field(schema_type, model):
243
243
  (DjangoObjectType): The extended schema_type object
244
244
  """
245
245
 
246
- cfs = CustomField.objects.get_for_model(model)
246
+ custom_fields = CustomField.objects.get_for_model(model, get_queryset=False)
247
247
  prefix = ""
248
248
  if settings.GRAPHQL_CUSTOM_FIELD_PREFIX and isinstance(settings.GRAPHQL_CUSTOM_FIELD_PREFIX, str):
249
249
  prefix = f"{settings.GRAPHQL_CUSTOM_FIELD_PREFIX}_"
250
250
 
251
- for field in cfs:
251
+ for field in custom_fields:
252
252
  # Since we guaranteed cf.key's uniqueness in CustomField data migration
253
253
  # We can safely field_key this in our GraphQL without duplication
254
254
  # For new CustomField instances, we also make sure that duplicate key does not exist.
@@ -281,6 +281,7 @@ def extend_schema_type_custom_field(schema_type, model):
281
281
 
282
282
  def extend_schema_type_computed_field(schema_type, model):
283
283
  """Extend schema_type object to had attribute and resolver around computed_fields.
284
+
284
285
  Each computed field will be defined as a first level attribute.
285
286
 
286
287
  Args:
@@ -291,12 +292,12 @@ def extend_schema_type_computed_field(schema_type, model):
291
292
  (DjangoObjectType): The extended schema_type object
292
293
  """
293
294
 
294
- cfs = ComputedField.objects.get_for_model(model)
295
+ computed_fields = ComputedField.objects.get_for_model(model, get_queryset=False)
295
296
  prefix = ""
296
297
  if settings.GRAPHQL_COMPUTED_FIELD_PREFIX and isinstance(settings.GRAPHQL_COMPUTED_FIELD_PREFIX, str):
297
298
  prefix = f"{settings.GRAPHQL_COMPUTED_FIELD_PREFIX}_"
298
299
 
299
- for field in cfs:
300
+ for field in computed_fields:
300
301
  field_name = f"{prefix}{field.key}"
301
302
  try:
302
303
  check_if_key_is_graphql_safe("Computed Field", field.key)
@@ -396,12 +397,16 @@ def extend_schema_type_global_features(schema_type, model):
396
397
 
397
398
 
398
399
  def extend_schema_type_relationships(schema_type, model):
399
- """Extend the schema type with attributes and resolvers corresponding
400
- to the relationships associated with this model."""
400
+ """
401
+ Extend the schema type with attributes and resolvers for the relationships associated with this model.
401
402
 
403
+ Args:
404
+ schema_type (DjangoObjectType): GraphQL Object type for a given model
405
+ model (Model): Django model
406
+ """
402
407
  relationships_by_side = {
403
- "source": Relationship.objects.get_for_model_source(model),
404
- "destination": Relationship.objects.get_for_model_destination(model),
408
+ "source": Relationship.objects.get_for_model_source(model, get_queryset=False),
409
+ "destination": Relationship.objects.get_for_model_destination(model, get_queryset=False),
405
410
  }
406
411
 
407
412
  prefix = ""
@@ -499,30 +504,16 @@ def generate_query_mixin():
499
504
 
500
505
  logger.debug("Generating dynamic schemas for all models in the models_features graphql registry")
501
506
  # - Ensure an attribute/schematype with the same name doesn't already exist
502
- registered_models = registry.get("model_features", {}).get("graphql", {})
503
- for app_name, models in registered_models.items():
504
- for model_name in models:
505
- try:
506
- # Find the model class based on the content type
507
- ct = ContentType.objects.get(app_label=app_name, model=model_name)
508
- model = ct.model_class()
509
- except ContentType.DoesNotExist:
510
- logger.warning(
511
- 'Unable to generate a schema type for the model "%s.%s" in GraphQL, '
512
- "as this model doesn't have an associated ContentType. Please create the Object manually.",
513
- app_name,
514
- model_name,
515
- )
516
- continue
507
+ registered_models = registry.get("feature_models", {}).get("graphql", [])
508
+ for model in registered_models:
509
+ type_identifier = model._meta.label_lower
517
510
 
518
- type_identifier = f"{app_name}.{model_name}"
519
-
520
- if type_identifier in registry["graphql_types"].keys():
521
- # Skip models that have been added statically
522
- continue
511
+ if type_identifier in registry["graphql_types"].keys():
512
+ # Skip models that have been added statically
513
+ continue
523
514
 
524
- schema_type = generate_schema_type(app_name=app_name, model=model)
525
- registry["graphql_types"][type_identifier] = schema_type
515
+ schema_type = generate_schema_type(app_name=model._meta.app_label, model=model)
516
+ registry["graphql_types"][type_identifier] = schema_type
526
517
 
527
518
  logger.debug("Adding plugins' statically defined graphql schema types")
528
519
  # After checking for conflict
@@ -542,6 +533,15 @@ def generate_query_mixin():
542
533
  registry["graphql_types"][type_identifier] = schema_type
543
534
 
544
535
  logger.debug("Extending all registered schema types with dynamic attributes")
536
+
537
+ # Precache all content-types as we'll need them for filtering and the like
538
+ for content_type in ContentType.objects.all():
539
+ ContentType.objects._add_to_cache(ContentType.objects.db, content_type)
540
+
541
+ CustomField.objects.populate_list_caches()
542
+ ComputedField.objects.populate_list_caches()
543
+ Relationship.objects.populate_list_caches()
544
+
545
545
  for schema_type in registry["graphql_types"].values():
546
546
  if already_present(schema_type._meta.model):
547
547
  continue
@@ -0,0 +1,47 @@
1
+ from django.core.exceptions import ValidationError
2
+ from django.core.management.base import BaseCommand
3
+
4
+ from nautobot.extras.models import Job, ScheduledJob
5
+
6
+
7
+ class ApprovalRequiredScheduledJobsError(ValidationError):
8
+ """Raised when scheduled jobs requiring approval are found during managment command."""
9
+
10
+ def __init__(self, message_lines):
11
+ self.message_lines = message_lines
12
+ super().__init__(message_lines)
13
+
14
+ def __str__(self):
15
+ return "\n".join(self.message_lines)
16
+
17
+
18
+ class Command(BaseCommand):
19
+ help = "Checks for scheduled jobs and jobs that require approval."
20
+
21
+ def handle(self, *args, **options):
22
+ approval_required_scheduled_jobs = ScheduledJob.objects.filter(approval_required=True).values_list("id", "name")
23
+
24
+ if approval_required_scheduled_jobs:
25
+ message_lines = [
26
+ "These need to be approved (and run) or denied before upgrading to Nautobot v3, as the introduction of the approval workflows feature means that future scheduled-job approvals will be handled differently.",
27
+ "Refer to the documentation: https://docs.nautobot.com/projects/core/en/v2.4.14/user-guide/platform-functionality/jobs/job-scheduling-and-approvals/#approval-via-the-ui",
28
+ "Below is a list of affected scheduled jobs:",
29
+ ]
30
+ for schedule_job_id, scheduled_job_name in approval_required_scheduled_jobs:
31
+ message_lines.append(f" - ID: {schedule_job_id}, Name: {scheduled_job_name}")
32
+ raise ApprovalRequiredScheduledJobsError(message_lines)
33
+
34
+ approval_required_jobs = Job.objects.filter(approval_required=True).values_list("name", flat=True)
35
+ if approval_required_jobs:
36
+ message_lines = [
37
+ "Following jobs still have `approval_required=True`.",
38
+ "These jobs will no longer trigger approval automatically.",
39
+ "After upgrading to Nautobot 3.x, you should add an approval workflow definition(s) covering these jobs.",
40
+ "Refer to the documentation: https://docs.nautobot.com/projects/core/en/v3.0.0/user-guide/platform-functionality/approval-workflow/",
41
+ "Affected jobs (Names):",
42
+ ]
43
+ for job_name in approval_required_jobs:
44
+ message_lines.append(f" - {job_name}")
45
+ else:
46
+ message_lines = ["No approval_required jobs or scheduled jobs found."]
47
+ self.stdout.write("\n".join(message_lines))
@@ -375,7 +375,7 @@ class Command(BaseCommand):
375
375
  confirm = input(
376
376
  f"""\
377
377
  You have requested a flush of the database before generating new data.
378
- This will IRREVERSIBLY DESTROY all data in the "{connections[options['database']].settings_dict['NAME']}" database,
378
+ This will IRREVERSIBLY DESTROY all data in the "{connections[options["database"]].settings_dict["NAME"]}" database,
379
379
  including all user accounts, and return each table to an empty state.
380
380
  Are you SURE you want to do this?
381
381
 
@@ -1,8 +1,97 @@
1
1
  # noinspection PyUnresolvedReferences
2
- from django.core.management.commands.migrate import Command # noqa: F401 # unused-import
2
+ import contextlib
3
+ import time
4
+
5
+ from django.apps import apps
6
+ from django.core.management.commands.migrate import Command as _Command
3
7
  from django.db import models
8
+ from django.db.migrations.operations.fields import FieldOperation
9
+ from django.db.migrations.operations.models import ModelOperation
4
10
 
5
11
  from nautobot.core.management import commands
6
12
 
7
13
  # Overload deconstruct with our own.
8
14
  models.Field.deconstruct = commands.custom_deconstruct
15
+
16
+
17
+ class Command(_Command):
18
+ def migration_progress_callback(self, action, migration=None, fake=False):
19
+ """
20
+ Enhanced version of Django's built-in callback.
21
+
22
+ Differences in behavior:
23
+ - Measures and reports elapsed time whenever verbosity >= 1 (default value)
24
+ - Measures and reports affected record counts and elapsed time per record where applicable at verbosity >= 2.
25
+ - Aligns output to 80-character terminal width in most cases
26
+
27
+ Examples:
28
+ # nautobot-server migrate
29
+ Running migrations:
30
+ Applying dcim.0065_controller_capabilities_and_more... OK 0.10s
31
+ Applying wireless.0001_initial... OK 0.31s
32
+ Applying dcim.0066_controllermanageddevicegroup_radio_profi... OK 0.12s
33
+
34
+ # nautobot-server migrate -v=2 extras 0100
35
+ Operations to perform:
36
+ Target specific migration: 0100_fileproxy_job_result, from extras
37
+ Running migrations:
38
+ Rendering model states... DONE 19.10s
39
+ Unapplying ipam.0052_alter_ipaddress_index_together_and_mor... OK 0.10s
40
+ Affected ipam.ipaddress 75 rows 0.001s/record
41
+ Affected ipam.prefix 184 rows 0.000s/record
42
+ Affected ipam.vrf 20 rows 0.004s/record
43
+ Unapplying ipam.0051_added_optional_vrf_relationship_to_vdc... OK 0.10s
44
+ Affected ipam.vrf 20 rows 0.006s/record
45
+ Affected ipam.vrfdeviceassignment 140 rows 0.001s/record
46
+ Unapplying virtualization.0030_alter_virtualmachine_local_c... OK 0.30s
47
+ Affected virtualization.virtualmachine 0 rows
48
+ Affected virtualization.vminterface 0 rows
49
+ Unapplying virtualization.0029_add_role_field_to_interface_... OK 0.10s
50
+ Affected virtualization.vminterface 0 rows
51
+ """
52
+ if self.verbosity < 1:
53
+ return
54
+
55
+ if action in ["apply_start", "render_start", "unapply_start"]:
56
+ self.start = time.monotonic()
57
+ self.affected_models = set()
58
+ self.affected_models_count = {}
59
+ self.migration = migration
60
+ if self.verbosity >= 2 and self.migration is not None:
61
+ for operation in self.migration.operations:
62
+ if isinstance(operation, FieldOperation):
63
+ self.affected_models.add((self.migration.app_label, operation.model_name.lower()))
64
+ elif isinstance(operation, ModelOperation):
65
+ self.affected_models.add((self.migration.app_label, operation.name.lower()))
66
+
67
+ for app_label, model_name in sorted(self.affected_models):
68
+ self.affected_models_count[f"{app_label}.{model_name}"] = 0
69
+ with contextlib.suppress(Exception):
70
+ model = apps.get_model(app_label, model_name)
71
+ self.affected_models_count[model._meta.label_lower] = model.objects.count()
72
+
73
+ if action == "apply_start":
74
+ msg = f" Applying {str(migration)[:50]}..."
75
+ elif action == "render_start":
76
+ msg = " Rendering model states..."
77
+ else:
78
+ msg = f" Unapplying {str(migration)[:48]}..."
79
+ self.stdout.write(f"{msg:<64}", ending="")
80
+ self.stdout.flush()
81
+
82
+ elif action in ["apply_success", "render_success", "unapply_success"]:
83
+ elapsed = time.monotonic() - self.start
84
+ outcome = "DONE" if action == "render_success" else "FAKED" if fake else "OK"
85
+ self.stdout.write(self.style.SUCCESS(f" {outcome:<5} {elapsed: 8.2f}s"))
86
+ if self.verbosity >= 2 and self.migration is not None:
87
+ for app_label, model_name in sorted(self.affected_models):
88
+ if self.affected_models_count[f"{app_label}.{model_name}"] == 0:
89
+ with contextlib.suppress(Exception):
90
+ model = apps.get_model(app_label, model_name)
91
+ self.affected_models_count[model._meta.label_lower] = model.objects.count()
92
+
93
+ for key, value in self.affected_models_count.items():
94
+ if value:
95
+ self.stdout.write(f" Affected {key:<38} {value: 8} rows {elapsed / value:6.3f}s/record")
96
+ else:
97
+ self.stdout.write(f" Affected {key:<38} {value: 8} rows")
@@ -1,6 +1,7 @@
1
1
  from django.core.cache import cache
2
2
  from django.db.models import Case, When
3
3
  from django.db.models.signals import post_delete, post_save
4
+ from tree_queries.compiler import TreeQuery
4
5
  from tree_queries.models import TreeNode
5
6
  from tree_queries.query import TreeManager as TreeManager_, TreeQuerySet as TreeQuerySet_
6
7
 
@@ -61,6 +62,22 @@ class TreeQuerySet(TreeQuerySet_, querysets.RestrictedQuerySet):
61
62
  return deepest.tree_depth
62
63
  return 0
63
64
 
65
+ def count(self):
66
+ """Custom count method for optimization purposes.
67
+
68
+ TreeQuerySet instances in Nautobot are by default with tree fields. So if somewhere tree fields aren't
69
+ explicitly removed from the queryset and count is called, the whole tree is calculated. Since this is not
70
+ needed, this implementation calls `without_tree_fields` before issuing the count query and `with_tree_fields`
71
+ afterwards when applicable.
72
+ """
73
+ should_have_tree_fields = isinstance(self.query, TreeQuery)
74
+ if should_have_tree_fields:
75
+ self.without_tree_fields()
76
+ count = super().count()
77
+ if should_have_tree_fields:
78
+ self.with_tree_fields()
79
+ return count
80
+
64
81
 
65
82
  class TreeManager(TreeManager_, BaseManager.from_queryset(TreeQuerySet)):
66
83
  """
nautobot/core/settings.py CHANGED
@@ -765,7 +765,7 @@ CONSTANCE_CONFIG = {
765
765
  ),
766
766
  "JOB_CREATE_FILE_MAX_SIZE": ConstanceConfigItem(
767
767
  default=10 << 20,
768
- help_text=mark_safe( # noqa: S308 # suspicious-mark-safe-usage, but this is a static string so it's safe
768
+ help_text=mark_safe(
769
769
  "Maximum size (in bytes) of any single file generated by a <code>Job.create_file()</code> call."
770
770
  ),
771
771
  field_type=int,
@@ -798,7 +798,7 @@ CONSTANCE_CONFIG = {
798
798
  ),
799
799
  "NETWORK_DRIVERS": ConstanceConfigItem(
800
800
  default={},
801
- help_text=mark_safe( # noqa: S308 # suspicious-mark-safe-usage, but this is a static string so it's safe
801
+ help_text=mark_safe(
802
802
  "Extend or override default Platform.network_driver translations provided by "
803
803
  '<a href="https://netutils.readthedocs.io/en/latest/user/lib_use_cases_lib_mapper/">netutils</a>. '
804
804
  "Enter a dictionary in JSON format, for example:\n"
@@ -1487,9 +1487,9 @@ properties:
1487
1487
  }
1488
1488
  ```
1489
1489
 
1490
- The default top-level keys are `ansible`, `hier_config`, `napalm`, `netmiko`, `netutils_parser`,
1491
- `ntc_templates`, `pyats`, `pyntc`, and `scrapli`, but you can also add additional keys if you have
1492
- an alternative network driver that you want your Nautobot instance to include.
1490
+ The default top-level keys consists of `ansible`, `hier_config`, `napalm`, etc, and comes from netutils, but
1491
+ you can also add additional keys if you have an alternative network driver that you want your Nautobot instance
1492
+ to include.
1493
1493
  is_constance_config: true
1494
1494
  type: "object"
1495
1495
  version_added: "1.6.0"