nautobot 2.4.10__py3-none-any.whl → 2.4.11__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 (416) hide show
  1. nautobot/cloud/tests/test_views.py +13 -1
  2. nautobot/cloud/views.py +39 -9
  3. nautobot/core/celery/__init__.py +21 -0
  4. nautobot/core/celery/encoders.py +3 -0
  5. nautobot/core/forms/forms.py +4 -1
  6. nautobot/core/jobs/bulk_actions.py +8 -8
  7. nautobot/core/jobs/cleanup.py +11 -0
  8. nautobot/core/management/commands/generate_test_data.py +2 -1
  9. nautobot/core/templates/generic/object_retrieve.html +1 -1
  10. nautobot/core/testing/mixins.py +19 -1
  11. nautobot/core/testing/views.py +104 -8
  12. nautobot/core/tests/test_jobs.py +20 -4
  13. nautobot/core/tests/test_utils.py +193 -0
  14. nautobot/core/tests/test_views_utils.py +53 -2
  15. nautobot/core/ui/object_detail.py +4 -0
  16. nautobot/core/utils/lookup.py +4 -2
  17. nautobot/core/utils/module_loading.py +86 -58
  18. nautobot/core/views/generic.py +2 -12
  19. nautobot/core/views/mixins.py +19 -1
  20. nautobot/core/views/renderers.py +4 -13
  21. nautobot/core/views/utils.py +16 -0
  22. nautobot/dcim/api/serializers.py +13 -0
  23. nautobot/dcim/api/urls.py +1 -0
  24. nautobot/dcim/api/views.py +20 -0
  25. nautobot/dcim/apps.py +1 -0
  26. nautobot/dcim/factory.py +11 -0
  27. nautobot/dcim/filters/__init__.py +110 -0
  28. nautobot/dcim/forms.py +205 -19
  29. nautobot/dcim/migrations/0070_modulefamily_models.py +92 -0
  30. nautobot/dcim/models/__init__.py +2 -0
  31. nautobot/dcim/models/device_component_templates.py +14 -0
  32. nautobot/dcim/models/device_components.py +13 -1
  33. nautobot/dcim/models/devices.py +62 -0
  34. nautobot/dcim/navigation.py +16 -0
  35. nautobot/dcim/tables/__init__.py +2 -0
  36. nautobot/dcim/tables/devices.py +48 -0
  37. nautobot/dcim/tables/devicetypes.py +35 -1
  38. nautobot/dcim/tables/template_code.py +2 -0
  39. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +1 -90
  40. nautobot/dcim/templates/dcim/inc/cable_toggle_buttons.html +1 -1
  41. nautobot/dcim/templates/dcim/interfaceredundancygroup_retrieve.html +1 -63
  42. nautobot/dcim/templates/dcim/location.html +2 -249
  43. nautobot/dcim/templates/dcim/location_edit.html +2 -38
  44. nautobot/dcim/templates/dcim/location_retrieve.html +249 -0
  45. nautobot/dcim/templates/dcim/location_update.html +38 -0
  46. nautobot/dcim/templates/dcim/module_update.html +1 -0
  47. nautobot/dcim/templates/dcim/modulebay_retrieve.html +93 -1
  48. nautobot/dcim/templates/dcim/modulefamily_retrieve.html +31 -0
  49. nautobot/dcim/templates/dcim/moduletype_retrieve.html +6 -0
  50. nautobot/dcim/templates/dcim/powerfeed_retrieve.html +1 -160
  51. nautobot/dcim/tests/test_api.py +35 -0
  52. nautobot/dcim/tests/test_filters.py +102 -3
  53. nautobot/dcim/tests/test_models.py +146 -0
  54. nautobot/dcim/tests/test_views.py +70 -97
  55. nautobot/dcim/urls.py +4 -22
  56. nautobot/dcim/views.py +439 -153
  57. nautobot/extras/api/views.py +9 -2
  58. nautobot/extras/datasources/git.py +11 -3
  59. nautobot/extras/forms/forms.py +9 -5
  60. nautobot/extras/jobs.py +4 -2
  61. nautobot/extras/models/datasources.py +5 -8
  62. nautobot/extras/models/jobs.py +5 -0
  63. nautobot/extras/plugins/__init__.py +3 -0
  64. nautobot/extras/tables.py +40 -3
  65. nautobot/extras/templates/extras/configcontext.html +2 -220
  66. nautobot/extras/templates/extras/configcontext_edit.html +2 -50
  67. nautobot/extras/templates/extras/configcontext_retrieve.html +2 -0
  68. nautobot/extras/templates/extras/configcontext_update.html +50 -0
  69. nautobot/extras/templates/extras/configcontextschema.html +2 -48
  70. nautobot/extras/templates/extras/configcontextschema_edit.html +2 -19
  71. nautobot/extras/templates/extras/configcontextschema_retrieve.html +48 -0
  72. nautobot/extras/templates/extras/configcontextschema_update.html +19 -0
  73. nautobot/extras/templates/extras/inc/configcontext_data.html +1 -0
  74. nautobot/extras/templates/extras/inc/json_data.html +1 -1
  75. nautobot/extras/templates/extras/inc/json_format.html +2 -2
  76. nautobot/extras/templates/extras/job_edit.html +12 -6
  77. nautobot/extras/templates/extras/tag.html +2 -52
  78. nautobot/extras/templates/extras/tag_edit.html +2 -15
  79. nautobot/extras/templates/extras/tag_retrieve.html +52 -0
  80. nautobot/extras/templates/extras/tag_update.html +15 -0
  81. nautobot/extras/templates/extras/team_retrieve.html +2 -2
  82. nautobot/extras/tests/test_api.py +15 -15
  83. nautobot/extras/tests/test_filters.py +4 -4
  84. nautobot/extras/tests/test_jobs.py +23 -10
  85. nautobot/extras/tests/test_models.py +19 -8
  86. nautobot/extras/tests/test_plugins.py +6 -3
  87. nautobot/extras/tests/test_views.py +66 -11
  88. nautobot/extras/urls.py +4 -134
  89. nautobot/extras/views.py +113 -158
  90. nautobot/ipam/models.py +19 -4
  91. nautobot/ipam/tables.py +19 -0
  92. nautobot/ipam/templates/ipam/vlan.html +2 -84
  93. nautobot/ipam/templates/ipam/vlan_edit.html +2 -24
  94. nautobot/ipam/templates/ipam/vlan_retrieve.html +84 -0
  95. nautobot/ipam/templates/ipam/vlan_update.html +24 -0
  96. nautobot/ipam/tests/test_views.py +5 -0
  97. nautobot/ipam/urls.py +1 -21
  98. nautobot/ipam/views.py +45 -70
  99. nautobot/project-static/docs/404.html +31 -8
  100. nautobot/project-static/docs/apps/index.html +31 -8
  101. nautobot/project-static/docs/apps/nautobot-apps.html +31 -8
  102. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +31 -8
  103. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +31 -8
  104. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +31 -8
  105. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +31 -8
  106. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +31 -8
  107. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +31 -8
  108. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +31 -8
  109. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +31 -8
  110. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +31 -8
  111. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +31 -8
  112. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +31 -8
  113. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +31 -8
  114. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +31 -8
  115. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +31 -8
  116. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +31 -8
  117. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +31 -8
  118. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +31 -8
  119. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +31 -8
  120. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +31 -8
  121. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +120 -8
  122. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +31 -8
  123. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +31 -8
  124. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +31 -8
  125. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +31 -8
  126. nautobot/project-static/docs/development/apps/api/configuration-view.html +31 -8
  127. nautobot/project-static/docs/development/apps/api/database-backend-config.html +31 -8
  128. nautobot/project-static/docs/development/apps/api/models/django-admin.html +31 -8
  129. nautobot/project-static/docs/development/apps/api/models/global-search.html +31 -8
  130. nautobot/project-static/docs/development/apps/api/models/graphql.html +31 -8
  131. nautobot/project-static/docs/development/apps/api/models/index.html +31 -8
  132. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +40 -8
  133. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +31 -8
  134. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +31 -8
  135. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +31 -8
  136. nautobot/project-static/docs/development/apps/api/platform-features/index.html +31 -8
  137. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +31 -8
  138. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +31 -8
  139. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +31 -8
  140. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +32 -9
  141. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +31 -8
  142. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +31 -8
  143. nautobot/project-static/docs/development/apps/api/prometheus.html +31 -8
  144. nautobot/project-static/docs/development/apps/api/setup.html +31 -8
  145. nautobot/project-static/docs/development/apps/api/testing.html +31 -8
  146. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +31 -8
  147. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +31 -8
  148. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +31 -8
  149. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +31 -8
  150. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +31 -8
  151. nautobot/project-static/docs/development/apps/api/views/base-template.html +31 -8
  152. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +31 -8
  153. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +31 -8
  154. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +31 -8
  155. nautobot/project-static/docs/development/apps/api/views/index.html +31 -8
  156. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +31 -8
  157. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +31 -8
  158. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +31 -8
  159. nautobot/project-static/docs/development/apps/api/views/notes.html +31 -8
  160. nautobot/project-static/docs/development/apps/api/views/rest-api.html +31 -8
  161. nautobot/project-static/docs/development/apps/api/views/urls.html +31 -8
  162. nautobot/project-static/docs/development/apps/index.html +31 -8
  163. nautobot/project-static/docs/development/apps/migration/code-updates.html +31 -8
  164. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +31 -8
  165. nautobot/project-static/docs/development/apps/migration/from-v1.html +31 -8
  166. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +31 -8
  167. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +31 -8
  168. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +31 -8
  169. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +31 -8
  170. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +31 -8
  171. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +31 -8
  172. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +31 -8
  173. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +31 -8
  174. nautobot/project-static/docs/development/apps/porting-from-netbox.html +31 -8
  175. nautobot/project-static/docs/development/core/application-registry.html +31 -8
  176. nautobot/project-static/docs/development/core/best-practices.html +31 -8
  177. nautobot/project-static/docs/development/core/bootstrap-ui.html +31 -8
  178. nautobot/project-static/docs/development/core/caching.html +31 -8
  179. nautobot/project-static/docs/development/core/controllers.html +31 -8
  180. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +31 -8
  181. nautobot/project-static/docs/development/core/generic-views.html +31 -8
  182. nautobot/project-static/docs/development/core/getting-started.html +31 -8
  183. nautobot/project-static/docs/development/core/homepage.html +31 -8
  184. nautobot/project-static/docs/development/core/index.html +31 -8
  185. nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +31 -8
  186. nautobot/project-static/docs/development/core/model-checklist.html +31 -8
  187. nautobot/project-static/docs/development/core/model-features.html +31 -8
  188. nautobot/project-static/docs/development/core/natural-keys.html +31 -8
  189. nautobot/project-static/docs/development/core/navigation-menu.html +31 -8
  190. nautobot/project-static/docs/development/core/release-checklist.html +31 -8
  191. nautobot/project-static/docs/development/core/role-internals.html +31 -8
  192. nautobot/project-static/docs/development/core/settings.html +31 -8
  193. nautobot/project-static/docs/development/core/style-guide.html +31 -8
  194. nautobot/project-static/docs/development/core/templates.html +31 -8
  195. nautobot/project-static/docs/development/core/testing.html +31 -8
  196. nautobot/project-static/docs/development/core/ui-component-framework.html +31 -8
  197. nautobot/project-static/docs/development/core/user-preferences.html +31 -8
  198. nautobot/project-static/docs/development/index.html +31 -8
  199. nautobot/project-static/docs/development/jobs/getting-started.html +35 -8
  200. nautobot/project-static/docs/development/jobs/index.html +31 -8
  201. nautobot/project-static/docs/development/jobs/installation.html +31 -8
  202. nautobot/project-static/docs/development/jobs/job-extensions.html +31 -8
  203. nautobot/project-static/docs/development/jobs/job-logging.html +31 -8
  204. nautobot/project-static/docs/development/jobs/job-patterns.html +31 -8
  205. nautobot/project-static/docs/development/jobs/job-structure.html +31 -8
  206. nautobot/project-static/docs/development/jobs/migration/from-v1.html +31 -8
  207. nautobot/project-static/docs/development/jobs/testing.html +31 -8
  208. nautobot/project-static/docs/index.html +31 -8
  209. nautobot/project-static/docs/insert-analytics.sh +36 -0
  210. nautobot/project-static/docs/objects.inv +0 -0
  211. nautobot/project-static/docs/overview/application_stack.html +31 -8
  212. nautobot/project-static/docs/overview/design_philosophy.html +31 -8
  213. nautobot/project-static/docs/release-notes/index.html +31 -8
  214. nautobot/project-static/docs/release-notes/version-1.0.html +31 -8
  215. nautobot/project-static/docs/release-notes/version-1.1.html +31 -8
  216. nautobot/project-static/docs/release-notes/version-1.2.html +31 -8
  217. nautobot/project-static/docs/release-notes/version-1.3.html +31 -8
  218. nautobot/project-static/docs/release-notes/version-1.4.html +31 -8
  219. nautobot/project-static/docs/release-notes/version-1.5.html +31 -8
  220. nautobot/project-static/docs/release-notes/version-1.6.html +31 -8
  221. nautobot/project-static/docs/release-notes/version-2.0.html +31 -8
  222. nautobot/project-static/docs/release-notes/version-2.1.html +31 -8
  223. nautobot/project-static/docs/release-notes/version-2.2.html +31 -8
  224. nautobot/project-static/docs/release-notes/version-2.3.html +31 -8
  225. nautobot/project-static/docs/release-notes/version-2.4.html +252 -8
  226. nautobot/project-static/docs/search/search_index.json +1 -1
  227. nautobot/project-static/docs/sitemap.xml +302 -298
  228. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  229. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +31 -8
  230. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +31 -8
  231. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +31 -8
  232. nautobot/project-static/docs/user-guide/administration/configuration/index.html +31 -8
  233. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +31 -8
  234. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +31 -8
  235. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +31 -8
  236. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +31 -8
  237. nautobot/project-static/docs/user-guide/administration/guides/docker.html +31 -8
  238. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +31 -8
  239. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +31 -8
  240. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +31 -8
  241. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +31 -8
  242. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +31 -8
  243. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +31 -8
  244. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +31 -8
  245. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +31 -8
  246. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +31 -8
  247. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +31 -8
  248. nautobot/project-static/docs/user-guide/administration/installation/index.html +31 -8
  249. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +31 -8
  250. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +31 -8
  251. nautobot/project-static/docs/user-guide/administration/installation/services.html +31 -8
  252. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +31 -8
  253. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +31 -8
  254. nautobot/project-static/docs/user-guide/administration/security/index.html +31 -8
  255. nautobot/project-static/docs/user-guide/administration/security/notices.html +31 -8
  256. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +31 -8
  257. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +31 -8
  258. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +31 -8
  259. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +31 -8
  260. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +31 -8
  261. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +31 -8
  262. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +31 -8
  263. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +31 -8
  264. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +31 -8
  265. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +31 -8
  266. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +31 -8
  267. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +31 -8
  268. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +31 -8
  269. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +31 -8
  270. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +31 -8
  271. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +31 -8
  272. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +31 -8
  273. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +31 -8
  274. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +31 -8
  275. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +31 -8
  276. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +31 -8
  277. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +31 -8
  278. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +31 -8
  279. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +31 -8
  280. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +31 -8
  281. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +31 -8
  282. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +31 -8
  283. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +31 -8
  284. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +31 -8
  285. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +31 -8
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +31 -8
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +31 -8
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +31 -8
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +31 -8
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +43 -20
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +31 -8
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +31 -8
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +31 -8
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +31 -8
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +31 -8
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +31 -8
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +31 -8
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +31 -8
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +31 -8
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +31 -8
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +35 -8
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +35 -8
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +35 -8
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +10261 -0
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +34 -11
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +31 -8
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +31 -8
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +31 -8
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +31 -8
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +31 -8
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +31 -8
  312. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +31 -8
  313. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +31 -8
  314. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +31 -8
  315. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +31 -8
  316. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +31 -8
  317. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +31 -8
  318. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +31 -8
  319. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +31 -8
  320. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +31 -8
  321. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +31 -8
  322. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +31 -8
  323. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +31 -8
  324. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +31 -8
  325. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +31 -8
  326. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +31 -8
  327. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +31 -8
  328. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +31 -8
  329. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +31 -8
  330. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +31 -8
  331. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +31 -8
  332. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +31 -8
  333. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +31 -8
  334. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +31 -8
  335. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +31 -8
  336. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +31 -8
  337. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +31 -8
  338. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +31 -8
  339. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +31 -8
  340. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +31 -8
  341. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +31 -8
  342. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +31 -8
  343. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +31 -8
  344. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +31 -8
  345. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +31 -8
  346. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +31 -8
  347. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +31 -8
  348. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +31 -8
  349. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +31 -8
  350. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +31 -8
  351. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +31 -8
  352. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +31 -8
  353. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +31 -8
  354. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +31 -8
  355. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +31 -8
  356. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +31 -8
  357. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +31 -8
  358. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +41 -15
  359. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +31 -8
  360. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +31 -8
  361. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +31 -8
  362. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +31 -8
  363. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +31 -8
  364. nautobot/project-static/docs/user-guide/index.html +31 -8
  365. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +31 -8
  366. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +31 -8
  367. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +31 -8
  368. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +31 -8
  369. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +31 -8
  370. nautobot/project-static/docs/user-guide/platform-functionality/events.html +31 -8
  371. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +31 -8
  372. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +31 -8
  373. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +37 -9
  374. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +31 -8
  375. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +31 -8
  376. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +31 -8
  377. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +31 -8
  378. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +31 -8
  379. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +31 -8
  380. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +31 -8
  381. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +31 -8
  382. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +31 -8
  383. nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +31 -8
  384. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +31 -8
  385. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +31 -8
  386. nautobot/project-static/docs/user-guide/platform-functionality/note.html +31 -8
  387. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +31 -8
  388. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +31 -8
  389. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +31 -8
  390. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +31 -8
  391. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +31 -8
  392. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +31 -8
  393. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +31 -8
  394. nautobot/project-static/docs/user-guide/platform-functionality/role.html +31 -8
  395. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +31 -8
  396. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +31 -8
  397. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +31 -8
  398. nautobot/project-static/docs/user-guide/platform-functionality/status.html +31 -8
  399. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +31 -8
  400. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +31 -8
  401. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +31 -8
  402. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +31 -8
  403. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +31 -8
  404. nautobot/tenancy/tables.py +2 -0
  405. nautobot/virtualization/tests/test_views.py +1 -1
  406. nautobot/wireless/forms.py +0 -1
  407. nautobot/wireless/models.py +1 -1
  408. nautobot/wireless/tables.py +7 -0
  409. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/METADATA +4 -4
  410. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/RECORD +416 -401
  411. /nautobot/dcim/templates/dcim/{platform_edit.html → platform_create.html} +0 -0
  412. /nautobot/extras/test_jobs/{pass.py → pass_job.py} +0 -0
  413. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/LICENSE.txt +0 -0
  414. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/NOTICE +0 -0
  415. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/WHEEL +0 -0
  416. {nautobot-2.4.10.dist-info → nautobot-2.4.11.dist-info}/entry_points.txt +0 -0
