nautobot 2.4.8__py3-none-any.whl → 2.4.9__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 (364) hide show
  1. nautobot/circuits/templates/circuits/circuittype.html +1 -1
  2. nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -39
  3. nautobot/circuits/views.py +18 -23
  4. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +4 -111
  5. nautobot/cloud/views.py +56 -25
  6. nautobot/core/celery/schedulers.py +1 -0
  7. nautobot/core/filters.py +1 -1
  8. nautobot/core/graphql/schema.py +1 -0
  9. nautobot/core/jobs/__init__.py +14 -3
  10. nautobot/core/tables.py +13 -6
  11. nautobot/core/testing/views.py +27 -2
  12. nautobot/core/tests/test_jobs.py +113 -0
  13. nautobot/core/tests/test_ui.py +53 -1
  14. nautobot/core/tests/test_utils.py +11 -0
  15. nautobot/core/ui/object_detail.py +19 -12
  16. nautobot/core/utils/filtering.py +3 -0
  17. nautobot/core/views/renderers.py +1 -1
  18. nautobot/dcim/forms.py +10 -0
  19. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +1 -43
  20. nautobot/dcim/templates/dcim/deviceredundancygroup_retrieve.html +1 -59
  21. nautobot/dcim/templates/dcim/devicetype.html +2 -217
  22. nautobot/dcim/templates/dcim/devicetype_edit.html +2 -32
  23. nautobot/dcim/templates/dcim/devicetype_retrieve.html +217 -0
  24. nautobot/dcim/templates/dcim/devicetype_update.html +32 -0
  25. nautobot/dcim/templates/dcim/inc/rack_elevation.html +1 -1
  26. nautobot/dcim/templates/dcim/modulebay_retrieve.html +1 -84
  27. nautobot/dcim/templates/dcim/rack_elevation.html +14 -0
  28. nautobot/dcim/templates/dcim/rackreservation_retrieve.html +0 -68
  29. nautobot/dcim/tests/integration/test_fileinputpicker.py +1 -1
  30. nautobot/dcim/urls.py +1 -36
  31. nautobot/dcim/views.py +133 -81
  32. nautobot/extras/api/views.py +4 -6
  33. nautobot/extras/migrations/0024_job_data_migration.py +1 -1
  34. nautobot/extras/models/jobs.py +78 -62
  35. nautobot/extras/tables.py +11 -1
  36. nautobot/extras/templates/extras/computedfield_retrieve.html +1 -55
  37. nautobot/extras/templates/extras/inc/job_tiles.html +1 -1
  38. nautobot/extras/templates/extras/jobresult.html +1 -1
  39. nautobot/extras/templates/extras/metadatatype_retrieve.html +1 -66
  40. nautobot/extras/templates/extras/scheduledjob.html +25 -9
  41. nautobot/extras/tests/test_api.py +1 -1
  42. nautobot/extras/tests/test_views.py +15 -2
  43. nautobot/extras/utils.py +18 -16
  44. nautobot/extras/views.py +65 -26
  45. nautobot/ipam/tables.py +3 -4
  46. nautobot/project-static/docs/404.html +4 -4
  47. nautobot/project-static/docs/apps/index.html +4 -4
  48. nautobot/project-static/docs/apps/nautobot-apps.html +4 -4
  49. nautobot/project-static/docs/assets/javascripts/{bundle.c8b220af.min.js → bundle.13a4f30d.min.js} +4 -4
  50. nautobot/project-static/docs/assets/javascripts/{bundle.c8b220af.min.js.map → bundle.13a4f30d.min.js.map} +2 -2
  51. nautobot/project-static/docs/assets/javascripts/workers/{search.f8cc74c7.min.js → search.d50fe291.min.js} +2 -2
  52. nautobot/project-static/docs/assets/javascripts/workers/{search.f8cc74c7.min.js.map → search.d50fe291.min.js.map} +1 -1
  53. nautobot/project-static/docs/assets/stylesheets/{main.2afb09e1.min.css → main.342714a4.min.css} +1 -1
  54. nautobot/project-static/docs/assets/stylesheets/{main.2afb09e1.min.css.map → main.342714a4.min.css.map} +1 -1
  55. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +4 -4
  56. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +4 -4
  57. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +4 -4
  58. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +4 -4
  59. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +4 -4
  60. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +4 -4
  61. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +4 -4
  62. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +4 -4
  63. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +4 -4
  64. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +4 -4
  65. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +4 -4
  66. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +4 -4
  67. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +4 -4
  68. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +4 -4
  69. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +4 -4
  70. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +4 -4
  71. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +4 -4
  72. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +4 -4
  73. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +4 -4
  74. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +4 -4
  75. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6 -8
  76. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +4 -4
  77. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +36 -6
  78. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +4 -4
  79. nautobot/project-static/docs/development/apps/api/configuration-view.html +4 -4
  80. nautobot/project-static/docs/development/apps/api/database-backend-config.html +4 -4
  81. nautobot/project-static/docs/development/apps/api/models/django-admin.html +4 -4
  82. nautobot/project-static/docs/development/apps/api/models/global-search.html +4 -4
  83. nautobot/project-static/docs/development/apps/api/models/graphql.html +4 -4
  84. nautobot/project-static/docs/development/apps/api/models/index.html +4 -4
  85. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +4 -4
  86. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +4 -4
  87. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +4 -4
  88. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +4 -4
  89. nautobot/project-static/docs/development/apps/api/platform-features/index.html +4 -4
  90. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +4 -4
  91. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +4 -4
  92. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +4 -4
  93. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +4 -4
  94. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +4 -4
  95. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +4 -4
  96. nautobot/project-static/docs/development/apps/api/prometheus.html +4 -4
  97. nautobot/project-static/docs/development/apps/api/setup.html +4 -4
  98. nautobot/project-static/docs/development/apps/api/testing.html +4 -4
  99. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +4 -4
  100. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +4 -4
  101. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +4 -4
  102. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +4 -4
  103. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +4 -4
  104. nautobot/project-static/docs/development/apps/api/views/base-template.html +4 -4
  105. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +4 -4
  106. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +4 -4
  107. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +4 -4
  108. nautobot/project-static/docs/development/apps/api/views/index.html +4 -4
  109. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +4 -4
  110. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +4 -4
  111. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +4 -4
  112. nautobot/project-static/docs/development/apps/api/views/notes.html +4 -4
  113. nautobot/project-static/docs/development/apps/api/views/rest-api.html +4 -4
  114. nautobot/project-static/docs/development/apps/api/views/urls.html +4 -4
  115. nautobot/project-static/docs/development/apps/index.html +4 -4
  116. nautobot/project-static/docs/development/apps/migration/code-updates.html +4 -4
  117. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +4 -4
  118. nautobot/project-static/docs/development/apps/migration/from-v1.html +4 -4
  119. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +4 -4
  120. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +4 -4
  121. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +4 -4
  122. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +4 -4
  123. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +4 -4
  124. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +4 -4
  125. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +4 -4
  126. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +4 -4
  127. nautobot/project-static/docs/development/apps/porting-from-netbox.html +4 -4
  128. nautobot/project-static/docs/development/core/application-registry.html +4 -4
  129. nautobot/project-static/docs/development/core/best-practices.html +4 -4
  130. nautobot/project-static/docs/development/core/bootstrap-ui.html +4 -4
  131. nautobot/project-static/docs/development/core/caching.html +4 -4
  132. nautobot/project-static/docs/development/core/controllers.html +4 -4
  133. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +41 -55
  134. nautobot/project-static/docs/development/core/generic-views.html +4 -4
  135. nautobot/project-static/docs/development/core/getting-started.html +4 -4
  136. nautobot/project-static/docs/development/core/homepage.html +4 -4
  137. nautobot/project-static/docs/development/core/index.html +4 -4
  138. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +4 -4
  139. nautobot/project-static/docs/development/core/model-checklist.html +4 -4
  140. nautobot/project-static/docs/development/core/model-features.html +4 -4
  141. nautobot/project-static/docs/development/core/natural-keys.html +4 -4
  142. nautobot/project-static/docs/development/core/navigation-menu.html +4 -4
  143. nautobot/project-static/docs/development/core/release-checklist.html +4 -4
  144. nautobot/project-static/docs/development/core/role-internals.html +4 -4
  145. nautobot/project-static/docs/development/core/settings.html +4 -4
  146. nautobot/project-static/docs/development/core/style-guide.html +4 -4
  147. nautobot/project-static/docs/development/core/templates.html +4 -4
  148. nautobot/project-static/docs/development/core/testing.html +4 -4
  149. nautobot/project-static/docs/development/core/ui-component-framework.html +4 -4
  150. nautobot/project-static/docs/development/core/user-preferences.html +4 -4
  151. nautobot/project-static/docs/development/index.html +4 -4
  152. nautobot/project-static/docs/development/jobs/getting-started.html +4 -4
  153. nautobot/project-static/docs/development/jobs/index.html +4 -4
  154. nautobot/project-static/docs/development/jobs/installation.html +4 -4
  155. nautobot/project-static/docs/development/jobs/job-extensions.html +4 -4
  156. nautobot/project-static/docs/development/jobs/job-logging.html +4 -4
  157. nautobot/project-static/docs/development/jobs/job-patterns.html +4 -4
  158. nautobot/project-static/docs/development/jobs/job-structure.html +4 -4
  159. nautobot/project-static/docs/development/jobs/migration/from-v1.html +4 -4
  160. nautobot/project-static/docs/development/jobs/testing.html +4 -4
  161. nautobot/project-static/docs/index.html +4 -4
  162. nautobot/project-static/docs/overview/application_stack.html +4 -4
  163. nautobot/project-static/docs/overview/design_philosophy.html +4 -4
  164. nautobot/project-static/docs/release-notes/index.html +4 -4
  165. nautobot/project-static/docs/release-notes/version-1.0.html +4 -4
  166. nautobot/project-static/docs/release-notes/version-1.1.html +4 -4
  167. nautobot/project-static/docs/release-notes/version-1.2.html +4 -4
  168. nautobot/project-static/docs/release-notes/version-1.3.html +4 -4
  169. nautobot/project-static/docs/release-notes/version-1.4.html +4 -4
  170. nautobot/project-static/docs/release-notes/version-1.5.html +4 -4
  171. nautobot/project-static/docs/release-notes/version-1.6.html +4 -4
  172. nautobot/project-static/docs/release-notes/version-2.0.html +4 -4
  173. nautobot/project-static/docs/release-notes/version-2.1.html +4 -4
  174. nautobot/project-static/docs/release-notes/version-2.2.html +4 -4
  175. nautobot/project-static/docs/release-notes/version-2.3.html +4 -4
  176. nautobot/project-static/docs/release-notes/version-2.4.html +190 -4
  177. nautobot/project-static/docs/requirements.txt +1 -1
  178. nautobot/project-static/docs/search/search_index.json +1 -1
  179. nautobot/project-static/docs/sitemap.xml +298 -298
  180. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  181. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +4 -4
  182. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +4 -4
  183. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +4 -4
  184. nautobot/project-static/docs/user-guide/administration/configuration/index.html +4 -4
  185. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +4 -4
  186. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +4 -4
  187. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +4 -4
  188. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +4 -4
  189. nautobot/project-static/docs/user-guide/administration/guides/docker.html +4 -4
  190. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +4 -4
  191. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +4 -4
  192. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +4 -4
  193. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +4 -4
  194. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +4 -4
  195. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +4 -4
  196. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +4 -4
  197. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +4 -4
  198. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +4 -4
  199. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +4 -4
  200. nautobot/project-static/docs/user-guide/administration/installation/index.html +4 -4
  201. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +4 -4
  202. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +4 -4
  203. nautobot/project-static/docs/user-guide/administration/installation/services.html +4 -4
  204. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +4 -4
  205. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +4 -4
  206. nautobot/project-static/docs/user-guide/administration/security/index.html +4 -4
  207. nautobot/project-static/docs/user-guide/administration/security/notices.html +4 -4
  208. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +4 -4
  209. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +4 -4
  210. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +4 -4
  211. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +4 -4
  212. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +4 -4
  213. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +4 -4
  214. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +4 -4
  215. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +4 -4
  216. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +4 -4
  217. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +4 -4
  218. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +4 -4
  219. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +4 -4
  220. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +4 -4
  221. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +4 -4
  222. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +4 -4
  223. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +4 -4
  224. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +4 -4
  225. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +4 -4
  226. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +4 -4
  227. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +4 -4
  228. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +4 -4
  229. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +4 -4
  230. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +4 -4
  231. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +4 -4
  232. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +4 -4
  233. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +4 -4
  234. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +4 -4
  235. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +4 -4
  236. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +4 -4
  237. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +4 -4
  238. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +4 -4
  239. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +4 -4
  240. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +4 -4
  241. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +4 -4
  242. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +4 -4
  243. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +4 -4
  244. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +4 -4
  245. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +4 -4
  246. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +4 -4
  247. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +4 -4
  248. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +4 -4
  249. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +4 -4
  250. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +4 -4
  251. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +4 -4
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +4 -4
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +4 -4
  254. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +4 -4
  255. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +4 -4
  256. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +4 -4
  257. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +4 -4
  258. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +4 -4
  259. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +4 -4
  260. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +4 -4
  261. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +4 -4
  262. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +4 -4
  263. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +4 -4
  264. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +4 -4
  265. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +4 -4
  266. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +4 -4
  267. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +4 -4
  268. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +4 -4
  269. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +4 -4
  270. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +4 -4
  271. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +4 -4
  272. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +4 -4
  273. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +4 -4
  274. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +4 -4
  275. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +4 -4
  276. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +4 -4
  277. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +4 -4
  278. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +4 -4
  279. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +4 -4
  280. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +4 -4
  281. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +4 -4
  282. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +4 -4
  283. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +4 -4
  284. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +4 -4
  285. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +4 -4
  286. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +4 -4
  287. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +4 -4
  288. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +4 -4
  289. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +4 -4
  290. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +4 -4
  291. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +4 -4
  292. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +4 -4
  293. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +4 -4
  294. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +4 -4
  295. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +4 -4
  296. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +4 -4
  297. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +4 -4
  298. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +4 -4
  299. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +4 -4
  300. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +4 -4
  301. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +4 -4
  302. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +4 -4
  303. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +4 -4
  304. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +4 -4
  305. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +4 -4
  306. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +4 -4
  307. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +4 -4
  308. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +4 -4
  309. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +4 -4
  310. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +4 -4
  311. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +4 -4
  312. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +4 -4
  313. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +4 -4
  314. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +4 -4
  315. nautobot/project-static/docs/user-guide/index.html +4 -4
  316. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +4 -4
  317. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +4 -4
  318. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +4 -4
  319. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +4 -4
  320. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +4 -4
  321. nautobot/project-static/docs/user-guide/platform-functionality/events.html +4 -4
  322. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +4 -4
  323. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +4 -4
  324. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +4 -4
  325. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +4 -4
  326. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +4 -4
  327. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +4 -4
  328. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +4 -4
  329. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +4 -4
  330. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +4 -4
  331. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +4 -4
  332. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +4 -4
  333. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +4 -4
  334. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +4 -4
  335. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +4 -4
  336. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +4 -4
  337. nautobot/project-static/docs/user-guide/platform-functionality/note.html +4 -4
  338. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +4 -4
  339. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +4 -4
  340. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +4 -4
  341. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +4 -4
  342. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +4 -4
  343. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +4 -4
  344. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +4 -4
  345. nautobot/project-static/docs/user-guide/platform-functionality/role.html +4 -4
  346. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +4 -4
  347. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +4 -4
  348. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +4 -4
  349. nautobot/project-static/docs/user-guide/platform-functionality/status.html +4 -4
  350. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +4 -4
  351. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +4 -4
  352. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +4 -4
  353. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +4 -4
  354. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +4 -4
  355. nautobot/project-static/js/forms.js +0 -14
  356. nautobot/wireless/tables.py +1 -0
  357. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -55
  358. nautobot/wireless/views.py +33 -28
  359. {nautobot-2.4.8.dist-info → nautobot-2.4.9.dist-info}/METADATA +3 -3
  360. {nautobot-2.4.8.dist-info → nautobot-2.4.9.dist-info}/RECORD +364 -361
  361. {nautobot-2.4.8.dist-info → nautobot-2.4.9.dist-info}/LICENSE.txt +0 -0
  362. {nautobot-2.4.8.dist-info → nautobot-2.4.9.dist-info}/NOTICE +0 -0
  363. {nautobot-2.4.8.dist-info → nautobot-2.4.9.dist-info}/WHEEL +0 -0
  364. {nautobot-2.4.8.dist-info → nautobot-2.4.9.dist-info}/entry_points.txt +0 -0
