nautobot 2.2.0__py3-none-any.whl → 2.2.1__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 (345) hide show
  1. nautobot/__init__.py +31 -0
  2. nautobot/circuits/apps.py +1 -1
  3. nautobot/core/api/routers.py +25 -0
  4. nautobot/core/cli/__init__.py +18 -11
  5. nautobot/core/constants.py +85 -0
  6. nautobot/core/forms/widgets.py +1 -2
  7. nautobot/core/graphql/schema.py +1 -0
  8. nautobot/core/models/__init__.py +1 -0
  9. nautobot/core/settings.py +23 -3
  10. nautobot/core/settings.yaml +20 -0
  11. nautobot/core/signals.py +1 -0
  12. nautobot/core/templates/generic/object_retrieve.html +2 -2
  13. nautobot/core/templates/inc/javascript.html +4 -4
  14. nautobot/core/templates/inc/media.html +2 -2
  15. nautobot/core/templates/nautobot_config.py.j2 +14 -1
  16. nautobot/core/testing/__init__.py +1 -1
  17. nautobot/core/testing/filters.py +1 -1
  18. nautobot/core/tests/integration/test_view_authentication.py +1 -0
  19. nautobot/core/tests/test_views.py +22 -0
  20. nautobot/core/utils/data.py +1 -2
  21. nautobot/core/utils/lookup.py +2 -0
  22. nautobot/core/views/generic.py +1 -3
  23. nautobot/core/views/mixins.py +0 -1
  24. nautobot/core/views/renderers.py +7 -5
  25. nautobot/dcim/apps.py +8 -4
  26. nautobot/dcim/elevations.py +5 -1
  27. nautobot/dcim/tables/devices.py +1 -1
  28. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +12 -4
  29. nautobot/dcim/templates/dcim/device.html +1 -1
  30. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
  31. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
  32. nautobot/dcim/tests/test_api.py +36 -0
  33. nautobot/dcim/tests/test_signals.py +1 -1
  34. nautobot/dcim/views.py +6 -0
  35. nautobot/extras/api/serializers.py +20 -1
  36. nautobot/extras/apps.py +7 -0
  37. nautobot/extras/context_managers.py +15 -4
  38. nautobot/extras/filters/customfields.py +14 -9
  39. nautobot/extras/filters/mixins.py +6 -1
  40. nautobot/extras/health_checks.py +1 -0
  41. nautobot/extras/jobs.py +1 -0
  42. nautobot/extras/managers.py +1 -2
  43. nautobot/extras/models/contacts.py +1 -0
  44. nautobot/extras/models/customfields.py +25 -2
  45. nautobot/extras/models/datasources.py +1 -0
  46. nautobot/extras/models/mixins.py +1 -0
  47. nautobot/extras/plugins/__init__.py +2 -1
  48. nautobot/extras/querysets.py +1 -2
  49. nautobot/extras/secrets/providers.py +1 -0
  50. nautobot/extras/signals.py +15 -5
  51. nautobot/extras/tasks.py +70 -17
  52. nautobot/extras/tests/test_api.py +0 -4
  53. nautobot/extras/tests/test_customfields.py +72 -9
  54. nautobot/extras/views.py +8 -7
  55. nautobot/ipam/api/serializers.py +10 -0
  56. nautobot/ipam/apps.py +3 -2
  57. nautobot/project-static/docs/404.html +102 -70
  58. nautobot/project-static/docs/apps/index.html +103 -68
  59. nautobot/project-static/docs/apps/nautobot-apps.html +103 -68
  60. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
  61. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
  62. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
  63. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
  64. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +103 -68
  65. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +103 -68
  66. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +141 -68
  67. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +141 -69
  68. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +103 -68
  69. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +103 -68
  70. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +103 -68
  71. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +103 -68
  72. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +103 -68
  73. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +103 -68
  74. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +103 -68
  75. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +103 -68
  76. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +103 -68
  77. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +103 -68
  78. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +103 -68
  79. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +103 -68
  80. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +103 -68
  81. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +103 -68
  82. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +104 -69
  83. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +103 -68
  84. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +103 -68
  85. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +103 -68
  86. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +103 -68
  87. nautobot/project-static/docs/development/apps/api/configuration-view.html +103 -68
  88. nautobot/project-static/docs/development/apps/api/database-backend-config.html +103 -68
  89. nautobot/project-static/docs/development/apps/api/models/django-admin.html +103 -68
  90. nautobot/project-static/docs/development/apps/api/models/global-search.html +103 -68
  91. nautobot/project-static/docs/development/apps/api/models/graphql.html +103 -68
  92. nautobot/project-static/docs/development/apps/api/models/index.html +103 -68
  93. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +103 -68
  94. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +103 -68
  95. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +103 -68
  96. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +103 -68
  97. nautobot/project-static/docs/development/apps/api/platform-features/index.html +103 -68
  98. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +103 -68
  99. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +103 -68
  100. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +103 -68
  101. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +103 -68
  102. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +103 -68
  103. nautobot/project-static/docs/development/apps/api/prometheus.html +103 -68
  104. nautobot/project-static/docs/development/apps/api/setup.html +103 -68
  105. nautobot/project-static/docs/development/apps/api/testing.html +103 -68
  106. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +103 -68
  107. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +103 -68
  108. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +103 -68
  109. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +103 -68
  110. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +103 -68
  111. nautobot/project-static/docs/development/apps/api/views/base-template.html +103 -68
  112. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +103 -68
  113. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +103 -68
  114. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +103 -68
  115. nautobot/project-static/docs/development/apps/api/views/index.html +103 -68
  116. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +103 -68
  117. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +103 -68
  118. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +103 -68
  119. nautobot/project-static/docs/development/apps/api/views/notes.html +103 -68
  120. nautobot/project-static/docs/development/apps/api/views/rest-api.html +103 -68
  121. nautobot/project-static/docs/development/apps/api/views/urls.html +103 -68
  122. nautobot/project-static/docs/development/apps/index.html +103 -68
  123. nautobot/project-static/docs/development/apps/migration/code-updates.html +103 -68
  124. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +103 -68
  125. nautobot/project-static/docs/development/apps/migration/from-v1.html +103 -68
  126. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +103 -68
  127. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +103 -68
  128. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +103 -68
  129. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +103 -68
  130. nautobot/project-static/docs/development/apps/porting-from-netbox.html +103 -68
  131. nautobot/project-static/docs/development/core/application-registry.html +103 -68
  132. nautobot/project-static/docs/development/core/best-practices.html +121 -76
  133. nautobot/project-static/docs/development/core/bootstrap-ui.html +103 -68
  134. nautobot/project-static/docs/development/core/caching.html +103 -68
  135. nautobot/project-static/docs/development/core/controllers.html +106 -71
  136. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +103 -68
  137. nautobot/project-static/docs/development/core/extending-models.html +13 -8187
  138. nautobot/project-static/docs/development/core/generic-views.html +118 -83
  139. nautobot/project-static/docs/development/core/getting-started.html +103 -68
  140. nautobot/project-static/docs/development/core/homepage.html +121 -86
  141. nautobot/project-static/docs/development/core/index.html +103 -68
  142. nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
  143. nautobot/project-static/docs/development/core/model-features.html +106 -71
  144. nautobot/project-static/docs/development/core/natural-keys.html +103 -68
  145. nautobot/project-static/docs/development/core/navigation-menu.html +103 -68
  146. nautobot/project-static/docs/development/core/release-checklist.html +103 -68
  147. nautobot/project-static/docs/development/core/role-internals.html +103 -68
  148. nautobot/project-static/docs/development/core/settings.html +103 -68
  149. nautobot/project-static/docs/development/core/style-guide.html +103 -68
  150. nautobot/project-static/docs/development/core/templates.html +103 -68
  151. nautobot/project-static/docs/development/core/testing.html +103 -68
  152. nautobot/project-static/docs/development/core/user-preferences.html +103 -68
  153. nautobot/project-static/docs/development/extending-models.html +3 -3
  154. nautobot/project-static/docs/development/index.html +103 -68
  155. nautobot/project-static/docs/development/jobs/index.html +104 -69
  156. nautobot/project-static/docs/development/jobs/migration/from-v1.html +103 -68
  157. nautobot/project-static/docs/index.html +102 -70
  158. nautobot/project-static/docs/objects.inv +0 -0
  159. nautobot/project-static/docs/release-notes/index.html +103 -68
  160. nautobot/project-static/docs/release-notes/version-1.0.html +103 -68
  161. nautobot/project-static/docs/release-notes/version-1.1.html +103 -68
  162. nautobot/project-static/docs/release-notes/version-1.2.html +103 -68
  163. nautobot/project-static/docs/release-notes/version-1.3.html +103 -68
  164. nautobot/project-static/docs/release-notes/version-1.4.html +103 -68
  165. nautobot/project-static/docs/release-notes/version-1.5.html +103 -68
  166. nautobot/project-static/docs/release-notes/version-1.6.html +103 -68
  167. nautobot/project-static/docs/release-notes/version-2.0.html +103 -68
  168. nautobot/project-static/docs/release-notes/version-2.1.html +103 -68
  169. nautobot/project-static/docs/release-notes/version-2.2.html +334 -97
  170. nautobot/project-static/docs/requirements.txt +3 -3
  171. nautobot/project-static/docs/search/search_index.json +1 -1
  172. nautobot/project-static/docs/sitemap.xml +258 -258
  173. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  174. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +103 -68
  175. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +103 -68
  176. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +103 -68
  177. nautobot/project-static/docs/user-guide/administration/configuration/index.html +103 -68
  178. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +168 -68
  179. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +103 -68
  180. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +103 -68
  181. nautobot/project-static/docs/user-guide/administration/guides/caching.html +103 -68
  182. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +103 -68
  183. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +103 -68
  184. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +103 -68
  185. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +107 -68
  186. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +103 -68
  187. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +103 -68
  188. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +106 -71
  189. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +103 -68
  190. nautobot/project-static/docs/user-guide/administration/installation/docker.html +103 -68
  191. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +103 -68
  192. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +103 -68
  193. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +103 -68
  194. nautobot/project-static/docs/user-guide/administration/installation/index.html +103 -68
  195. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +103 -68
  196. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +103 -68
  197. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +103 -68
  198. nautobot/project-static/docs/user-guide/administration/installation/services.html +103 -68
  199. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +103 -68
  200. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +103 -68
  201. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +103 -68
  202. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +103 -68
  203. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +103 -68
  204. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +103 -68
  205. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +103 -68
  206. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +103 -68
  207. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +103 -68
  208. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +103 -68
  209. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +103 -68
  210. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +103 -68
  211. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +103 -68
  212. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +103 -68
  213. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +103 -68
  214. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +103 -68
  215. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +103 -68
  216. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +103 -68
  217. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +103 -68
  218. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +103 -68
  219. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +103 -68
  220. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +103 -68
  221. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +103 -68
  222. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +103 -68
  223. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +103 -68
  224. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +103 -68
  225. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +103 -68
  226. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +103 -68
  227. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +103 -68
  228. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +103 -68
  229. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +103 -68
  230. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +103 -68
  231. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +103 -68
  232. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +103 -68
  233. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +103 -68
  234. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +103 -68
  235. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +103 -68
  236. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +103 -68
  237. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +103 -68
  238. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +103 -68
  239. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +103 -68
  240. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +103 -68
  241. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +103 -68
  242. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +103 -68
  243. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +103 -68
  244. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +103 -68
  245. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +103 -68
  246. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +103 -68
  247. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +103 -68
  248. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +103 -68
  249. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +103 -68
  250. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +103 -68
  251. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +103 -68
  252. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +103 -68
  253. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +103 -68
  254. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +103 -68
  255. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +103 -68
  256. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +114 -68
  257. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +114 -68
  258. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +103 -68
  259. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +103 -68
  260. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +103 -68
  261. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +103 -68
  262. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +103 -68
  263. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +103 -68
  264. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +103 -68
  265. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +103 -68
  266. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +103 -68
  267. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +103 -68
  268. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +103 -68
  269. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +103 -68
  270. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +103 -68
  271. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +103 -68
  272. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +103 -68
  273. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +103 -68
  274. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +103 -68
  275. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +103 -68
  276. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +103 -68
  277. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +103 -68
  278. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +103 -68
  279. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +103 -68
  280. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +103 -68
  281. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +103 -68
  282. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +103 -68
  283. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +103 -68
  284. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +103 -68
  285. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +103 -68
  286. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +103 -68
  287. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +103 -68
  288. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +103 -68
  289. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +103 -68
  290. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +103 -68
  291. nautobot/project-static/docs/user-guide/index.html +103 -68
  292. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +103 -68
  293. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +103 -68
  294. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +103 -68
  295. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +103 -68
  296. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +103 -68
  297. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +103 -68
  298. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +103 -68
  299. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +103 -68
  300. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +103 -68
  301. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +103 -68
  302. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +103 -68
  303. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +103 -68
  304. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +103 -68
  305. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +103 -68
  306. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +103 -68
  307. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +103 -68
  308. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +103 -68
  309. nautobot/project-static/docs/user-guide/platform-functionality/note.html +103 -68
  310. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +103 -68
  311. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +103 -68
  312. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +103 -68
  313. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +103 -68
  314. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +103 -68
  315. nautobot/project-static/docs/user-guide/platform-functionality/role.html +103 -68
  316. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +103 -68
  317. nautobot/project-static/docs/user-guide/platform-functionality/status.html +103 -68
  318. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +103 -68
  319. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +103 -68
  320. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +103 -68
  321. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +103 -68
  322. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +103 -68
  323. nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
  324. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
  325. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
  326. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
  327. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
  328. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
  329. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
  330. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
  331. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
  332. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
  333. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
  334. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/METADATA +22 -22
  335. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/RECORD +339 -338
  336. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
  337. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
  338. nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
  339. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
  340. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
  341. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
  342. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/LICENSE.txt +0 -0
  343. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/NOTICE +0 -0
  344. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/WHEEL +0 -0
  345. {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/entry_points.txt +0 -0
nautobot/dcim/apps.py CHANGED
@@ -5,14 +5,18 @@ class DCIMConfig(NautobotConfig):
5
5
  name = "nautobot.dcim"
6
6
  verbose_name = "DCIM"
7
7
  searchable_models = [
8
+ "cable",
9
+ "controller",
10
+ "device",
11
+ "devicefamily",
12
+ "deviceredundancygroup",
13
+ "devicetype",
8
14
  "location",
15
+ "powerfeed",
9
16
  "rack",
10
17
  "rackgroup",
11
- "devicetype",
12
- "device",
18
+ "softwareversion",
13
19
  "virtualchassis",
14
- "cable",
15
- "powerfeed",
16
20
  ]
17
21
 
18
22
  def ready(self):
@@ -3,6 +3,8 @@ from django.urls import reverse
3
3
  from django.utils.http import urlencode
4
4
  import svgwrite
5
5
 
6
+ from nautobot.core.utils.config import get_settings_or_config
7
+
6
8
  from .choices import DeviceFaceChoices
7
9
  from .constants import RACK_ELEVATION_BORDER_WIDTH
8
10
 
@@ -233,7 +235,9 @@ class RackElevationSVG:
233
235
  start_y + unit_height / 2 + RACK_ELEVATION_BORDER_WIDTH,
234
236
  )