nautobot/extras/views.py CHANGED
@@ -2,6 +2,7 @@ import logging
2
2
  from typing import Optional
3
3
  from urllib.parse import parse_qs
4
4
 
5
+ from django.conf import settings
5
6
  from django.contrib import messages
6
7
  from django.contrib.contenttypes.models import ContentType
7
8
  from django.core.exceptions import ObjectDoesNotExist, ValidationError
@@ -15,7 +16,7 @@ from django.urls import reverse
15
16
  from django.urls.exceptions import NoReverseMatch
16
17
  from django.utils import timezone
17
18
  from django.utils.encoding import iri_to_uri
18
- from django.utils.html import format_html
19
+ from django.utils.html import format_html, format_html_join
19
20
  from django.utils.http import url_has_allowed_host_and_scheme
20
21
  from django.utils.timezone import get_current_timezone
21
22
  from django.views.generic import View
@@ -86,7 +87,6 @@ from .choices import (
86
87
  JobExecutionType,
87
88
  JobQueueTypeChoices,
88
89
  JobResultStatusChoices,
89
- LogLevelChoices,
90
90
  )
91
91
  from .datasources import (
92
92
  enqueue_git_repository_diff_origin_and_local,
@@ -111,7 +111,6 @@ from .models import (
111
111
  Job as JobModel,
112
112
  JobButton,
113
113
  JobHook,
114
- JobLogEntry,
115
114
  JobQueue,
116
115
  JobResult,
117
116
  MetadataType,
@@ -180,55 +179,89 @@ class ComputedFieldUIViewSet(NautobotUIViewSet):
180
179
  # have an associated owner, such as a Git repository
181
180
 
182
181
 
183
- class ConfigContextListView(generic.ObjectListView):
182
+ class ConfigContextUIViewSet(NautobotUIViewSet):
183
+ bulk_update_form_class = forms.ConfigContextBulkEditForm
184
+ filterset_class = filters.ConfigContextFilterSet
185
+ filterset_form_class = forms.ConfigContextFilterForm
186
+ form_class = forms.ConfigContextForm
184
187
  queryset = ConfigContext.objects.all()
185
- filterset = filters.ConfigContextFilterSet
186
- filterset_form = forms.ConfigContextFilterForm
187
- table = tables.ConfigContextTable
188
- action_buttons = ("add",)
188
+ serializer_class = serializers.ConfigContextSerializer
189
+ table_class = tables.ConfigContextTable
189
190
 
191
+ class AssignmentObjectFieldsPanel(object_detail.ObjectFieldsPanel):
192
+ def render_value(self, key, value, context):
193
+ if key == "dynamic_groups" and not settings.CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED:
194
+ return None
195
+ if not value:
196
+ return helpers.HTML_NONE
190
197
 
191
- class ConfigContextView(generic.ObjectView):
192
- queryset = ConfigContext.objects.all()
198
+ items = []
199
+ for val in value.all():
200
+ rendered_val = helpers.hyperlinked_object(val)
201
+ items.append(rendered_val)
202
+
203
+ if not items:
204
+ return helpers.HTML_NONE
205
+
206
+ return format_html("<ul>{}</ul>", format_html_join("", "<li>{}</li>", ((item,) for item in items)))
207
+
208
+ object_detail_content = object_detail.ObjectDetailContent(
209
+ panels=(
210
+ object_detail.ObjectFieldsPanel(
211
+ weight=100,
212
+ section=SectionChoices.LEFT_HALF,
213
+ fields="__all__",
214
+ exclude_fields=[
215
+ "data",
216
+ "owner_content_type",
217
+ "owner_object_id",
218
+ ],
219
+ hide_if_unset=[
220
+ "owner",
221
+ ],
222
+ ),
223
+ object_detail.Panel(
224
+ weight=100,
225
+ section=SectionChoices.FULL_WIDTH,
226
+ label="Data",
227
+ header_extra_content_template_path="extras/inc/json_format.html",
228
+ body_content_template_path="extras/inc/configcontext_data.html",
229
+ ),
230
+ AssignmentObjectFieldsPanel(
231
+ weight=200,
232
+ section=SectionChoices.RIGHT_HALF,
233
+ label="Assignment",
234
+ fields=[
235
+ "locations",
236
+ "roles",
237
+ "device_types",
238
+ "platforms",
239
+ "cluster_groups",
240
+ "clusters",
241
+ "tenant_groups",
242
+ "tenants",
243
+ "device_redundancy_groups",
244
+ "dynamic_groups",
245
+ ],
246
+ ),
247
+ )
248
+ )
193
249
 
194
250
  def get_extra_context(self, request, instance):
195
251
  context = super().get_extra_context(request, instance)
196
252
  # Determine user's preferred output format
197
- if request.GET.get("format") in ["json", "yaml"]:
198
- context["format"] = request.GET.get("format")
253
+ if request.GET.get("data_format") in ["json", "yaml"]:
254
+ context["data_format"] = request.GET.get("data_format")
199
255
  if request.user.is_authenticated:
200
- request.user.set_config("extras.configcontext.format", context["format"], commit=True)
256
+ request.user.set_config("extras.configcontext.format", context["data_format"], commit=True)
201
257
  elif request.user.is_authenticated:
202
- context["format"] = request.user.get_config("extras.configcontext.format", "json")
258
+ context["data_format"] = request.user.get_config("extras.configcontext.format", "json")
203
259
  else:
204
- context["format"] = "json"
260
+ context["data_format"] = "json"
205
261
 
206
262
  return context
207
263
 
208
264
 
209
- class ConfigContextEditView(generic.ObjectEditView):
210
- queryset = ConfigContext.objects.all()
211
- model_form = forms.ConfigContextForm
212
- template_name = "extras/configcontext_edit.html"
213
-
214
-
215
- class ConfigContextBulkEditView(generic.BulkEditView):
216
- queryset = ConfigContext.objects.all()
217
- filterset = filters.ConfigContextFilterSet
218
- table = tables.ConfigContextTable
219
- form = forms.ConfigContextBulkEditForm
220
-
221
-
222
- class ConfigContextDeleteView(generic.ObjectDeleteView):
223
- queryset = ConfigContext.objects.all()
224
-
225
-
226
- class ConfigContextBulkDeleteView(generic.BulkDeleteView):
227
- queryset = ConfigContext.objects.all()
228
- table = tables.ConfigContextTable
229
- filterset = filters.ConfigContextFilterSet
230
-
231
-
232
265
  class ObjectConfigContextView(generic.ObjectView):
233
266
  base_template = None
234
267
  template_name = "extras/object_configcontext.html"
@@ -263,28 +296,26 @@ class ObjectConfigContextView(generic.ObjectView):
263
296
  # have an associated owner, such as a Git repository
264
297
 
265
298
 
266
- class ConfigContextSchemaListView(generic.ObjectListView):
267
- queryset = ConfigContextSchema.objects.all()
268
- filterset = filters.ConfigContextSchemaFilterSet
269
- filterset_form = forms.ConfigContextSchemaFilterForm
270
- table = tables.ConfigContextSchemaTable
271
- action_buttons = ("add",)
272
-
273
-
274
- class ConfigContextSchemaView(generic.ObjectView):
299
+ class ConfigContextSchemaUIViewSet(NautobotUIViewSet):
300
+ bulk_update_form_class = forms.ConfigContextSchemaBulkEditForm
301
+ filterset_class = filters.ConfigContextSchemaFilterSet
302
+ filterset_form_class = forms.ConfigContextSchemaFilterForm
303
+ form_class = forms.ConfigContextSchemaForm
275
304
  queryset = ConfigContextSchema.objects.all()
305
+ serializer_class = serializers.ConfigContextSchemaSerializer
306
+ table_class = tables.ConfigContextSchemaTable
276
307
 
277
308
  def get_extra_context(self, request, instance):
278
309
  context = super().get_extra_context(request, instance)
279
310
  # Determine user's preferred output format
280
- if request.GET.get("format") in ["json", "yaml"]:
281
- context["format"] = request.GET.get("format")
311
+ if request.GET.get("data_format") in ["json", "yaml"]:
312
+ context["data_format"] = request.GET.get("data_format")
282
313
  if request.user.is_authenticated:
283
- request.user.set_config("extras.configcontextschema.format", context["format"], commit=True)
314
+ request.user.set_config("extras.configcontextschema.format", context["data_format"], commit=True)
284
315
  elif request.user.is_authenticated:
285
- context["format"] = request.user.get_config("extras.configcontextschema.format", "json")
316
+ context["data_format"] = request.user.get_config("extras.configcontextschema.format", "json")
286
317
  else:
287
- context["format"] = "json"
318
+ context["data_format"] = "json"
288
319
 
289
320
  return context
290
321
 
@@ -372,29 +403,6 @@ class ConfigContextSchemaObjectValidationView(generic.ObjectView):
372
403
  }
373
404
 
374
405
 
375
- class ConfigContextSchemaEditView(generic.ObjectEditView):
376
- queryset = ConfigContextSchema.objects.all()
377
- model_form = forms.ConfigContextSchemaForm
378
- template_name = "extras/configcontextschema_edit.html"
379
-
380
-
381
- class ConfigContextSchemaBulkEditView(generic.BulkEditView):
382
- queryset = ConfigContextSchema.objects.all()
383
- filterset = filters.ConfigContextSchemaFilterSet
384
- table = tables.ConfigContextSchemaTable
385
- form = forms.ConfigContextSchemaBulkEditForm
386
-
387
-
388
- class ConfigContextSchemaDeleteView(generic.ObjectDeleteView):
389
- queryset = ConfigContextSchema.objects.all()
390
-
391
-
392
- class ConfigContextSchemaBulkDeleteView(generic.BulkDeleteView):
393
- queryset = ConfigContextSchema.objects.all()
394
- table = tables.ConfigContextSchemaTable
395
- filterset = filters.ConfigContextSchemaFilterSet
396
-
397
-
398
406
  #
399
407
  # Contacts
400
408
  #
@@ -1553,6 +1561,11 @@ class JobEditView(generic.ObjectEditView):
1553
1561
  model_form = forms.JobEditForm
1554
1562
  template_name = "extras/job_edit.html"
1555
1563
 
1564
+ def alter_obj(self, obj, request, url_args, url_kwargs):
1565
+ # Reload the job class to ensure we have the latest version
1566
+ get_job(obj.class_path, reload=True)
1567
+ return obj
1568
+
1556
1569
 
1557
1570
  class JobBulkEditView(generic.BulkEditView):
1558
1571
  queryset = JobModel.objects.all()
@@ -2077,44 +2090,12 @@ class JobHookUIViewSet(NautobotUIViewSet):
2077
2090
  #
2078
2091
 
2079
2092
 
2080
- def get_annotated_jobresult_queryset():
2081
- return (
2082
- JobResult.objects.defer("result")
2083
- .select_related("job_model", "user")
2084
- .annotate(
2085
- debug_log_count=count_related(
2086
- JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_DEBUG}
2087
- ),
2088
- success_log_count=count_related(
2089
- JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_SUCCESS}
2090
- ),
2091
- info_log_count=count_related(
2092
- JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_INFO}
2093
- ),
2094
- warning_log_count=count_related(
2095
- JobLogEntry, "job_result", filter_dict={"log_level": LogLevelChoices.LOG_WARNING}
2096
- ),
2097
- error_log_count=count_related(
2098
- JobLogEntry,
2099
- "job_result",
2100
- filter_dict={
2101
- "log_level__in": [
2102
- LogLevelChoices.LOG_FAILURE,
2103
- LogLevelChoices.LOG_ERROR,
2104
- LogLevelChoices.LOG_CRITICAL,
2105
- ],
2106
- },
2107
- ),
2108
- )
2109
- )
2110
-
2111
-
2112
2093
  class JobResultListView(generic.ObjectListView):