nautobot/dcim/views.py CHANGED
@@ -686,6 +686,45 @@ class RackReservationUIViewSet(NautobotUIViewSet):
686
686
  table_class = tables.RackReservationTable
687
687
  queryset = RackReservation.objects.all()
688
688
 
689
+ object_detail_content = object_detail.ObjectDetailContent(
690
+ panels=(
691
+ object_detail.KeyValueTablePanel(
692
+ section=SectionChoices.LEFT_HALF,
693
+ weight=100,
694
+ label="Rack",
695
+ context_data_key="rack_data",
696
+ ),
697
+ object_detail.ObjectFieldsPanel(
698
+ section=SectionChoices.LEFT_HALF,
699
+ weight=100,
700
+ label="Reservation Details",
701
+ fields=["unit_list", "tenant", "user", "description"],
702
+ ),
703
+ object_detail.Panel(
704
+ section=SectionChoices.RIGHT_HALF,
705
+ weight=100,
706
+ template_path="dcim/rack_elevation.html",
707
+ ),
708
+ ),
709
+ )
710
+
711
+ def get_extra_context(self, request, instance):
712
+ context = super().get_extra_context(request, instance)
713
+ if self.action == "retrieve":
714
+ context["rack_data"] = self.get_rack_context(instance)
715
+ return context
716
+
717
+ def get_rack_context(self, instance):
718
+ rack = getattr(instance, "rack", None)
719
+ if not rack:
720
+ return {}
721
+
722
+ return {
723
+ "location": rack.location,
724
+ "rack_group": rack.rack_group,
725
+ "rack": rack,
726
+ }
727
+
689
728
  def get_object(self):