235
237
  unit = ru + 1 if self.rack.desc_units else self.rack.u_height - ru
236
- drawing.add(drawing.text(str(unit), position_coordinates, class_="unit"))
238
+ unit_two_digit_format = get_settings_or_config("RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT")
239
+ unit_display = f"{unit:02d}" if unit_two_digit_format else str(unit)
240
+ drawing.add(drawing.text(unit_display, position_coordinates, class_="unit"))
237
241
 
238
242
  for unit in self.merge_elevations(face):
239
243
  # Loop through all units in the elevation
@@ -919,7 +919,7 @@ class VirtualChassisTable(BaseTable):
919
919
  master = tables.Column(linkify=True)
920
920
  member_count = LinkedCountColumn(
921
921
  viewname="dcim:device_list",
922
- url_params={"virtual_chassis_id": "pk"},
922
+ url_params={"virtual_chassis": "pk"},
923
923
  verbose_name="Members",
924
924
  )
925
925
  tags = TagColumn(url_name="dcim:virtualchassis_list")
@@ -64,6 +64,13 @@ var ready = (callback) => {
64
64
  }
65
65
  };
66
66
 
67
+ function getAttribute(node, querySelector, attribute) {
68
+ if (node === null or node.querySelector(querySelector) === null) {
69
+ return "";
70
+ }
71
+ return node.querySelector(querySelector).getAttribute(attribute) || "";
72
+ }
73
+
67
74
  ready(() => {
68
75
  fetch("{% url 'dcim-api:device-napalm' pk=object.pk %}?method=get_lldp_neighbors_detail")
69
76
  .then((response) => {
@@ -80,10 +87,10 @@ ready(() => {
80
87
  // var row = $('*[data-interface-name="' + iface.split(".")[0].replace(/([\/:])/g, "\\$1") + '"]');
81
88
 
82
89
  // Glean configured hostnames/interfaces from the DOM
83
- const configured_device = row.querySelector('td.configured_device').getAttribute('data');
84
- const configured_chassis = row.querySelector('td.configured_device').getAttribute('data-chassis');
85
- const configured_interface = row.querySelector('td.configured_interface').getAttribute('data-interface-name').toLowerCase();
86
- const configured_mac_address = row.querySelector('td.configured_mac').getAttribute('data-mac-address').toLowerCase();
90
+ const configured_device = getAttribute(row, 'td.configured_device', 'data');
91
+ const configured_chassis = getAttribute(row, 'td.configured_device', 'data-chassis');
92
+ const configured_interface = getAttribute(row, 'td.configured_interface', 'data-interface-name').toLowerCase();
93
+ const configured_mac_address = getAttribute(row, 'td.configured_mac', 'data-mac-address').toLowerCase();
87
94
  let configured_interface_short = null;
88
95
  if (configured_interface) {
89
96
  // Match long-form IOS names against short ones (e.g. Gi0/1 == GigabitEthernet0/1).
@@ -122,5 +129,6 @@ ready(() => {
122
129
  }
123
130
  });
124
131
  });
132
+
125
133
  </script>
126
134
  {% endblock %}
@@ -360,7 +360,7 @@
360
360
  </div>
361
361
  </div>
362
362
  </div>
363
- {% if is_contact_associatable_model %}
363
+ {% if object.is_contact_associable_model %}
364
364
  <div id="contacts" role="tabpanel" class="tab-pane {% if request.GET.tab == 'contacts' %}active{% else %}fade{% endif %}">
365
365
  <div class="row">
366
366
  <div class="col-md-12">
@@ -18,6 +18,10 @@
18
18
  <td>Device Types</td>
19
19
  <td><a href="{% url 'dcim:devicetype_list' %}?device_family={{ object.name }}">{{ object.device_type_count }}</a></td>
20
20
  </tr>
21
+ <tr>
22
+ <td>Total Devices</td>
23
+ <td>{{ total_devices }}</td>
24
+ </tr>
21
25
  </table>
22
26
  </div>
23
27
  {% endblock %}
@@ -169,7 +169,7 @@
169
169
  </div>
170
170
  </div>
171
171
  </div>
172
- {% if is_contact_associatable_model %}
172
+ {% if object.is_contact_associable_model %}
173
173
  <div id="contacts" role="tabpanel" class="tab-pane {% if request.GET.tab == 'contacts' %}active{% else %}fade{% endif %}">
174
174
  <div class="row">
175
175
  <div class="col-md-12">
@@ -618,6 +618,42 @@ class RackTest(APIViewTestCases.APIViewTestCase):
618
618
  self.assertEqual(response.get("Content-Type"), "image/svg+xml")
619
619
  self.assertIn(b'class="slot" height="19" width="190"', response.content)
620
620
 
621
+ @override_settings(
622
+ RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT=False,
623
+ RACK_ELEVATION_DEFAULT_UNIT_HEIGHT=22,
624
+ RACK_ELEVATION_DEFAULT_UNIT_WIDTH=230,
625
+ )
626
+ @override_config(RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT=True)
627
+ def test_get_rack_elevation_unit_svg_settings_overridden(self):
628
+ """
629
+ GET a single rack elevation in SVG format, with Django settings specifying the default RU display format
630
+ """
631
+ rack = Rack.objects.first()
632
+ self.add_permissions("dcim.view_rack")
633
+ reverse_url = reverse("dcim-api:rack-elevation", kwargs={"pk": rack.pk})
634
+ url = f"{reverse_url}?render=svg"
635
+
636
+ response = self.client.get(url, **self.header)
637
+ self.assertHttpStatus(response, status.HTTP_200_OK)
638
+ self.assertEqual(response.get("Content-Type"), "image/svg+xml")
639
+ self.assertIn(b'<text class="unit" x="15.0" y="915.0">1</text>', response.content)
640
+
641
+ @override_settings(RACK_ELEVATION_DEFAULT_UNIT_HEIGHT=22, RACK_ELEVATION_DEFAULT_UNIT_WIDTH=230)
642
+ @override_config(RACK_ELEVATION_UNIT_TWO_DIGIT_FORMAT=True)
643
+ def test_get_rack_elevation_unit_svg_config_overridden(self):
644
+ """
645
+ GET a single rack elevation in SVG format, with Constance config specifying the 2-digit RU display format
646
+ """
647
+ rack = Rack.objects.first()
648
+ self.add_permissions("dcim.view_rack")
649
+ reverse_url = reverse("dcim-api:rack-elevation", kwargs={"pk": rack.pk})
650
+ url = f"{reverse_url}?render=svg"
651
+
652
+ response = self.client.get(url, **self.header)
653
+ self.assertHttpStatus(response, status.HTTP_200_OK)
654
+ self.assertEqual(response.get("Content-Type"), "image/svg+xml")
655
+ self.assertIn(b'<text class="unit" x="15.0" y="915.0">01</text>', response.content)
656
+
621
657
  def test_detail_view_schema(self):
622
658
  url = self._get_detail_url(self._get_queryset().first())
623
659
  response = self.client.options(url, **self.header)
@@ -1,4 +1,4 @@
1
- """Tests for DCIM Signals.py """
1
+ """Tests for DCIM Signals.py"""
2
2
 
3
3
  from django.test import TestCase
4
4
 
nautobot/dcim/views.py CHANGED
@@ -2978,6 +2978,12 @@ class DeviceFamilyUIViewSet(NautobotUIViewSet):
2978
2978
  RequestConfig(request, paginate).configure(device_type_table)
2979
2979
 
2980
2980
  context["device_type_table"] = device_type_table
2981
+
2982
+ total_devices = 0
2983
+ for device_type in device_types:
2984
+ total_devices += device_type.device_count
2985
+ context["total_devices"] = total_devices
2986
+
2981
2987
  return context
2982
2988
 
2983
2989
 
@@ -193,10 +193,18 @@ class ContactSerializer(NautobotModelSerializer):
193
193
  class Meta:
194
194
  model = Contact
195
195
  fields = "__all__"
196
+ # https://www.django-rest-framework.org/api-guide/validators/#optional-fields
197
+ validators = []
198
+ extra_kwargs = {
199
+ "email": {"default": ""},
200
+ "phone": {"default": ""},
201
+ }
196
202
 
197
203
  def validate(self, data):
198
204
  attrs = data.copy()
199
205
  attrs.pop("teams", None)
206
+ validator = UniqueTogetherValidator(queryset=Contact.objects.all(), fields=("name", "phone", "email"))
207
+ validator(attrs, self)
200
208
  super().validate(attrs)
201
209
  return data
202
210
 
@@ -946,7 +954,18 @@ class TeamSerializer(NautobotModelSerializer):
946
954
  class Meta:
947
955
  model = Team
948
956
  fields = "__all__"
949
- extra_kwargs = {"contacts": {"required": False}}
957
+ extra_kwargs = {
958
+ "contacts": {"required": False},
959
+ "email": {"default": ""},
960
+ "phone": {"default": ""},
961
+ }
962
+ # https://www.django-rest-framework.org/api-guide/validators/#optional-fields
963
+ validators = []
964
+
965
+ def validate(self, data):
966
+ validator = UniqueTogetherValidator(queryset=Team.objects.all(), fields=("name", "phone", "email"))
967
+ validator(data, self)
968
+ return super().validate(data)
950
969
 
951
970
 
952
971
  #
nautobot/extras/apps.py CHANGED
@@ -12,6 +12,13 @@ logger = logging.getLogger(__name__)
12
12
 
13
13
  class ExtrasConfig(NautobotConfig):
14
14
  name = "nautobot.extras"
15
+ searchable_models = [
16
+ "contact",
17
+ "dynamicgroup",
18
+ "externalintegration",
19
+ "gitrepository",
20
+ "team",
21
+ ]
15
22
 
16
23
  def ready(self):
17
24
  super().ready()
@@ -7,7 +7,7 @@ from django.test.client import RequestFactory
7
7
 
8
8
  from nautobot.extras.choices import ObjectChangeEventContextChoices
9
9
  from nautobot.extras.models import ObjectChange
10
- from nautobot.extras.signals import change_context_state
10
+ from nautobot.extras.signals import change_context_state, get_user_if_authenticated
11
11
  from nautobot.extras.webhooks import enqueue_webhooks
12
12
 
13
13
 
@@ -46,11 +46,22 @@ class ChangeContext:
46
46
  if self.change_id is None:
47
47
  self.change_id = uuid.uuid4()
48
48
 
49
- def get_user(self):
49
+ def get_user(self, instance=None):
50
50
  """Return self.user if set, otherwise return self.request.user"""
51
51
  if self.user is not None:
52
- return self.user
53
- return self.request.user
52
+ return get_user_if_authenticated(self.user, instance)
53
+ return get_user_if_authenticated(self.request.user, instance)
54
+
55
+ def as_dict(self, instance=None):
56
+ """
57
+ Return ChangeContext attributes in dictionary format
58
+ """
59
+ context = {
60
+ "user": self.get_user(instance),
61
+ "change_id": self.change_id,
62
+ "context": self.context,
63
+ }
64
+ return context
54
65
 
55
66
 
56
67
  class JobChangeContext(ChangeContext):
@@ -8,8 +8,9 @@ from nautobot.core.filters import (
8
8
  MultiValueNumberFilter,
9
9
  )
10
10
  from nautobot.core.forms import NullableDateField
11
- from nautobot.core.forms.widgets import StaticSelect2Multiple
11
+ from nautobot.core.utils.data import is_uuid
12
12
  from nautobot.extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices
13
+ from nautobot.extras.models import CustomFieldChoice
13
14
 
14
15
  EXACT_FILTER_TYPES = (
15
16
  CustomFieldTypeChoices.TYPE_BOOLEAN,
@@ -71,19 +72,23 @@ class CustomFieldJSONFilter(CustomFieldFilterMixin, django_filters.Filter):
71
72
  """Custom field single value filter for backwards compatibility"""
72
73
 
73
74
 
74
- class CustomFieldMultiSelectFilter(CustomFieldFilterMixin, MultiValueCharFilter):
75
- """This provides functionality for filtering custom fields with multiple select type"""
75
+ class CustomFieldSelectFilter(CustomFieldFilterMixin, MultiValueCharFilter):
76
+ """Filter for custom fields of type TYPE_SELECT."""
76
77
 
77
- def __init__(self, *args, **kwargs):
78
- kwargs.setdefault("lookup_expr", "contains")
79
- super().__init__(*args, **kwargs)
78
+ def get_filter_predicate(self, v):
79
+ if is_uuid(v):
80
+ try:
81
+ v = self.custom_field.custom_field_choices.get(pk=v).value
82
+ except CustomFieldChoice.DoesNotExist:
83
+ v = ""
84
+ return super().get_filter_predicate(v)
80
85
 
81
86
 
82
- class CustomFieldMultiValueSelectFilter(CustomFieldFilterMixin, django_filters.MultipleChoiceFilter):
83
- """This provides functionality for filtering custom fields with select type"""
87
+ class CustomFieldMultiSelectFilter(CustomFieldSelectFilter):
88
+ """Filter for custom fields of type TYPE_MULTISELECT."""
84
89
 
85
90
  def __init__(self, *args, **kwargs):
86
- self.field_class.widget = StaticSelect2Multiple
91
+ kwargs.setdefault("lookup_expr", "contains")
87
92
  super().__init__(*args, **kwargs)
88
93
 
89
94
 
@@ -27,6 +27,7 @@ from nautobot.extras.filters.customfields import (
27
27
  CustomFieldMultiValueDateFilter,
28
28
  CustomFieldMultiValueNumberFilter,
29
29
  CustomFieldNumberFilter,
30
+ CustomFieldSelectFilter,
30
31
  )
31
32
  from nautobot.extras.models import (
32
33
  ConfigContextSchema,
@@ -61,12 +62,16 @@ class CustomFieldModelFilterSetMixin(django_filters.FilterSet):
61
62
  super().__init__(*args, **kwargs)
62
63
 
63
64
  custom_field_filter_classes = {
65
+ # Here, for the "base" filters for each custom field, for backwards compatibility, use single-value filters.
66
+ # For the "extended" filters, see below, we use multi-value filters.
67
+ # 3.0 TODO: switch the "base" filters to multi-value filters as well.
64
68
  CustomFieldTypeChoices.TYPE_DATE: CustomFieldDateFilter,
65
69
  CustomFieldTypeChoices.TYPE_BOOLEAN: CustomFieldBooleanFilter,
66
70
  CustomFieldTypeChoices.TYPE_INTEGER: CustomFieldNumberFilter,
67
71
  CustomFieldTypeChoices.TYPE_JSON: CustomFieldJSONFilter,
72
+ # The below are multi-value filters already:
68
73
  CustomFieldTypeChoices.TYPE_MULTISELECT: CustomFieldMultiSelectFilter,
69
- CustomFieldTypeChoices.TYPE_SELECT: CustomFieldMultiSelectFilter,
74
+ CustomFieldTypeChoices.TYPE_SELECT: CustomFieldSelectFilter,
70
75
  }
71
76
 
72
77
  custom_fields = CustomField.objects.get_for_model(self._meta.model, exclude_filter_disabled=True)
@@ -1,4 +1,5 @@
1
1
  """Nautobot custom health checks."""
2
+
2
3
  from typing import Optional
3
4
  from urllib.parse import urlparse
4
5
 
nautobot/extras/jobs.py CHANGED
@@ -1,4 +1,5 @@
1
1
  """Jobs functionality - consolidates and replaces legacy "custom scripts" and "reports" features."""
2
+
2
3
  from collections import OrderedDict
3
4
  import functools
4
5
  import inspect
@@ -1,6 +1,5 @@
1
1
  from celery import states
2
2
  from django.utils import timezone
3
- from django_celery_beat.managers import ExtendedManager
4
3
  from django_celery_results.managers import TaskResultManager, transaction_retry
5
4
 
6
5
  from nautobot.core.models import BaseManager
@@ -136,5 +135,5 @@ class JobResultManager(BaseManager.from_queryset(RestrictedQuerySet), TaskResult
136
135
  return obj
137
136
 
138
137
 
139
- class ScheduledJobsManager(BaseManager.from_queryset(RestrictedQuerySet), ExtendedManager):
138
+ class ScheduledJobsManager(BaseManager.from_queryset(RestrictedQuerySet)):
140
139
  pass
@@ -19,6 +19,7 @@ class ContactTeamSharedBase(PrimaryModel):
19
19
  address = models.TextField(blank=True)
20
20
 
21
21
  comments = models.TextField(blank=True)
22
+ is_contact_associable_model = False
22
23
 
23
24
  class Meta:
24
25
  abstract = True
@@ -724,7 +724,16 @@ class CustomField(BaseModel, ChangeLoggedModel, NotesMixin):
724
724
 
725
725
  super().delete(*args, **kwargs)
726
726
 
727
- delete_custom_field_data.delay(self.key, content_types)
727
+ # Circular Import
728
+ from nautobot.extras.signals import change_context_state
729
+
730
+ change_context = change_context_state.get()
731
+ if change_context is None:
732
+ context = None
733
+ else:
734
+ context = change_context.as_dict(instance=self)
735
+ context["context_detail"] = "delete custom field data"
736
+ delete_custom_field_data.delay(self.key, content_types, context)
728
737
 
729
738
  def add_prefix_to_cf_key(self):
730
739
  return "cf_" + str(self.key)
@@ -783,8 +792,22 @@ class CustomFieldChoice(BaseModel, ChangeLoggedModel):
783
792
  super().save(*args, **kwargs)
784
793
 
785
794
  if self.value != database_object.value:
795
+ # Circular Import
796
+ from nautobot.extras.signals import change_context_state
797
+
798
+ change_context = change_context_state.get()
799
+ if change_context is None:
800
+ context = None
801
+ else:
802
+ context = change_context.as_dict(instance=self)
803
+ context["context_detail"] = "update custom field choice data"
786
804
  transaction.on_commit(
787
- lambda: update_custom_field_choice_data.delay(self.custom_field.pk, database_object.value, self.value)
805
+ lambda: update_custom_field_choice_data.delay(
806
+ self.custom_field.pk,
807
+ database_object.value,
808
+ self.value,
809
+ context,
810
+ )
788
811
  )
789
812
 
790
813
  def delete(self, *args, **kwargs):
@@ -1,4 +1,5 @@
1
1
  """Models for representing external data sources."""
2
+
2
3
  from importlib.util import find_spec
3
4
  import os
4
5
 
@@ -1,6 +1,7 @@
1
1
  """
2
2
  Class-modifying mixins that need to be standalone to avoid circular imports.
3
3
  """
4
+
4
5
  from django.urls import NoReverseMatch, reverse
5
6
 
6
7
  from nautobot.core.utils.lookup import get_route_for_model
@@ -4,6 +4,7 @@ from importlib import import_module
4
4
  import inspect
5
5
  from logging import getLogger
6
6
 
7
+ from django.conf import settings
7
8
  from django.core.exceptions import ValidationError
8
9
  from django.template.loader import get_template
9
10
  from django.urls import get_resolver, URLPattern
@@ -147,7 +148,7 @@ class NautobotAppConfig(NautobotConfig):
147
148
 
148
149
  # Import metrics (if present)
149
150
  metrics = import_object(f"{self.__module__}.{self.metrics}")
150
- if metrics is not None:
151
+ if metrics is not None and self.name not in settings.METRICS_DISABLED_APPS:
151
152
  register_metrics(metrics)
152
153
  self.features["metrics"] = [] # Initialize as empty, to be filled by the signal handler
153
154
  # Inject the metrics to discover into the signal handler.
@@ -3,7 +3,6 @@ from django.contrib.contenttypes.models import ContentType
3
3
  from django.core.cache import cache
4
4
  from django.db.models import F, Model, OuterRef, Q, Subquery
5
5
  from django.db.models.functions import JSONObject
6
- from django_celery_beat.managers import ExtendedQuerySet
7
6
 
8
7
  from nautobot.core.models.query_functions import EmptyGroupByJSONBAgg
9
8
  from nautobot.core.models.querysets import RestrictedQuerySet
@@ -272,7 +271,7 @@ class JobQuerySet(RestrictedQuerySet):
272
271
  )
273
272
 
274
273
 
275
- class ScheduledJobExtendedQuerySet(RestrictedQuerySet, ExtendedQuerySet):
274
+ class ScheduledJobExtendedQuerySet(RestrictedQuerySet):
276
275
  """
277
276
  Base queryset used for the ScheduledJob class
278
277
  """
@@ -2,6 +2,7 @@
2
2
 
3
3
  Plugins may define and register additional providers in addition to these.
4
4
  """
5
+
5
6
  import os
6
7
 
7
8
  from django import forms
@@ -52,7 +52,7 @@ logger = logging.getLogger(__name__)
52
52
  #
53
53
 
54
54
 
55
- def _get_user_if_authenticated(user, instance):
55
+ def get_user_if_authenticated(user, instance):
56
56
  """Return the user object associated with the request if the user is defined.
57
57
 
58
58
  If the user is not defined, log a warning to indicate that the user couldn't be retrived from the request
@@ -119,7 +119,7 @@ def _handle_changed_object(sender, instance, raw=False, **kwargs):
119
119
 
120
120
  # Record an ObjectChange if applicable
121
121
  if hasattr(instance, "to_objectchange"):
122
- user = _get_user_if_authenticated(change_context_state.get().get_user(), instance)
122
+ user = change_context_state.get().get_user(instance)
123
123
  # save a copy of this instance's field cache so it can be restored after serialization
124
124
  # to prevent unexpected behavior when chaining multiple signal handlers
125
125
  original_cache = instance._state.fields_cache.copy()
@@ -186,7 +186,7 @@ def _handle_deleted_object(sender, instance, **kwargs):
186
186
 
187
187
  # Record an ObjectChange if applicable
188
188
  if hasattr(instance, "to_objectchange"):
189
- user = _get_user_if_authenticated(change_context_state.get().get_user(), instance)
189
+ user = change_context_state.get().get_user(instance)
190
190
 
191
191
  # save a copy of this instance's field cache so it can be restored after serialization
192
192
  # to prevent unexpected behavior when chaining multiple signal handlers
@@ -238,13 +238,23 @@ def handle_cf_removed_obj_types(instance, action, pk_set, **kwargs):
238
238
  """
239
239
  Handle the cleanup of old custom field data when a CustomField is removed from one or more ContentTypes.
240
240
  """
241
+
242
+ change_context = change_context_state.get()
243
+ if change_context is None:
244
+ context = None
245
+ else:
246
+ context = change_context.as_dict(instance=instance)
241
247
  if action == "post_remove":
242
248
  # Existing content types have been removed from the custom field, delete their data
243
- transaction.on_commit(lambda: delete_custom_field_data.delay(instance.key, pk_set))
249
+ if context:
250
+ context["context_detail"] = "delete custom field data from existing content types"
251
+ transaction.on_commit(lambda: delete_custom_field_data.delay(instance.key, pk_set, context))
244
252
 
245
253
  elif action == "post_add":
246
254
  # New content types have been added to the custom field, provision them
247
- transaction.on_commit(lambda: provision_field.delay(instance.pk, pk_set))
255
+ if context:
256
+ context["context_detail"] = "provision custom field data for new content types"
257
+ transaction.on_commit(lambda: provision_field.delay(instance.pk, pk_set, context))
248
258
 
249
259
 
250
260
  m2m_changed.connect(handle_cf_removed_obj_types, sender=CustomField.content_types.through)