2113
2094
  """
2114
2095
  List JobResults
2115
2096
  """
2116
2097
 
2117
- queryset = get_annotated_jobresult_queryset()
2098
+ queryset = JobResult.objects.defer("result").select_related("job_model", "user")
2118
2099
  filterset = filters.JobResultFilterSet
2119
2100
  filterset_form = forms.JobResultFilterForm
2120
2101
  table = tables.JobResultTable
@@ -2126,7 +2107,7 @@ class JobResultDeleteView(generic.ObjectDeleteView):
2126
2107
 
2127
2108
 
2128
2109
  class JobResultBulkDeleteView(generic.BulkDeleteView):
2129
- queryset = get_annotated_jobresult_queryset()
2110
+ queryset = JobResult.objects.defer("result").select_related("job_model", "user")
2130
2111
  table = tables.JobResultTable
2131
2112
  filterset = filters.JobResultFilterSet
2132
2113
 
@@ -2519,24 +2500,15 @@ class RelationshipUIViewSet(NautobotUIViewSet):
2519
2500
  )
2520
2501
 
2521
2502
 
2522
- class RelationshipAssociationListView(generic.ObjectListView):
2503
+ class RelationshipAssociationUIViewSet(ObjectListViewMixin, ObjectDestroyViewMixin, ObjectBulkDestroyViewMixin):
2504
+ filterset_class = filters.RelationshipAssociationFilterSet
2505
+ filterset_form_class = forms.RelationshipAssociationFilterForm
2506
+ serializer_class = serializers.RelationshipAssociationSerializer
2507
+ table_class = tables.RelationshipAssociationTable
2523
2508
  queryset = RelationshipAssociation.objects.all()