690
729
  obj = super().get_object()
691
730
 
@@ -743,20 +782,18 @@ class ManufacturerUIViewSet(NautobotUIViewSet):
743
782
  #
744
783
  # Device types
745
784
  #
746
-
747
-
748
- class DeviceTypeListView(generic.ObjectListView):
749
- queryset = DeviceType.objects.all()
750
- filterset = filters.DeviceTypeFilterSet
751
- filterset_form = forms.DeviceTypeFilterForm
752
- table = tables.DeviceTypeTable
753
- template_name = "dcim/devicetype_list.html"
754
-
755
-
756
- class DeviceTypeView(generic.ObjectView):
785
+ class DeviceTypeUIViewSet(NautobotUIViewSet):
786
+ bulk_update_form_class = forms.DeviceTypeBulkEditForm
787
+ filterset_class = filters.DeviceTypeFilterSet
788
+ filterset_form_class = forms.DeviceTypeFilterForm
789
+ form_class = forms.DeviceTypeForm
790
+ serializer_class = serializers.DeviceTypeSerializer
791
+ table_class = tables.DeviceTypeTable
757
792
  queryset = DeviceType.objects.select_related("manufacturer").prefetch_related("software_image_files")
758
793
 
759
794
  def get_extra_context(self, request, instance):
