nautobot 2.2.0b1__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 (425) hide show
  1. nautobot/__init__.py +31 -0
  2. nautobot/apps/api.py +1 -2
  3. nautobot/apps/utils.py +4 -0
  4. nautobot/apps/views.py +2 -0
  5. nautobot/circuits/api/urls.py +1 -2
  6. nautobot/circuits/api/views.py +0 -12
  7. nautobot/circuits/apps.py +1 -1
  8. nautobot/circuits/tests/test_filters.py +1 -1
  9. nautobot/core/api/routers.py +50 -3
  10. nautobot/core/api/utils.py +4 -0
  11. nautobot/core/api/views.py +21 -15
  12. nautobot/core/cli/__init__.py +18 -11
  13. nautobot/core/constants.py +85 -0
  14. nautobot/core/filters.py +7 -1
  15. nautobot/core/forms/widgets.py +1 -2
  16. nautobot/core/graphql/schema.py +1 -0
  17. nautobot/core/management/commands/generate_test_data.py +4 -4
  18. nautobot/core/models/__init__.py +1 -0
  19. nautobot/core/settings.py +24 -3
  20. nautobot/core/settings.yaml +20 -0
  21. nautobot/core/signals.py +1 -0
  22. nautobot/core/tables.py +2 -1
  23. nautobot/core/templates/admin/base.html +23 -94
  24. nautobot/core/templates/generic/object_retrieve.html +2 -2
  25. nautobot/core/templates/graphene/graphiql.html +18 -47
  26. nautobot/core/templates/inc/footer.html +5 -5
  27. nautobot/core/templates/inc/javascript.html +4 -4
  28. nautobot/core/templates/inc/media.html +2 -2
  29. nautobot/core/templates/inc/nav_menu.html +0 -7
  30. nautobot/core/templates/nautobot_config.py.j2 +14 -1
  31. nautobot/core/templates/rest_framework/api.html +12 -5
  32. nautobot/core/templatetags/helpers.py +2 -2
  33. nautobot/core/testing/__init__.py +1 -1
  34. nautobot/core/testing/filters.py +1 -1
  35. nautobot/core/testing/views.py +30 -0
  36. nautobot/core/tests/integration/test_view_authentication.py +68 -0
  37. nautobot/core/tests/test_api.py +13 -6
  38. nautobot/core/tests/test_csv.py +5 -4
  39. nautobot/core/tests/test_filters.py +2 -1
  40. nautobot/core/tests/test_graphql.py +4 -14
  41. nautobot/core/tests/test_navigations.py +3 -0
  42. nautobot/core/tests/test_views.py +44 -16
  43. nautobot/core/utils/data.py +1 -2
  44. nautobot/core/utils/lookup.py +126 -0
  45. nautobot/core/views/__init__.py +3 -7
  46. nautobot/core/views/generic.py +20 -6
  47. nautobot/core/views/mixins.py +7 -1
  48. nautobot/core/views/renderers.py +11 -6
  49. nautobot/dcim/api/serializers.py +4 -4
  50. nautobot/dcim/api/urls.py +2 -3
  51. nautobot/dcim/api/views.py +7 -18
  52. nautobot/dcim/apps.py +8 -4
  53. nautobot/dcim/elevations.py +5 -1
  54. nautobot/dcim/factory.py +7 -7
  55. nautobot/dcim/filters/__init__.py +16 -17
  56. nautobot/dcim/forms.py +61 -45
  57. nautobot/dcim/homepage.py +11 -3
  58. nautobot/dcim/management/commands/migrate_location_contacts.py +218 -0
  59. nautobot/dcim/migrations/0057_controller_models.py +11 -70
  60. nautobot/dcim/models/__init__.py +2 -2
  61. nautobot/dcim/models/devices.py +14 -16
  62. nautobot/dcim/models/racks.py +1 -3
  63. nautobot/dcim/navigation.py +23 -31
  64. nautobot/dcim/signals.py +6 -6
  65. nautobot/dcim/tables/__init__.py +2 -2
  66. nautobot/dcim/tables/devices.py +13 -16
  67. nautobot/dcim/tables/template_code.py +1 -1
  68. nautobot/dcim/templates/dcim/controller_create.html +70 -0
  69. nautobot/dcim/templates/dcim/controller_retrieve.html +35 -18
  70. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +88 -0
  71. nautobot/dcim/templates/dcim/device/lldp_neighbors.html +75 -43
  72. nautobot/dcim/templates/dcim/device.html +11 -3
  73. nautobot/dcim/templates/dcim/device_edit.html +1 -1
  74. nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
  75. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
  76. nautobot/dcim/tests/test_api.py +47 -6
  77. nautobot/dcim/tests/test_filters.py +92 -81
  78. nautobot/dcim/tests/test_graphql.py +11 -1
  79. nautobot/dcim/tests/test_models.py +15 -15
  80. nautobot/dcim/tests/test_signals.py +3 -1
  81. nautobot/dcim/tests/test_views.py +24 -12
  82. nautobot/dcim/urls.py +1 -1
  83. nautobot/dcim/views.py +25 -15
  84. nautobot/extras/api/serializers.py +20 -1
  85. nautobot/extras/api/urls.py +1 -2
  86. nautobot/extras/api/views.py +0 -10
  87. nautobot/extras/apps.py +7 -0
  88. nautobot/extras/context_managers.py +15 -4
  89. nautobot/extras/filters/__init__.py +53 -2
  90. nautobot/extras/filters/customfields.py +14 -9
  91. nautobot/extras/filters/mixins.py +6 -1
  92. nautobot/extras/forms/contacts.py +7 -0
  93. nautobot/extras/health_checks.py +1 -0
  94. nautobot/extras/jobs.py +1 -0
  95. nautobot/extras/managers.py +15 -2
  96. nautobot/extras/models/contacts.py +1 -0
  97. nautobot/extras/models/customfields.py +25 -2
  98. nautobot/extras/models/datasources.py +1 -0
  99. nautobot/extras/models/mixins.py +1 -0
  100. nautobot/extras/navigation.py +71 -65
  101. nautobot/extras/plugins/__init__.py +2 -1
  102. nautobot/extras/plugins/views.py +7 -11
  103. nautobot/extras/querysets.py +1 -2
  104. nautobot/extras/secrets/providers.py +1 -0
  105. nautobot/extras/signals.py +15 -5
  106. nautobot/extras/tasks.py +70 -17
  107. nautobot/extras/tests/test_api.py +2 -4
  108. nautobot/extras/tests/test_customfields.py +72 -9
  109. nautobot/extras/tests/test_dynamicgroups.py +2 -0
  110. nautobot/extras/tests/test_filters.py +89 -4
  111. nautobot/extras/tests/test_models.py +9 -0
  112. nautobot/extras/tests/test_relationships.py +10 -1
  113. nautobot/extras/tests/test_views.py +112 -1
  114. nautobot/extras/views.py +18 -17
  115. nautobot/ipam/api/serializers.py +10 -0
  116. nautobot/ipam/api/urls.py +1 -2
  117. nautobot/ipam/api/views.py +0 -11
  118. nautobot/ipam/apps.py +3 -2
  119. nautobot/ipam/tables.py +2 -22
  120. nautobot/ipam/tests/test_graphql.py +2 -3
  121. nautobot/ipam/tests/test_tables.py +42 -0
  122. nautobot/ipam/tests/test_views.py +1 -0
  123. nautobot/ipam/views.py +9 -9
  124. nautobot/project-static/css/base.css +1 -0
  125. nautobot/project-static/docs/404.html +126 -73
  126. nautobot/project-static/docs/apps/index.html +127 -71
  127. nautobot/project-static/docs/apps/nautobot-apps.html +127 -71
  128. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
  129. nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
  130. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
  131. nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
  132. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +127 -71
  133. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +127 -71
  134. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +167 -73
  135. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +165 -72
  136. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +127 -71
  137. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +127 -71
  138. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +127 -71
  139. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +127 -71
  140. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +127 -71
  141. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +127 -71
  142. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +127 -71
  143. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +127 -71
  144. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +127 -71
  145. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +127 -71
  146. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +127 -71
  147. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +127 -71
  148. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +127 -71
  149. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +127 -71
  150. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +128 -72
  151. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +127 -71
  152. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +127 -71
  153. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +345 -71
  154. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +172 -73
  155. nautobot/project-static/docs/development/apps/api/configuration-view.html +127 -71
  156. nautobot/project-static/docs/development/apps/api/database-backend-config.html +127 -71
  157. nautobot/project-static/docs/development/apps/api/models/django-admin.html +127 -71
  158. nautobot/project-static/docs/development/apps/api/models/global-search.html +127 -71
  159. nautobot/project-static/docs/development/apps/api/models/graphql.html +127 -71
  160. nautobot/project-static/docs/development/apps/api/models/index.html +127 -71
  161. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +127 -71
  162. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +127 -71
  163. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +127 -71
  164. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +127 -71
  165. nautobot/project-static/docs/development/apps/api/platform-features/index.html +127 -71
  166. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +127 -71
  167. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +127 -71
  168. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +127 -71
  169. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +127 -71
  170. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +127 -71
  171. nautobot/project-static/docs/development/apps/api/prometheus.html +127 -71
  172. nautobot/project-static/docs/development/apps/api/setup.html +127 -71
  173. nautobot/project-static/docs/development/apps/api/testing.html +127 -71
  174. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +127 -71
  175. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +127 -71
  176. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +127 -71
  177. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +127 -71
  178. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +127 -71
  179. nautobot/project-static/docs/development/apps/api/views/base-template.html +127 -71
  180. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +141 -80
  181. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +144 -83
  182. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +127 -71
  183. nautobot/project-static/docs/development/apps/api/views/index.html +127 -71
  184. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +127 -71
  185. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +127 -71
  186. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +127 -71
  187. nautobot/project-static/docs/development/apps/api/views/notes.html +127 -71
  188. nautobot/project-static/docs/development/apps/api/views/rest-api.html +127 -71
  189. nautobot/project-static/docs/development/apps/api/views/urls.html +127 -71
  190. nautobot/project-static/docs/development/apps/index.html +127 -71
  191. nautobot/project-static/docs/development/apps/migration/code-updates.html +127 -71
  192. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +127 -71
  193. nautobot/project-static/docs/development/apps/migration/from-v1.html +127 -71
  194. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +127 -71
  195. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +127 -71
  196. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +127 -71
  197. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +127 -71
  198. nautobot/project-static/docs/development/apps/porting-from-netbox.html +127 -71
  199. nautobot/project-static/docs/development/core/application-registry.html +127 -71
  200. nautobot/project-static/docs/development/core/best-practices.html +145 -79
  201. nautobot/project-static/docs/development/core/bootstrap-ui.html +127 -71
  202. nautobot/project-static/docs/development/core/caching.html +127 -71
  203. nautobot/project-static/docs/development/core/controllers.html +141 -275
  204. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +127 -71
  205. nautobot/project-static/docs/development/core/extending-models.html +13 -8166
  206. nautobot/project-static/docs/development/core/generic-views.html +142 -86
  207. nautobot/project-static/docs/development/core/getting-started.html +146 -81
  208. nautobot/project-static/docs/development/core/homepage.html +145 -89
  209. nautobot/project-static/docs/development/core/index.html +127 -71
  210. nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
  211. nautobot/project-static/docs/development/core/model-features.html +130 -74
  212. nautobot/project-static/docs/development/core/natural-keys.html +127 -71
  213. nautobot/project-static/docs/development/core/navigation-menu.html +127 -71
  214. nautobot/project-static/docs/development/core/release-checklist.html +127 -71
  215. nautobot/project-static/docs/development/core/role-internals.html +127 -71
  216. nautobot/project-static/docs/development/core/settings.html +127 -71
  217. nautobot/project-static/docs/development/core/style-guide.html +127 -71
  218. nautobot/project-static/docs/development/core/templates.html +127 -71
  219. nautobot/project-static/docs/development/core/testing.html +127 -71
  220. nautobot/project-static/docs/development/core/user-preferences.html +127 -71
  221. nautobot/project-static/docs/development/extending-models.html +3 -3
  222. nautobot/project-static/docs/development/index.html +127 -71
  223. nautobot/project-static/docs/development/jobs/index.html +128 -72
  224. nautobot/project-static/docs/development/jobs/migration/from-v1.html +127 -71
  225. nautobot/project-static/docs/index.html +126 -73
  226. nautobot/project-static/docs/models/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +3 -3
  227. nautobot/project-static/docs/objects.inv +0 -0
  228. nautobot/project-static/docs/release-notes/index.html +127 -71
  229. nautobot/project-static/docs/release-notes/version-1.0.html +127 -71
  230. nautobot/project-static/docs/release-notes/version-1.1.html +127 -71
  231. nautobot/project-static/docs/release-notes/version-1.2.html +127 -71
  232. nautobot/project-static/docs/release-notes/version-1.3.html +127 -71
  233. nautobot/project-static/docs/release-notes/version-1.4.html +127 -71
  234. nautobot/project-static/docs/release-notes/version-1.5.html +127 -71
  235. nautobot/project-static/docs/release-notes/version-1.6.html +127 -71
  236. nautobot/project-static/docs/release-notes/version-2.0.html +127 -71
  237. nautobot/project-static/docs/release-notes/version-2.1.html +538 -254
  238. nautobot/project-static/docs/release-notes/version-2.2.html +520 -101
  239. nautobot/project-static/docs/requirements.txt +3 -3
  240. nautobot/project-static/docs/search/search_index.json +1 -1
  241. nautobot/project-static/docs/sitemap.xml +264 -259
  242. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  243. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +127 -71
  244. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +127 -71
  245. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +127 -71
  246. nautobot/project-static/docs/user-guide/administration/configuration/index.html +127 -71
  247. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +192 -71
  248. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +127 -71
  249. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +127 -71
  250. nautobot/project-static/docs/user-guide/administration/guides/caching.html +127 -71
  251. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +127 -71
  252. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +127 -71
  253. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +127 -71
  254. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -71
  255. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +127 -71
  256. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +127 -71
  257. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +130 -74
  258. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +127 -71
  259. nautobot/project-static/docs/user-guide/administration/installation/docker.html +134 -74
  260. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +127 -71
  261. nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +8616 -0
  262. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +127 -71
  263. nautobot/project-static/docs/user-guide/administration/installation/index.html +127 -71
  264. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +127 -71
  265. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +127 -71
  266. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +130 -74
  267. nautobot/project-static/docs/user-guide/administration/installation/services.html +127 -71
  268. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +127 -71
  269. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +127 -71
  270. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +127 -71
  271. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +127 -71
  272. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +127 -71
  273. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +127 -71
  274. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +127 -71
  275. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +127 -71
  276. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +127 -71
  277. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +127 -71
  278. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +127 -71
  279. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +127 -71
  280. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +127 -71
  281. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +127 -71
  282. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +127 -71
  283. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +127 -71
  284. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +127 -71
  285. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +127 -71
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +127 -71
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +127 -71
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +127 -71
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +127 -71
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +127 -71
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +362 -79
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +210 -85
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +127 -71
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +127 -71
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +127 -71
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +127 -71
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +127 -71
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +127 -71
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +127 -71
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +127 -71
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +127 -71
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +127 -71
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +127 -71
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +127 -71
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +127 -71
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +127 -71
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +127 -71
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +127 -71
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +127 -71
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +127 -71
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +127 -71
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +127 -71
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +127 -71
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +127 -71
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +127 -71
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +127 -71
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +127 -71
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +127 -71
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +127 -71
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +127 -71
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +127 -71
  322. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +127 -71
  323. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +130 -74
  324. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +127 -71
  325. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +138 -71
  326. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +138 -71
  327. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +127 -71
  328. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +127 -71
  329. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +127 -71
  330. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +127 -71
  331. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +127 -71
  332. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +127 -71
  333. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +127 -71
  334. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +127 -71
  335. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +127 -71
  336. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +127 -71
  337. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +127 -71
  338. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +127 -71
  339. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +127 -71
  340. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +127 -71
  341. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +127 -71
  342. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +127 -71
  343. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +127 -71
  344. nautobot/project-static/docs/user-guide/feature-guides/{contact-and-team.html → contacts-and-teams.html} +128 -72
  345. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +129 -73
  346. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +127 -71
  347. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +127 -71
  348. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +127 -71
  349. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +127 -71
  350. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +127 -71
  351. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +127 -71
  352. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +129 -73
  353. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +127 -71
  354. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +127 -71
  355. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +127 -71
  356. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +127 -71
  357. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +127 -71
  358. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +127 -71
  359. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +127 -71
  360. nautobot/project-static/docs/user-guide/index.html +127 -71
  361. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +127 -71
  362. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +127 -71
  363. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +127 -71
  364. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +127 -71
  365. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +127 -71
  366. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +127 -71
  367. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +127 -71
  368. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +127 -71
  369. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +127 -71
  370. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +127 -71
  371. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +127 -71
  372. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +127 -71
  373. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +127 -71
  374. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +127 -71
  375. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +127 -71
  376. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +127 -71
  377. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +127 -71
  378. nautobot/project-static/docs/user-guide/platform-functionality/note.html +127 -71
  379. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +127 -71
  380. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +127 -71
  381. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +127 -71
  382. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +127 -71
  383. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +127 -71
  384. nautobot/project-static/docs/user-guide/platform-functionality/role.html +127 -71
  385. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +127 -71
  386. nautobot/project-static/docs/user-guide/platform-functionality/status.html +127 -71
  387. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +127 -71
  388. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +127 -71
  389. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +127 -71
  390. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +127 -71
  391. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +127 -71
  392. nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
  393. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
  394. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
  395. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
  396. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
  397. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
  398. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
  399. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
  400. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
  401. nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
  402. nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
  403. nautobot/tenancy/api/urls.py +1 -2
  404. nautobot/tenancy/api/views.py +0 -12
  405. nautobot/tenancy/tables.py +1 -1
  406. nautobot/tenancy/tests/test_views.py +1 -0
  407. nautobot/users/api/urls.py +1 -2
  408. nautobot/users/api/views.py +2 -65
  409. nautobot/users/views.py +8 -8
  410. nautobot/virtualization/api/urls.py +1 -2
  411. nautobot/virtualization/api/views.py +0 -12
  412. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/METADATA +24 -24
  413. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/RECORD +418 -412
  414. nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +0 -43
  415. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
  416. nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
  417. nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
  418. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
  419. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
  420. nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
  421. /nautobot/dcim/templates/dcim/{controllerdevicegroup_retrieve.html → controllermanageddevicegroup_retrieve.html} +0 -0
  422. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/LICENSE.txt +0 -0
  423. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/NOTICE +0 -0
  424. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/WHEEL +0 -0
  425. {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/entry_points.txt +0 -0
@@ -14,8 +14,50 @@ menu_items = (
14
14
  weight=100,
15
15
  groups=(
16
16
  NavMenuGroup(
17
- name="Metadata", # TODO: is there a better name for this grouping?
17
+ name="Contacts",
18
18
  weight=400,
19
+ items=(
20
+ NavMenuItem(
21
+ link="extras:contact_list",
22
+ name="Contacts",
23
+ weight=100,
24
+ permissions=["extras.view_contact"],
25
+ buttons=[NavMenuAddButton(link="extras:contact_add", permissions=["extras.add_contact"])],
26
+ ),
27
+ NavMenuItem(
28
+ link="extras:team_list",
29
+ name="Teams",
30
+ weight=200,
31
+ permissions=["extras.view_team"],
32
+ buttons=[NavMenuAddButton(link="extras:team_add", permissions=["extras.add_team"])],
33
+ ),
34
+ ),
35
+ ),
36
+ NavMenuGroup(
37
+ name="Groups",
38
+ weight=500,
39
+ items=(
40
+ NavMenuItem(
41
+ link="extras:dynamicgroup_list",
42
+ name="Dynamic Groups",
43
+ weight=100,
44
+ permissions=[
45
+ "extras.view_dynamicgroup",
46
+ ],
47
+ buttons=(
48
+ NavMenuAddButton(
49
+ link="extras:dynamicgroup_add",
50
+ permissions=[
51
+ "extras.add_dynamicgroup",
52
+ ],
53
+ ),
54
+ ),
55
+ ),
56
+ ),
57
+ ),
58
+ NavMenuGroup(
59
+ name="Metadata", # TODO: is there a better name for this grouping?
60
+ weight=600,
19
61
  items=(
20
62
  NavMenuItem(
21
63
  link="extras:tag_list",
@@ -65,42 +107,6 @@ menu_items = (
65
107
  ),
66
108
  ),
67
109
  ),
68
- NavMenuItem(
69
- link="extras:contact_list",
70
- name="Contacts",
71
- weight=400,
72
- permissions=["extras.view_contact"],
73
- buttons=[NavMenuAddButton(link="extras:contact_add", permissions=["extras.add_contact"])],
74
- ),
75
- NavMenuItem(
76
- link="extras:team_list",
77
- name="Teams",
78
- weight=500,
79
- permissions=["extras.view_team"],
80
- buttons=[NavMenuAddButton(link="extras:team_add", permissions=["extras.add_team"])],
81
- ),
82
- ),
83
- ),
84
- NavMenuGroup(
85
- name="Dynamic Groups",
86
- weight=500,
87
- items=(
88
- NavMenuItem(
89
- link="extras:dynamicgroup_list",
90
- name="Dynamic Groups",
91
- weight=100,
92
- permissions=[
93
- "extras.view_dynamicgroup",
94
- ],
95
- buttons=(
96
- NavMenuAddButton(
97
- link="extras:dynamicgroup_add",
98
- permissions=[
99
- "extras.add_dynamicgroup",
100
- ],
101
- ),
102
- ),
103
- ),
104
110
  ),
105
111
  ),
106
112
  ),
@@ -276,22 +282,6 @@ menu_items = (
276
282
  ),
277
283
  ),