2524
- filterset = filters.RelationshipAssociationFilterSet
2525
- filterset_form = forms.RelationshipAssociationFilterForm
2526
- table = tables.RelationshipAssociationTable
2527
2509
  action_buttons = ()
2528
2510
 
2529
2511
 
2530
- class RelationshipAssociationBulkDeleteView(generic.BulkDeleteView):
2531
- queryset = RelationshipAssociation.objects.all()
2532
- table = tables.RelationshipAssociationTable
2533
- filterset = filters.RelationshipAssociationFilterSet
2534
-
2535
-
2536
- class RelationshipAssociationDeleteView(generic.ObjectDeleteView):
2537
- queryset = RelationshipAssociation.objects.all()
2538
-
2539
-
2540
2512
  #
2541
2513
  # Roles
2542
2514
  #
@@ -3005,17 +2977,28 @@ class StatusUIViewSet(NautobotUIViewSet):
3005
2977
  #
3006
2978
 
3007
2979
 
3008
- class TagListView(generic.ObjectListView):
3009
- queryset = Tag.objects.annotate(items=count_related(TaggedItem, "tag"))
3010
- filterset = filters.TagFilterSet
3011
- filterset_form = forms.TagFilterForm
3012
- table = tables.TagTable
2980
+ class TagUIViewSet(NautobotUIViewSet):
2981
+ bulk_update_form_class = forms.TagBulkEditForm
2982
+ filterset_class = filters.TagFilterSet
2983
+ filterset_form_class = forms.TagFilterForm
2984
+ form_class = forms.TagForm
2985
+ queryset = Tag.objects.all()
2986
+ serializer_class = serializers.TagSerializer
2987
+ table_class = tables.TagTable
2988
+
2989
+ def alter_queryset(self, request):
2990
+ queryset = super().alter_queryset(request)
3013
2991
 