795
+ if self.action != "retrieve":
796
+ return {}
760
797
  instance_count = Device.objects.restrict(request.user).filter(device_type=instance).count()
761
798
 
762
799
  # Component tables
@@ -831,16 +868,6 @@ class DeviceTypeView(generic.ObjectView):
831
868
  }
832
869
 
833
870
 
834
- class DeviceTypeEditView(generic.ObjectEditView):
835
- queryset = DeviceType.objects.all()
836
- model_form = forms.DeviceTypeForm
837
- template_name = "dcim/devicetype_edit.html"
838
-
839
-
840
- class DeviceTypeDeleteView(generic.ObjectDeleteView):
841
- queryset = DeviceType.objects.all()
842
-
843
-
844
871
  class DeviceTypeImportView(generic.ObjectImportView):
845
872
  additional_permissions = [
846
873
  "dcim.add_devicetype",
@@ -871,19 +898,6 @@ class DeviceTypeImportView(generic.ObjectImportView):
871
898
  )
872
899
 
873
900
 
874
- class DeviceTypeBulkEditView(generic.BulkEditView):
875
- queryset = DeviceType.objects.all()
876
- filterset = filters.DeviceTypeFilterSet
877
- table = tables.DeviceTypeTable
878
- form = forms.DeviceTypeBulkEditForm
879
-
880
-
881
- class DeviceTypeBulkDeleteView(generic.BulkDeleteView):
882
- queryset = DeviceType.objects.all()
883
- filterset = filters.DeviceTypeFilterSet
884
- table = tables.DeviceTypeTable
885
-
886
-
887
901
  #
888
902
  # Module types
889
903
  #
@@ -3381,13 +3395,42 @@ class ModuleBayUIViewSet(ModuleBayCommonViewSetMixin, NautobotUIViewSet):
3381
3395
  table_class = tables.ModuleBayTable
3382
3396
  create_template_name = "dcim/device_component_add.html"
3383
3397
 
3398
+ object_detail_content = object_detail.ObjectDetailContent(
3399
+ panels=(
3400
+ object_detail.ObjectFieldsPanel(
3401
+ weight=100,
3402
+ section=SectionChoices.LEFT_HALF,
3403
+ fields="__all__",
3404
+ hide_if_unset=("parent_device", "parent_module"),
3405
+ ),
3406
+ object_detail.ObjectFieldsPanel(
3407
+ weight=100,
3408
+ section=SectionChoices.RIGHT_HALF,
3409
+ context_object_key="installed_module_data",
3410
+ label="Installed Module",
3411
+ ),
3412
+ )
3413
+ )
3414
+
3384
3415
  def get_extra_context(self, request, instance):
3416
+ context = super().get_extra_context(request, instance)
3417
+
3385
3418
  if instance:
3386
- return {
3387
- "device_breadcrumb_url": "dcim:device_modulebays",
3388
- "module_breadcrumb_url": "dcim:module_modulebays",
3389
- }
3390
- return {}
3419
+ # Set breadcrumbs always
3420
+ context.update(
3421
+ {
3422
+ "device_breadcrumb_url": "dcim:device_modulebays",
3423
+ "module_breadcrumb_url": "dcim:module_modulebays",
3424
+ }
3425
+ )
3426
+
3427
+ # Add installed module context
3428
+ context["installed_module_data"] = self._get_installed_module_context(instance)
3429
+
3430
+ return context
3431
+
3432
+ def _get_installed_module_context(self, instance):
3433
+ return getattr(instance, "installed_module", None)
3391
3434
 
3392
3435
  def get_selected_objects_parents_name(self, selected_objects):