278
284
  ),
279
- NavMenuItem(
280
- link="extras:relationship_list",
281
- name="Relationships",
282
- weight=200,
283
- permissions=[
284
- "extras.view_relationship",
285
- ],
286
- buttons=(
287
- NavMenuAddButton(
288
- link="extras:relationship_add",
289
- permissions=[
290
- "extras.add_relationship",
291
- ],
292
- ),
293
- ),
294
- ),
295
285
  NavMenuItem(
296
286
  link="extras:note_list",
297
287
  name="Notes",
@@ -389,37 +379,53 @@ menu_items = (
389
379
  ),
390
380
  ),
391
381
  NavMenuGroup(
392
- name="Miscellaneous",
382
+ name="Data Model",
393
383
  weight=600,
394
384
  items=(
395
385
  NavMenuItem(
396
- link="extras:computedfield_list",
397
- name="Computed Fields",
386
+ link="extras:customfield_list",
387
+ name="Custom Fields",
398
388
  weight=100,
399
389
  permissions=[
400
- "extras.view_computedfield",
390
+ "extras.view_customfield",
401
391
  ],
402
392
  buttons=(
403
393
  NavMenuAddButton(
404
- link="extras:computedfield_add",
394
+ link="extras:customfield_add",
405
395
  permissions=[
406
- "extras.add_computedfield",
396
+ "extras.add_customfield",
407
397
  ],
408
398
  ),
409
399
  ),
410
400
  ),
411
401
  NavMenuItem(
412
- link="extras:customfield_list",
413
- name="Custom Fields",
402
+ link="extras:relationship_list",
403
+ name="Relationships",
414
404
  weight=200,
415
405
  permissions=[
416
- "extras.view_customfield",
406
+ "extras.view_relationship",
417
407
  ],
418
408
  buttons=(
419
409
  NavMenuAddButton(
420
- link="extras:customfield_add",
410
+ link="extras:relationship_add",
421
411
  permissions=[
422
- "extras.add_customfield",
412
+ "extras.add_relationship",
413
+ ],
414
+ ),
415
+ ),
416
+ ),
417
+ NavMenuItem(
418
+ link="extras:computedfield_list",
419
+ name="Computed Fields",
420
+ weight=300,
421
+ permissions=[
422
+ "extras.view_computedfield",
423
+ ],
424
+ buttons=(
425
+ NavMenuAddButton(
426
+ link="extras:computedfield_add",
427
+ permissions=[
428
+ "extras.add_computedfield",
423
429
  ],
424
430
  ),
425
431
  ),
@@ -427,7 +433,7 @@ menu_items = (
427
433
  NavMenuItem(
428
434
  link="extras:customlink_list",
429
435
  name="Custom Links",
430
- weight=300,
436
+ weight=400,
431
437
  permissions=[
432
438
  "extras.view_customlink",
433
439
  ],
@@ -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.
@@ -2,11 +2,9 @@ from collections import OrderedDict
2
2
 
3
3
  from django.apps import apps
4
4
  from django.conf import settings
5
- from django.contrib.auth.mixins import LoginRequiredMixin
6
5
  from django.http import Http404
7
6
  from django.shortcuts import render
8
7
  from django.urls.exceptions import NoReverseMatch
9
- from django.views.generic import View
10
8
  from django_tables2 import RequestConfig
11
9
  from drf_spectacular.utils import extend_schema
12
10
  from rest_framework import permissions
@@ -14,13 +12,14 @@ from rest_framework.response import Response
14
12
  from rest_framework.reverse import reverse
15
13
  from rest_framework.views import APIView
16
14
 
17
- from nautobot.core.api.views import NautobotAPIVersionMixin
15
+ from nautobot.core.api.views import AuthenticatedAPIRootView, NautobotAPIVersionMixin
18
16
  from nautobot.core.forms import TableConfigForm
17
+ from nautobot.core.views.generic import GenericView
19
18
  from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
20
19
  from nautobot.extras.plugins.tables import InstalledAppsTable
21
20
 
22
21
 
23
- class InstalledAppsView(LoginRequiredMixin, View):
22
+ class InstalledAppsView(GenericView):
24
23
  """
25
24
  View for listing all installed Apps.
26
25
  """
@@ -66,7 +65,7 @@ class InstalledAppsView(LoginRequiredMixin, View):
66
65
  )
67
66
 
68
67
 
69
- class InstalledAppDetailView(LoginRequiredMixin, View):
68
+ class InstalledAppDetailView(GenericView):
70
69
  """
71
70
  View for showing details of an installed App.
72
71
  """
@@ -93,7 +92,6 @@ class InstalledAppsAPIView(NautobotAPIVersionMixin, APIView):
93
92
  """
94
93
 
95
94
  permission_classes = [permissions.IsAdminUser]
96
- _ignore_model_permissions = True
97
95
 
98
96
  def get_view_name(self):
99
97
  return "Installed Apps"
@@ -129,11 +127,9 @@ class InstalledAppsAPIView(NautobotAPIVersionMixin, APIView):
129
127
  return Response([self._get_app_data(apps.get_app_config(app)) for app in settings.PLUGINS])
130
128
 
131
129
 
132
- class AppsAPIRootView(NautobotAPIVersionMixin, APIView):
133
- _ignore_model_permissions = True
134
-
135
- def get_view_name(self):
136
- return "Apps"
130
+ class AppsAPIRootView(AuthenticatedAPIRootView):
131
+ name = "Apps"
132
+ description = "API extension point for installed Nautobot Apps"
137
133
 
138
134
  @staticmethod
139
135
  def _get_app_entry(app_config, request, format_):
@@ -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)
nautobot/extras/tasks.py CHANGED
@@ -14,7 +14,7 @@ logger = getLogger("nautobot.extras.tasks")
14
14
 
15
15
 
16
16
  @nautobot_task
17
- def update_custom_field_choice_data(field_id, old_value, new_value):
17
+ def update_custom_field_choice_data(field_id, old_value, new_value, change_context=None):
18
18
  """
19
19
  Update the values for a custom field choice used in objects' _custom_field_data for the given field.
20
20
 
@@ -23,6 +23,8 @@ def update_custom_field_choice_data(field_id, old_value, new_value):
23
23
  old_value (str): The existing value of the choice
24
24
  new_value (str): The value which will be used as replacement
25
25
  """
26
+ # Circular Import
27
+ from nautobot.extras.context_managers import web_request_context
26
28
  from nautobot.extras.models import CustomField
27
29
 
28
30
  try:
@@ -35,19 +37,43 @@ def update_custom_field_choice_data(field_id, old_value, new_value):
35
37
  # Loop through all field content types and search for values to update
36
38
  for ct in field.content_types.all():
37
39
  model = ct.model_class()
38
- for obj in model.objects.filter(**{f"_custom_field_data__{field.key}": old_value}):
39
- obj._custom_field_data[field.key] = new_value
40
- obj.save()
40
+ if change_context is not None:
41
+ with web_request_context(
42
+ user=change_context.get("user"),
43
+ change_id=change_context.get("change_id"),
44
+ context_detail=change_context.get("context_detail"),
45
+ context=change_context.get("context"),
46
+ ):
47
+ for obj in model.objects.filter(**{f"_custom_field_data__{field.key}": old_value}):
48
+ obj._custom_field_data[field.key] = new_value
49
+ obj.save()
50
+ else:
51
+ for obj in model.objects.filter(**{f"_custom_field_data__{field.key}": old_value}):
52
+ obj._custom_field_data[field.key] = new_value
53
+ obj.save()
41
54
 
42
55
  elif field.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
43
56
  # Loop through all field content types and search for values to update
44
57
  for ct in field.content_types.all():
45
58
  model = ct.model_class()
46
- for obj in model.objects.filter(**{f"_custom_field_data__{field.key}__contains": old_value}):
47
- old_list = obj._custom_field_data[field.key]
48
- new_list = [new_value if e == old_value else e for e in old_list]
49
- obj._custom_field_data[field.key] = new_list
50
- obj.save()
59
+ if change_context is not None:
60
+ with web_request_context(
61
+ user=change_context.get("user"),
62
+ change_id=change_context.get("change_id"),
63
+ context_detail=change_context.get("context_detail"),
64
+ context=change_context.get("context"),
65
+ ):
66
+ for obj in model.objects.filter(**{f"_custom_field_data__{field.key}__contains": old_value}):
67
+ old_list = obj._custom_field_data[field.key]
68
+ new_list = [new_value if e == old_value else e for e in old_list]
69
+ obj._custom_field_data[field.key] = new_list
70
+ obj.save()
71
+ else:
72
+ for obj in model.objects.filter(**{f"_custom_field_data__{field.key}__contains": old_value}):
73
+ old_list = obj._custom_field_data[field.key]
74
+ new_list = [new_value if e == old_value else e for e in old_list]
75
+ obj._custom_field_data[field.key] = new_list
76
+ obj.save()
51
77
 
52
78
  else:
53
79
  logger.error(f"Unknown field type, failing to act on choice data for this field {field.key}.")
@@ -57,7 +83,7 @@ def update_custom_field_choice_data(field_id, old_value, new_value):
57
83
 
58
84
 
59
85
  @nautobot_task
60
- def delete_custom_field_data(field_key, content_type_pk_set):
86
+ def delete_custom_field_data(field_key, content_type_pk_set, change_context=None):
61
87
  """
62
88
  Delete the values for a custom field
63
89
 
@@ -65,16 +91,30 @@ def delete_custom_field_data(field_key, content_type_pk_set):
65
91
  field_key (str): The key of the custom field which is being deleted
66
92
  content_type_pk_set (list): List of PKs for content types to act upon
67
93
  """
94
+ # Circular Import
95
+ from nautobot.extras.context_managers import web_request_context
96
+
68
97
  with transaction.atomic():
69
98
  for ct in ContentType.objects.filter(pk__in=content_type_pk_set):
70
99
  model = ct.model_class()
71
- for obj in model.objects.filter(**{f"_custom_field_data__{field_key}__isnull": False}):
72
- del obj._custom_field_data[field_key]
73
- obj.save()
100
+ if change_context is not None:
101
+ with web_request_context(
102
+ user=change_context.get("user"),
103
+ change_id=change_context.get("change_id"),
104
+ context_detail=change_context.get("context_detail"),
105
+ context=change_context.get("context"),
106
+ ):
107
+ for obj in model.objects.filter(**{f"_custom_field_data__{field_key}__isnull": False}):
108
+ del obj._custom_field_data[field_key]
109
+ obj.save()
110
+ else:
111
+ for obj in model.objects.filter(**{f"_custom_field_data__{field_key}__isnull": False}):
112
+ del obj._custom_field_data[field_key]
113
+ obj.save()
74
114
 
75
115
 
76
116
  @nautobot_task
77
- def provision_field(field_id, content_type_pk_set):
117
+ def provision_field(field_id, content_type_pk_set, change_context=None):
78
118
  """
79
119
  Provision a new custom field on all relevant content type object instances.
80
120
 
@@ -82,6 +122,8 @@ def provision_field(field_id, content_type_pk_set):
82
122
  field_id (uuid4): The PK of the custom field being provisioned
83
123
  content_type_pk_set (list): List of PKs for content types to act upon
84
124
  """
125
+ # Circular Import
126
+ from nautobot.extras.context_managers import web_request_context
85
127
  from nautobot.extras.models import CustomField
86
128
 
87
129
  try:
@@ -93,9 +135,20 @@ def provision_field(field_id, content_type_pk_set):
93
135
  with transaction.atomic():
94
136
  for ct in ContentType.objects.filter(pk__in=content_type_pk_set):
95
137
  model = ct.model_class()
96
- for obj in model.objects.all():
97
- obj._custom_field_data.setdefault(field.key, field.default)
98
- obj.save()
138
+ if change_context is not None:
139
+ with web_request_context(
140
+ user=change_context.get("user"),
141
+ change_id=change_context.get("change_id"),
142
+ context_detail=change_context.get("context_detail"),
143
+ context=change_context.get("context"),
144
+ ):
145
+ for obj in model.objects.all():
146
+ obj._custom_field_data.setdefault(field.key, field.default)
147
+ obj.save()
148
+ else:
149
+ for obj in model.objects.all():
150
+ obj._custom_field_data.setdefault(field.key, field.default)
151
+ obj.save()
99
152
 
100
153
  return True
101
154
 
@@ -18,6 +18,7 @@ from nautobot.core.testing import APITestCase, APIViewTestCases
18
18
  from nautobot.core.testing.utils import disable_warnings
19
19
  from nautobot.core.utils.lookup import get_route_for_model
20
20
  from nautobot.dcim.models import (
21
+ Controller,
21
22
  Device,
22
23
  DeviceType,
23
24
  Location,
@@ -408,11 +409,9 @@ class ContactTest(APIViewTestCases.APIViewTestCase):
408
409
  {
409
410
  "name": "Contact 3",
410
411
  "phone": "555-0123",
411
- "email": "",
412
412
  },
413
413
  {
414
414
  "name": "Contact 4",
415
- "phone": "",
416
415
  "email": "contact4@example.com",
417
416
  },
418
417
  ]
@@ -2851,6 +2850,7 @@ class RelationshipTest(APIViewTestCases.APIViewTestCase, RequiredRelationshipTes
2851
2850
  vlan_groups = VLANGroup.objects.all()[:2]
2852
2851
 
2853
2852
  # Try deleting all devices and then creating 2 VLANs (fails):
2853
+ Controller.objects.filter(controller_device__isnull=False).delete()
2854
2854
  Device.objects.all().delete()
2855
2855
  response = send_bulk_data(
2856
2856
  "post",
@@ -3611,11 +3611,9 @@ class TeamTest(APIViewTestCases.APIViewTestCase):
3611
3611
  {
3612
3612
  "name": "Team 3",
3613
3613
  "phone": "555-0123",
3614
- "email": "",
3615
3614
  },
3616
3615
  {
3617
3616
  "name": "Team 4",
3618
- "phone": "",
3619
3617
  "email": "team4@example.com",
3620
3618
  "address": "Rainbow Bridge, Central NJ",
3621
3619
  },