2992
+ # Only annotate for list, bulk_edit, bulk_delete views
2993
+ if self.action in ["list", "bulk_update", "bulk_destroy"]:
2994
+ queryset = queryset.annotate(items=count_related(TaggedItem, "tag"))
3014
2995
 
3015
- class TagView(generic.ObjectView):
3016
- queryset = Tag.objects.all()
2996
+ return queryset
3017
2997
 
3018
2998
  def get_extra_context(self, request, instance):
2999
+ # Only run this logic when retrieving a single object
3000
+ if instance is None or self.action != "retrieve":
3001
+ return super().get_extra_context(request, instance)
3019
3002
  tagged_items = (
3020
3003
  TaggedItem.objects.filter(tag=instance).select_related("content_type").prefetch_related("content_object")
3021
3004
  )
@@ -3036,34 +3019,6 @@ class TagView(generic.ObjectView):
3036
3019
  }
3037
3020
 
3038
3021
 
3039
- class TagEditView(generic.ObjectEditView):
3040
- queryset = Tag.objects.all()
3041
- model_form = forms.TagForm
3042
- template_name = "extras/tag_edit.html"
3043
-
3044
-
3045
- class TagDeleteView(generic.ObjectDeleteView):
3046
- queryset = Tag.objects.all()
3047
-
3048
-
3049
- class TagBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
3050
- queryset = Tag.objects.all()
3051
- table = tables.TagTable
3052
-
3053
-
3054
- class TagBulkEditView(generic.BulkEditView):
3055
- queryset = Tag.objects.annotate(items=count_related(TaggedItem, "tag"))
3056
- table = tables.TagTable
3057
- form = forms.TagBulkEditForm
3058
- filterset = filters.TagFilterSet
3059
-
3060
-
3061
- class TagBulkDeleteView(generic.BulkDeleteView):
3062
- queryset = Tag.objects.annotate(items=count_related(TaggedItem, "tag"))
3063
- table = tables.TagTable
3064
- filterset = filters.TagFilterSet
3065
-
3066
-
3067
3022
  #