3393
3436
  selected_object = selected_objects.first()
@@ -4135,18 +4178,32 @@ class DeviceRedundancyGroupUIViewSet(NautobotUIViewSet):
4135
4178
  serializer_class = serializers.DeviceRedundancyGroupSerializer
4136
4179
  table_class = tables.DeviceRedundancyGroupTable
4137
4180
 
4138
- def get_extra_context(self, request, instance):
4139
- context = super().get_extra_context(request, instance)
4140
-
4141
- if self.action == "retrieve" and instance:
4142
- devices = instance.devices_sorted.restrict(request.user)
4143
- devices_table = tables.DeviceTable(devices)
4144
- devices_table.columns.show("device_redundancy_group_priority")
4145
- context["devices_table"] = devices_table
4146
- controllers = instance.controllers_sorted.restrict(request.user)
4147
- controllers_table = tables.ControllerTable(controllers)
4148
- context["controllers_table"] = controllers_table
4149
- return context
4181
+ object_detail_content = object_detail.ObjectDetailContent(
4182
+ panels=(
4183
+ object_detail.ObjectFieldsPanel(
4184
+ section=SectionChoices.LEFT_HALF,
4185
+ weight=100,
4186
+ fields="__all__",
4187
+ ),
4188
+ object_detail.ObjectsTablePanel(
4189
+ section=SectionChoices.FULL_WIDTH,
4190
+ weight=100,
4191
+ table_class=tables.ControllerTable,
4192
+ table_attribute="controllers_sorted",
4193
+ related_field_name="controller_device_redundancy_group",
4194
+ ),
4195
+ object_detail.ObjectsTablePanel(
4196
+ section=SectionChoices.FULL_WIDTH,
4197
+ weight=200,
4198
+ table_class=tables.DeviceTable,
4199
+ table_attribute="devices_sorted",
4200
+ related_field_name="device_redundancy_group",
4201
+ include_columns=[
4202
+ "device_redundancy_group_priority",
4203
+ ],
4204
+ ),
4205
+ )
4206
+ )
4150
4207
 
4151
4208
 
4152
4209
  class InterfaceRedundancyGroupUIViewSet(NautobotUIViewSet):
@@ -4211,36 +4268,31 @@ class DeviceFamilyUIViewSet(NautobotUIViewSet):
4211
4268
  serializer_class = serializers.DeviceFamilySerializer
4212
4269
  table_class = tables.DeviceFamilyTable
4213
4270
  lookup_field = "pk"
4214
-
4215
- def get_extra_context(self, request, instance):
4216
- # Related device types table
4217
- context = super().get_extra_context(request, instance)
4218
- if self.action == "retrieve":
4219
- device_types = (
4220
- DeviceType.objects.restrict(request.user, "view")
4221
- .filter(device_family=instance)
4222
- .select_related("manufacturer")
4223
- .annotate(device_count=count_related(Device, "device_type"))
4224
- )
4225
- device_type_table = tables.DeviceTypeTable(device_types, orderable=False)
4226
-
4227
- paginate = {
4228
- "paginator_class": EnhancedPaginator,
4229
- "per_page": get_paginate_count(request),
4230
- }
4231
- RequestConfig(request, paginate).configure(device_type_table)
4232
-
4233
- context["device_type_table"] = device_type_table
4234
-
4235
- total_devices = 0
4236
- device_type_count = 0
4237
- for device_type in device_types:
4238
- total_devices += device_type.device_count
4239
- device_type_count += 1
4240
- context["total_devices"] = total_devices
4241
- context["device_type_count"] = device_type_count
4242
-
4243
- return context
4271
+ object_detail_content = object_detail.ObjectDetailContent(
4272
+ panels=(
4273
+ object_detail.ObjectFieldsPanel(
4274
+ weight=100,
4275
+ section=SectionChoices.LEFT_HALF,
4276
+ fields="__all__",
4277
+ ),
4278
+ object_detail.ObjectsTablePanel(
4279
+ weight=100,
4280
+ section=SectionChoices.FULL_WIDTH,
4281
+ table_class=tables.DeviceTypeTable,
4282
+ table_filter="device_family",
4283
+ select_related_fields=["manufacturer"],
4284
+ exclude_columns=["device_family"],
4285
+ ),
4286
+ object_detail.ObjectsTablePanel(
4287
+ weight=200,
4288
+ section=SectionChoices.FULL_WIDTH,
4289
+ table_class=tables.DeviceTable,
4290
+ table_filter="device_type__device_family",
4291
+ related_field_name="device_family",
4292
+ exclude_columns=["device_family"],
4293
+ ),
4294
+ )
4295
+ )
4244
4296
 
4245
4297
 
4246
4298
  #