3068
3023
  # Teams
3069
3024
  #
nautobot/ipam/models.py CHANGED
@@ -889,7 +889,7 @@ class Prefix(PrimaryModel):
889
889
  prefix_length__lte=self.prefix_length,
890
890
  network__lte=self.network,
891
891
  broadcast__gte=self.broadcast,
892
- namespace=self.namespace,
892
+ namespace_id=self.namespace_id,
893
893
  )
894
894
 
895
895
  return supernets
@@ -921,7 +921,7 @@ class Prefix(PrimaryModel):
921
921
  ip_version=self.ip_version,
922
922
  network__gte=self.network,
923
923
  broadcast__lte=self.broadcast,
924
- namespace=self.namespace,
924
+ namespace_id=self.namespace_id,
925
925
  )
926
926
 
927
927
  def is_child_node(self):
@@ -1093,6 +1093,17 @@ class Prefix(PrimaryModel):
1093
1093
  For prefixes containing IP addresses and/or pools, pools are considered fully utilized while
1094
1094
  only IP addresses that are not contained within pools are added to the utilization.
1095
1095
 
1096
+ It is recommended that when using this method you add the following prefetch to the queryset when dealing with
1097
+ multiple prefixes to ensure good performance:
1098
+
1099
+ ```
1100
+ prefetch_related(
1101
+ Prefetch(
1102
+ "children", queryset=Prefix.objects.only("network", "prefix_length", "parent_id").order_by()
1103
+ )
1104
+ )
1105
+ ```
1106
+
1096
1107
  Returns:
1097
1108
  UtilizationData (namedtuple): (numerator, denominator)
1098
1109
  """
@@ -1105,7 +1116,7 @@ class Prefix(PrimaryModel):
1105
1116
  # change this when that is the case, see #3873 for historical context.
1106
1117
  if self.type != choices.PrefixTypeChoices.TYPE_CONTAINER:
1107
1118
  pool_ips = IPAddress.objects.filter(
1108
- parent__namespace=self.namespace,
1119
+ parent__namespace_id=self.namespace_id,
1109
1120
  ip_version=self.ip_version,
1110
1121
  host__gte=self.network,
1111
1122
  host__lte=self.broadcast,
@@ -1113,7 +1124,11 @@ class Prefix(PrimaryModel):
1113
1124
  child_ips = netaddr.IPSet(pool_ips)
1114
1125
 
1115
1126
  if self.type != choices.PrefixTypeChoices.TYPE_POOL:
1116
- child_prefixes = netaddr.IPSet(p.prefix for p in self.children.only("network", "prefix_length").iterator())
1127
+ # Using self.children.all over self.children.iterator (with chunk_size given or not) consistently shaves
1128
+ # off around 200 extra SQL queries and shows better performance.
1129
+ # Also note that this is meant to be used in conjunction with a Prefetch on an only query. This query is
1130
+ # performed in nautobot.ipam.tables.PrefixDetailTable.
1131
+ child_prefixes = netaddr.IPSet(p.prefix for p in self.children.all())
1117
1132
 
1118
1133
  numerator_set = child_ips | child_prefixes
1119
1134
 
nautobot/ipam/tables.py CHANGED
@@ -1,5 +1,8 @@
1
+ from django.db.models import Prefetch, QuerySet
1
2
  from django.utils.safestring import mark_safe
2
3
  import django_tables2 as tables
4
+ from django_tables2.data import TableData
5
+ from django_tables2.rows import BoundRows
3
6
  from django_tables2.utils import Accessor
4
7
 
5
8
  from nautobot.core.tables import (
@@ -47,7 +50,9 @@ UTILIZATION_GRAPH = """
47
50
  # object: the base ancestor Prefix, in the case of PrefixDetailTable, else None