@@ -703,10 +703,8 @@ class JobViewSetBase(
703
703
  # of errors under messages
704
704
  return Response({"errors": e.message_dict if hasattr(e, "error_dict") else e.messages}, status=400)
705
705
 
706
- queue = get_job_queue(task_queue)
707
- if queue is None:
708
- queue = job_model.default_job_queue
709
- if queue.queue_type == JobQueueTypeChoices.TYPE_CELERY and not get_worker_count(queue=task_queue):
706
+ job_queue = get_job_queue(task_queue) or job_model.default_job_queue
707
+ if job_queue.queue_type == JobQueueTypeChoices.TYPE_CELERY and not get_worker_count(queue=task_queue):
710
708
  raise CeleryWorkerNotRunningException(queue=task_queue)
711
709
 
712
710
  # Default to a null JobResult.
@@ -737,7 +735,7 @@ class JobViewSetBase(
737
735
  interval=schedule_data.get("interval"),
738
736
  crontab=schedule_data.get("crontab", ""),
739
737
  approval_required=approval_required,
740
- task_queue=task_queue,
738
+ job_queue=job_queue,
741
739
  **job_class.serialize_data(cleaned_data),
742
740
  )
743
741
  else:
@@ -748,7 +746,7 @@ class JobViewSetBase(
748
746
  job_result = JobResult.enqueue_job(
749
747
  job_model,
750
748
  request.user,
751
- task_queue=task_queue,
749
+ job_queue=job_queue,
752
750
  **job_class.serialize_data(cleaned_data),
753
751
  )
754
752
 
@@ -52,7 +52,7 @@ def migrate_job_data(apps, schema_editor):
52
52
 
53
53
  # Shouldn't be needed but I've seen cases where it happens - not sure exactly why
54
54
  for job_jobresult in JobResult.objects.filter(obj_type__model="jobmodel"):
55
- print("Fixing up content type on {job_jobresult}")
55
+ print(f"Fixing up content type on {job_jobresult}")
56
56
  job_jobresult.obj_type = job_ct
57
57
  job_jobresult.save()
58
58
 
@@ -1,10 +1,11 @@
1
1
  # Data models relating to Jobs
2
2
 
3
3
  import contextlib
4
- from datetime import timedelta
4
+ from datetime import datetime, timedelta
5
5
  import json
6
6
  import logging
7
7
  import signal
8
+ from typing import Optional, TYPE_CHECKING, Union
8
9
 
9
10
  from billiard.exceptions import SoftTimeLimitExceeded
10
11
  from celery.exceptions import NotRegistered
@@ -58,6 +59,11 @@ from nautobot.extras.utils import (
58
59
 
59
60
  from .customfields import CustomFieldModel
60
61
 
62
+ if TYPE_CHECKING:
63
+ from django.contrib.auth import get_user_model
64
+
65
+ User = get_user_model()
66
+
61
67
  logger = logging.getLogger(__name__)
62
68
 
63
69
 
@@ -329,12 +335,12 @@ class Job(PrimaryModel):
329
335
  raise NotRegistered from err
330
336
 
331
337
  @property
332
- def task_queues(self):
338
+ def task_queues(self) -> list[str]:
333
339
  """Deprecated backward-compatibility property for the list of queue names for this Job."""
334
340
  return self.job_queues.values_list("name", flat=True)
335
341
 
336
342
  @task_queues.setter
337
- def task_queues(self, value):
343
+ def task_queues(self, value: Union[str, list[str]]):
338
344
  job_queues = []
339
345
  # value is going to be a comma separated list of queue names
340
346
  if isinstance(value, str):
@@ -748,49 +754,34 @@ class JobResult(BaseModel, CustomFieldModel):
748
754
  )
749
755
 
750
756
  @classmethod
751
- def execute_job(cls, job_model, user, *job_args, celery_kwargs=None, profile=False, job_result=None, **job_kwargs):
757
+ def execute_job(cls, *args, **kwargs):
752
758
  """
753
759
  Create a JobResult instance and run a job in the current process, blocking until the job finishes.
754
760
 
755
761
  Running tasks synchronously in celery is *NOT* supported and if possible `enqueue_job` with synchronous=False
756
762
  should be used instead.
757
763
 
758
- Args:
759
- job_model (Job): The Job to be enqueued for execution
760
- user (User): User object to link to the JobResult instance
761
- celery_kwargs (dict, optional): Dictionary of kwargs to pass as **kwargs to Celery when job is run
762
- profile (bool, optional): Whether to run cProfile on the job execution
763
- job_result (JobResult, optional): Existing JobResult with status PENDING, used in kubernetes job execution
764
- *job_args: positional args passed to the job task
765
- **job_kwargs: keyword args passed to the job task
764
+ Args: see `enqueue_job()`
766
765
 
767
766
  Returns:
768
767
  JobResult instance
769
768
  """
770
- return cls.enqueue_job(
771
- job_model,
772
- user,
773
- *job_args,
774
- celery_kwargs=celery_kwargs,
775
- profile=profile,
776
- job_result=job_result,
777
- synchronous=True,
778
- **job_kwargs,
779
- )
769
+ return cls.enqueue_job(*args, **kwargs, synchronous=True)
780
770
 
781
771
  @classmethod
782
772
  def enqueue_job(
783
773
  cls,
784
- job_model,
785
- user,
774
+ job_model: Job,
775
+ user: "User",
786
776
  *job_args,
787
- celery_kwargs=None,
788
- profile=False,
789
- schedule=None,
790
- task_queue=None,
791
- job_result=None,
792
- synchronous=False,
793
- ignore_singleton_lock=False,
777
+ celery_kwargs: Optional[dict] = None,
778
+ profile: bool = False,
779
+ schedule: Optional["ScheduledJob"] = None,
780
+ job_queue: Optional["JobQueue"] = None,
781
+ task_queue: Optional[str] = None, # deprecated!
782
+ job_result: Optional["JobResult"] = None,
783
+ synchronous: bool = False,
784
+ ignore_singleton_lock: bool = False,
794
785
  **job_kwargs,
795
786
  ):
796
787
  """Create/Modify a JobResult instance and enqueue a job to be executed asynchronously by a Celery worker.
@@ -798,13 +789,16 @@ class JobResult(BaseModel, CustomFieldModel):
798
789
  Args:
799
790
  job_model (Job): The Job to be enqueued for execution.
800
791
  user (User): User object to link to the JobResult instance.
801
- celery_kwargs (dict, optional): Dictionary of kwargs to pass as **kwargs to `apply_async()`/`apply()` when job is run.
802
- profile (bool, optional): If True, dump cProfile stats on the job execution.
803
- schedule (ScheduledJob, optional): ScheduledJob instance to link to the JobResult. Cannot be used with synchronous=True.
804
- task_queue (str, optional): The celery queue to send the job to. If not set, use the default celery queue.
805
- job_result (JobResult, optional): Existing JobResult with status PENDING, to be modified and to be used in kubernetes job execution.
806
- synchronous (bool, optional): If True, run the job in the current process, blocking until the job completes.
807
- ignore_singleton_lock (bool, optional): If True, invalidate the singleton lock before running the job.
792
+ celery_kwargs (dict): Dictionary of kwargs to pass as **kwargs to `apply_async()`/`apply()` when job is run.
793
+ profile (bool): If True, dump cProfile stats on the job execution.
794
+ schedule (ScheduledJob): ScheduledJob instance to link to the JobResult.
795
+ Cannot be used with synchronous=True.
796
+ job_queue (JobQueue): Job queue to send the job to. If not set, use the default queue for the given Job.
797
+ task_queue (str): The celery queue name to send the job to. **Deprecated, prefer `job_queue` instead.**
798
+ job_result (JobResult): Existing JobResult with status PENDING, to be modified and to be used
799
+ in kubernetes job execution.
800
+ synchronous (bool): If True, run the job in the current process, blocking until the job completes.
801
+ ignore_singleton_lock (bool): If True, invalidate the singleton lock before running the job.
808
802
  This allows singleton jobs to run twice, or makes it possible to remove the lock when the first instance
809
803
  of the job failed to remove it for any reason.
810
804
  *job_args: positional args passed to the job task (UNUSED)
@@ -818,6 +812,20 @@ class JobResult(BaseModel, CustomFieldModel):
818
812
  if schedule is not None and synchronous:
819
813
  raise ValueError("Scheduled jobs cannot be run synchronously")
820
814
 
815
+ if job_queue is not None and task_queue is not None and job_queue.name != task_queue:
816
+ raise ValueError("task_queue and job_queue are mutually exclusive")
817
+ if job_queue is not None and task_queue is None:
818
+ task_queue = job_queue.name
819
+ elif task_queue is not None and job_queue is None:
820
+ job_queue = JobQueue.objects.get(name=task_queue)
821
+ else: # both none
822
+ if celery_kwargs is not None and "queue" in celery_kwargs:
823
+ task_queue = celery_kwargs["queue"]
824
+ job_queue = JobQueue.objects.get(name=task_queue)
825
+ else:
826
+ job_queue = job_model.default_job_queue
827
+ task_queue = job_queue.name
828
+
821
829
  if job_result is None:
822
830
  job_result = cls.objects.create(
823
831
  name=job_model.name,
@@ -835,10 +843,6 @@ class JobResult(BaseModel, CustomFieldModel):
835
843
  f"There is a mismatch between the job specified {job_model} and the job associated with the job result {job_result.job_model}"
836
844
  )
837
845
 
838
- if task_queue is None:
839
- task_queue = job_model.default_job_queue.name
840
-
841
- job_queue = JobQueue.objects.get(name=task_queue)
842
846
  # Kubernetes Job Queue logic
843
847
  # As we execute Kubernetes jobs, we want to execute `run_kubernetes_job_and_return_job_result`
844
848
  # the first time the kubernetes job is enqueued to spin up the kubernetes pod.
@@ -863,6 +867,7 @@ class JobResult(BaseModel, CustomFieldModel):
863
867
  job_celery_kwargs["time_limit"] = job_model.time_limit
864
868
 
865
869
  if celery_kwargs is not None:
870
+ # TODO: this lets celery_kwargs override keys like `queue` and `nautobot_job_user_id`; is that desirable?
866
871
  job_celery_kwargs.update(celery_kwargs)
867
872
 
868
873
  if synchronous:
@@ -1208,7 +1213,6 @@ class ScheduledJob(BaseModel):
1208
1213
  ordering = ["name"]
1209
1214
 
1210
1215
  def save(self, *args, **kwargs):
1211
- self.queue = self.queue or ""
1212
1216
  # make sure non-valid crontab doesn't get saved
1213
1217
  if self.interval == JobExecutionType.TYPE_CUSTOM:
1214
1218
  try:
@@ -1253,12 +1257,12 @@ class ScheduledJob(BaseModel):
1253
1257
  return self.to_cron()
1254
1258
 
1255
1259
  @property
1256
- def queue(self):
1260
+ def queue(self) -> str:
1257
1261
  """Deprecated backward-compatibility property for the queue name this job is scheduled for."""
1258
1262
  return self.job_queue.name if self.job_queue else ""
1259
1263
 
1260
1264
  @queue.setter
1261
- def queue(self, value):
1265
+ def queue(self, value: str):
1262
1266
  if value:
1263
1267
  try:
1264
1268
  self.job_queue = JobQueue.objects.get(name=value)
@@ -1301,14 +1305,15 @@ class ScheduledJob(BaseModel):
1301
1305
  cls,
1302
1306
  job_model,
1303
1307
  user,
1304
- name=None,
1305
- start_time=None,
1306
- interval=JobExecutionType.TYPE_IMMEDIATELY,
1307
- crontab="",
1308
- profile=False,
1309
- approval_required=False,
1310
- task_queue=None,
1311
- ignore_singleton_lock=False,
1308
+ name: Optional[str] = None,
1309
+ start_time: Optional[datetime] = None,
1310
+ interval: str = JobExecutionType.TYPE_IMMEDIATELY,
1311
+ crontab: str = "",
1312
+ profile: bool = False,
1313
+ approval_required: bool = False,
1314
+ job_queue: Optional[JobQueue] = None,
1315
+ task_queue: Optional[str] = None, # deprecated!
1316
+ ignore_singleton_lock: bool = False,
1312
1317
  **job_kwargs,
1313
1318
  ):
1314
1319
  """
@@ -1321,21 +1326,32 @@ class ScheduledJob(BaseModel):
1321
1326
  Parameters:
1322
1327
  job_model (JobModel): The job model instance.
1323
1328
  user (User): The user who is scheduling the job.
1324
- name (str, optional): The name of the scheduled job. Defaults to None.
1325
- start_time (datetime, optional): The start time for the job. Defaults to None.
1326
- interval (JobExecutionType, optional): The interval type for the job execution.
1329
+ name (str): The name of the scheduled job. Automatically derived from the job_model and start_time if unset.
1330
+ start_time (datetime): The start time for the job. Defaults to the current time if unset.
1331
+ interval (JobExecutionType): The interval type for the job execution.
1327
1332
  Defaults to JobExecutionType.TYPE_IMMEDIATELY.
1328
- crontab (str, optional): The crontab string for the schedule. Defaults to "".
1329
- profile (bool, optional): Flag indicating whether to profile the job. Defaults to False.
1330
- approval_required (bool, optional): Flag indicating if approval is required. Defaults to False.
1331
- task_queue (str, optional): The task queue for the job. Defaults to None, which will use the configured default celery queue.
1332
- ignore_singleton_lock (bool, optional): Flag indicating whether to ignore singleton locks. Defaults to False.
1333
+ crontab (str): The crontab string for the schedule. Defaults to "".
1334
+ profile (bool): Flag indicating whether to profile the job. Defaults to False.
1335
+ approval_required (bool): Flag indicating if approval is required. Defaults to False.
1336
+ job_queue (JobQueue): The Job queue to use. If unset, use the configured default celery queue.
1337
+ task_queue (str): The queue name to use. **Deprecated, prefer `job_queue`.**
1338
+ ignore_singleton_lock (bool): Whether to ignore singleton locks. Defaults to False.
1333
1339
  **job_kwargs: Additional keyword arguments to pass to the job.
1334
1340
 
1335
1341
  Returns:
1336
1342
  ScheduledJob instance
1337
1343
  """
1338
1344
 
1345
+ if job_queue is not None and task_queue is not None and job_queue.name != task_queue:
1346
+ raise ValueError("task_queue and job_queue are mutually exclusive")
1347
+ if job_queue is not None and task_queue is None:
1348
+ task_queue = job_queue.name
1349
+ elif task_queue is not None and job_queue is None:
1350
+ job_queue = JobQueue.objects.get(name=task_queue)
1351
+ else: # both None
1352
+ job_queue = job_model.default_job_queue
1353
+ task_queue = job_queue.name
1354
+
1339
1355
  if interval == JobExecutionType.TYPE_IMMEDIATELY:
1340
1356
  start_time = timezone.localtime()
1341
1357
  name = name or f"{job_model.name} - {start_time}"
@@ -1376,7 +1392,7 @@ class ScheduledJob(BaseModel):
1376
1392
  user=user,
1377
1393
  approval_required=approval_required,
1378
1394
  crontab=crontab,
1379
- queue=task_queue,
1395
+ job_queue=job_queue,
1380
1396
  )
1381
1397
  scheduled_job.validated_save()
1382
1398
  return scheduled_job
nautobot/extras/tables.py CHANGED
@@ -40,6 +40,7 @@ from .models import (
40
40
  JobLogEntry,
41
41
  JobQueue,
42
42
  JobResult,
43
+ MetadataChoice,
43
44
  MetadataType,
44
45
  Note,
45
46
  ObjectChange,
@@ -730,7 +731,7 @@ class JobTable(BaseTable):
730
731
  accessor="latest_result",
731
732
  template_code="""
732
733
  {% if value %}
733
- {{ value.created }} by {{ value.user }}
734
+ {{ value.date_created|date:settings.SHORT_DATETIME_FORMAT }} by {{ value.user }}
734
735
  {% else %}
735
736
  <span class="text-muted">Never</span>
736
737
  {% endif %}
@@ -1008,6 +1009,15 @@ class MetadataTypeTable(BaseTable):
1008
1009
  )
1009
1010
 
1010
1011
 
1012
+ class MetadataChoiceTable(BaseTable):
1013
+ value = tables.Column()
1014
+ weight = tables.Column()
1015
+
1016
+ class Meta(BaseTable.Meta):
1017
+ model = MetadataChoice
1018
+ fields = ("value", "weight")
1019
+
1020
+
1011
1021
  class ObjectMetadataTable(BaseTable):
1012
1022
  pk = ToggleColumn()
1013
1023
  # NOTE: there is no identity column in this table; this is intentional as we have no detail view for ObjectMetadata
@@ -1,56 +1,2 @@
1
1
  {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block content_left_page %}
5
- <div class="panel panel-default">
6
- <div class="panel-heading">
7
- <strong>Computed Field</strong>
8
- </div>
9
-
10
- <table class="table table-hover panel-body attr-table">
11
- <tr>
12
- <td>Content Type</td>
13
- <td><span>{{ object.content_type }}</span></td>
14
- </tr>
15
- <tr>
16
- <td>Label</td>
17
- <td><span>{{ object.label }}</span></td>
18
- </tr>
19
- <tr>
20
- <td>Key</td>
21
- <td><span>{{ object.key }}</span></td>
22
- </tr>
23
- <tr>
24
- <td>Grouping</td>
25
- <td>{{ object.grouping | placeholder }}</td>
26
- </tr>
27
- <tr>
28
- <td>Description</td>
29
- <td><span>{{ object.description|placeholder }}</span></td>
30
- </tr>
31
- <tr>
32
- <td>Fallback Value</td>
33
- <td><span>{{ object.fallback_value }}</span></td>
34
- </tr>
35
- <tr>
36
- <td>Weight</td>
37
- <td><span>{{ object.weight }}</span></td>
38
- </tr>
39
- <tr>
40
- <td>Move to Advanced Tab</td>
41
- <td><span>{{ object.advanced_ui | render_boolean }}</span></td>
42
- </tr>
43
- </table>
44
- </div>
45
- {% endblock content_left_page %}
46
-
47
- {% block content_full_width_page %}
48
- <div class="panel panel-default">
49
- <div class="panel-heading">
50
- <strong>Template</strong>
51
- </div>
52
- <div class="panel-body">
53
- <pre>{{ object.template }}</pre>
54
- </div>
55
- </div>
56
- {% endblock content_full_width_page %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}