48
51
  PREFIX_COPY_LINK = """
49
52
  {% load helpers %}
53
+ {% if not table.hide_hierarchy_ui %}
50
54
  {% tree_hierarchy_ui_representation record.ancestors.count|as_range table.hide_hierarchy_ui base_tree_depth|default:0 %}
55
+ {% endif %}
51
56
  <span class="hover_copy">
52
57
  <a href="\
53
58
  {% if record.present_in_database %}\
@@ -418,6 +423,20 @@ class PrefixDetailTable(PrefixTable):
418
423
  tenant = TenantColumn()
419
424
  tags = TagColumn(url_name="ipam:prefix_list")
420
425
 
426
+ def __init__(self, *args, **kwargs):
427
+ super().__init__(*args, **kwargs)
428
+ # Conditionally prefetch children for the utilization calculation if that column is visible.
429
+ if self.columns["utilization"].visible and isinstance(self.data.data, QuerySet):
430
+ self.data = TableData.from_data(
431
+ self.data.data.prefetch_related(
432
+ Prefetch(
433
+ "children", queryset=Prefix.objects.only("network", "prefix_length", "parent_id").order_by()
434
+ )
435
+ )
436
+ )
437
+ self.data.set_table(self)
438
+ self.rows = BoundRows(data=self.data, table=self, pinned_data=self.pinned_data)
439
+
421
440
  class Meta(PrefixTable.Meta):
422
441
  fields = (
423
442
  "pk",
@@ -1,84 +1,2 @@
1
- {% extends 'generic/object_retrieve.html' %}
2
- {% load helpers %}
3
-
4
- {% block extra_breadcrumbs %}
5
- {% if object.vlan_group %}
6
- <li><a href="{% url 'ipam:vlan_list' %}?vlan_group={{ object.vlan_group.name }}">{{ object.vlan_group }}</a></li>
7
- {% endif %}
8
- {% endblock extra_breadcrumbs %}
9
-
10
- {% block extra_nav_tabs %}
11
- <li role="presentation"{% if active_tab == 'interfaces' %} class="active"{% endif %}>
12
- <a href="{% url 'ipam:vlan_interfaces' pk=object.pk %}">Device Interfaces <span class="badge">{{ object.get_interfaces.count }}</span></a>
13
- </li>
14
- <li role="presentation"{% if active_tab == 'vminterfaces' %} class="active"{% endif %}>
15
- <a href="{% url 'ipam:vlan_vminterfaces' pk=object.pk %}">VM Interfaces <span class="badge">{{ object.get_vminterfaces.count }}</span></a>
16
- </li>
17
- {% endblock extra_nav_tabs %}
18
-
19
- {% block content_left_page %}
20
- <div class="panel panel-default">
21
- <div class="panel-heading">
22
- <strong>VLAN</strong>
23
- </div>
24
- <table class="table table-hover panel-body attr-table">
25
- <tr>
26
- <td>Locations</td>
27
- <td>
28
- {% for location in object.locations.all %}
29
- {{ location|hyperlinked_object }}<br>
30
- {% empty %}
31
- <span class="text-muted">None</span>
32
- {% endfor %}
33
- </td>
34
- </tr>
35
- <tr>
36
- <td>VLAN Group</td>
37
- <td>{{ object.vlan_group|hyperlinked_object }}</td>
38
- </tr>
39
- <tr>
40
- <td>VLAN ID</td>
41
- <td>{{ object.vid }}</td>
42
- </tr>
43
- <tr>
44
- <td>Name</td>
45
- <td>{{ object.name }}</td>
46
- </tr>
47
- {% include 'inc/tenant_table_row.html' %}
48
- <tr>
49
- <td>Status</td>
50
- <td>
51
- {{ object.status| hyperlinked_object_with_color }}
52
- </td>
53
- </tr>
54
- <tr>
55
- <td>Role</td>
56
- <td>{{ object.role | hyperlinked_object_with_color }}</td>
57
- </tr>
58
- <tr>
59
- <td>Description</td>
60
- <td>{{ object.description|placeholder }}</td>
61
- </tr>
62
- </table>
63
- </div>
64
- {% endblock content_left_page %}
65
-
66
- {% block content_full_width_page %}
67
- <div class="panel panel-default">
68
- <div class="panel-heading">
69
- <strong>Prefixes</strong>
70
- </div>
71
- {% include 'responsive_table.html' with table=prefix_table %}
72
- {% if perms.ipam.add_prefix %}
73
- <div class="panel-footer text-right noprint">
74
- <a href="{% url 'ipam:prefix_add' %}?{% if object.tenant %}tenant={{ object.tenant.pk }}{% endif %}&vlan={{ object.pk }}{% for loc in object.locations.all %}&locations={{ loc.pk }}{% endfor %}" class="btn btn-primary btn-xs">
75
- <span class="mdi mdi-plus-thick" aria-hidden="true"></span>
76
- Add a prefix
77
- </a>
78
- </div>
79
- {% endif %}
80
- </div>
81
- {% if prefix_table.paginator.num_pages > 1 %}
82
- {% include "inc/paginator.html" with paginator=prefix_table.paginator page=prefix_table.page %}
83
- {% endif %}
84
- {% endblock content_full_width_page %}
1
+ {% extends 'ipam/vlan_retrieve.html' %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}
@@ -1,24 +1,2 @@
1
- {% extends 'generic/object_create.html' %}
2
- {% load form_helpers %}
3
-
4
- {% block form %}
5
- <div class="panel panel-default">
6
- <div class="panel-heading"><strong>VLAN</strong></div>
7
- <div class="panel-body">
8
- {% render_field form.vid %}
9
- {% render_field form.name %}
10
- {% render_field form.status %}
11
- {% render_field form.role %}
12
- {% render_field form.description %}
13
- </div>
14
- </div>
15
- <div class="panel panel-default">
16
- <div class="panel-heading"><strong>Assignment</strong></div>
17
- <div class="panel-body">
18
- {% render_field form.locations %}
19
- {% render_field form.vlan_group %}
20
- </div>
21
- </div>
22
- {% include 'inc/tenancy_form_panel.html' %}
23
- {% include 'inc/extras_features_edit_form_fields.html' %}
24
- {% endblock %}
1
+ {% extends 'ipam/vlan_update.html' %}
2
+ {% comment %}3.0 TODO: remove this template, which only exists for backward compatibility with 2.4 and earlier{% endcomment %}