nautobot 2.4.0b1__py3-none-any.whl → 2.4.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 (601) hide show
  1. nautobot/apps/__init__.py +1 -1
  2. nautobot/apps/api.py +8 -8
  3. nautobot/apps/change_logging.py +2 -2
  4. nautobot/apps/choices.py +4 -4
  5. nautobot/apps/events.py +3 -3
  6. nautobot/apps/factory.py +2 -2
  7. nautobot/apps/filters.py +1 -1
  8. nautobot/apps/forms.py +20 -20
  9. nautobot/apps/graphql.py +2 -2
  10. nautobot/apps/jobs.py +8 -8
  11. nautobot/apps/models.py +19 -19
  12. nautobot/apps/tables.py +1 -1
  13. nautobot/apps/testing.py +10 -10
  14. nautobot/apps/ui.py +2 -2
  15. nautobot/apps/utils.py +7 -7
  16. nautobot/apps/views.py +7 -7
  17. nautobot/circuits/api/serializers.py +1 -0
  18. nautobot/circuits/api/views.py +4 -8
  19. nautobot/circuits/tables.py +2 -1
  20. nautobot/circuits/templates/circuits/circuit_create.html +1 -7
  21. nautobot/circuits/views.py +3 -3
  22. nautobot/cloud/api/views.py +6 -10
  23. nautobot/cloud/models.py +1 -1
  24. nautobot/cloud/views.py +0 -16
  25. nautobot/core/api/constants.py +11 -0
  26. nautobot/core/api/fields.py +5 -5
  27. nautobot/core/api/filter_backends.py +3 -9
  28. nautobot/core/api/schema.py +13 -2
  29. nautobot/core/api/serializers.py +40 -34
  30. nautobot/core/api/views.py +56 -4
  31. nautobot/core/celery/log.py +4 -4
  32. nautobot/core/celery/schedulers.py +2 -2
  33. nautobot/core/choices.py +2 -2
  34. nautobot/core/events/__init__.py +3 -3
  35. nautobot/core/filters.py +67 -35
  36. nautobot/core/forms/__init__.py +19 -19
  37. nautobot/core/forms/fields.py +14 -11
  38. nautobot/core/forms/forms.py +33 -2
  39. nautobot/core/graphql/types.py +1 -1
  40. nautobot/core/jobs/__init__.py +28 -7
  41. nautobot/core/jobs/bulk_actions.py +285 -0
  42. nautobot/core/jobs/cleanup.py +48 -12
  43. nautobot/core/jobs/groups.py +1 -1
  44. nautobot/core/management/commands/validate_models.py +1 -1
  45. nautobot/core/models/__init__.py +3 -1
  46. nautobot/core/models/query_functions.py +2 -2
  47. nautobot/core/models/tree_queries.py +6 -3
  48. nautobot/core/settings.py +29 -2
  49. nautobot/core/settings.yaml +21 -0
  50. nautobot/core/tables.py +79 -61
  51. nautobot/core/templates/about.html +67 -0
  52. nautobot/core/templates/inc/media.html +3 -0
  53. nautobot/core/templates/inc/nav_menu.html +1 -0
  54. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  55. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  56. nautobot/core/templates/nautobot_config.py.j2 +13 -0
  57. nautobot/core/templates/search.html +7 -0
  58. nautobot/core/templates/utilities/render_jinja2.html +1 -1
  59. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  60. nautobot/core/templates/utilities/theme_preview.html +7 -0
  61. nautobot/core/templatetags/helpers.py +11 -2
  62. nautobot/core/testing/__init__.py +8 -8
  63. nautobot/core/testing/api.py +170 -15
  64. nautobot/core/testing/filters.py +45 -10
  65. nautobot/core/testing/forms.py +2 -0
  66. nautobot/core/testing/integration.py +86 -4
  67. nautobot/core/testing/mixins.py +7 -2
  68. nautobot/core/testing/views.py +44 -29
  69. nautobot/core/tests/integration/test_app_home.py +0 -1
  70. nautobot/core/tests/integration/test_app_navbar.py +0 -1
  71. nautobot/core/tests/integration/test_filters.py +0 -2
  72. nautobot/core/tests/integration/test_home.py +0 -1
  73. nautobot/core/tests/integration/test_navbar.py +0 -1
  74. nautobot/core/tests/integration/test_view_authentication.py +1 -0
  75. nautobot/core/tests/runner.py +1 -1
  76. nautobot/core/tests/test_api.py +98 -1
  77. nautobot/core/tests/test_csv.py +25 -3
  78. nautobot/core/tests/test_filters.py +209 -246
  79. nautobot/core/tests/test_forms.py +1 -0
  80. nautobot/core/tests/test_jobs.py +460 -1
  81. nautobot/core/tests/test_models.py +9 -0
  82. nautobot/core/tests/test_settings_schema.py +7 -0
  83. nautobot/core/tests/test_tables.py +100 -0
  84. nautobot/core/tests/test_utils.py +63 -1
  85. nautobot/core/tests/test_views.py +30 -3
  86. nautobot/core/ui/nav.py +1 -0
  87. nautobot/core/ui/object_detail.py +15 -1
  88. nautobot/core/urls.py +11 -0
  89. nautobot/core/utils/lookup.py +11 -8
  90. nautobot/core/utils/querysets.py +64 -0
  91. nautobot/core/utils/requests.py +24 -9
  92. nautobot/core/views/__init__.py +42 -0
  93. nautobot/core/views/generic.py +131 -197
  94. nautobot/core/views/mixins.py +126 -38
  95. nautobot/core/views/renderers.py +6 -6
  96. nautobot/dcim/api/serializers.py +56 -64
  97. nautobot/dcim/api/views.py +47 -113
  98. nautobot/dcim/constants.py +6 -13
  99. nautobot/dcim/factory.py +6 -1
  100. nautobot/dcim/filters/__init__.py +31 -2
  101. nautobot/dcim/forms.py +36 -17
  102. nautobot/dcim/graphql/types.py +2 -2
  103. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  104. nautobot/dcim/models/__init__.py +1 -1
  105. nautobot/dcim/models/device_component_templates.py +2 -2
  106. nautobot/dcim/models/device_components.py +22 -20
  107. nautobot/dcim/models/devices.py +10 -1
  108. nautobot/dcim/models/locations.py +3 -3
  109. nautobot/dcim/models/power.py +6 -5
  110. nautobot/dcim/models/racks.py +4 -4
  111. nautobot/dcim/tables/__init__.py +3 -3
  112. nautobot/dcim/tables/devices.py +7 -5
  113. nautobot/dcim/tables/devicetypes.py +2 -2
  114. nautobot/dcim/tables/racks.py +1 -1
  115. nautobot/dcim/templates/dcim/controller_create.html +1 -7
  116. nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
  117. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
  118. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
  119. nautobot/dcim/templates/dcim/device.html +1 -9
  120. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  121. nautobot/dcim/templates/dcim/location.html +1 -9
  122. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  123. nautobot/dcim/templates/dcim/rack.html +1 -9
  124. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  125. nautobot/dcim/templates/dcim/rackreservation.html +1 -9
  126. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
  127. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
  128. nautobot/dcim/tests/integration/test_controller.py +62 -0
  129. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  130. nautobot/dcim/tests/integration/test_device_bulk_delete.py +189 -0
  131. nautobot/dcim/tests/integration/test_device_bulk_edit.py +181 -0
  132. nautobot/dcim/tests/test_api.py +16 -5
  133. nautobot/dcim/tests/test_filters.py +33 -0
  134. nautobot/dcim/tests/test_forms.py +51 -2
  135. nautobot/dcim/tests/test_graphql.py +52 -0
  136. nautobot/dcim/tests/test_jobs.py +118 -0
  137. nautobot/dcim/tests/test_models.py +52 -9
  138. nautobot/dcim/tests/test_views.py +21 -83
  139. nautobot/dcim/views.py +1 -13
  140. nautobot/extras/api/customfields.py +2 -2
  141. nautobot/extras/api/serializers.py +90 -85
  142. nautobot/extras/api/views.py +22 -27
  143. nautobot/extras/constants.py +2 -0
  144. nautobot/extras/filters/__init__.py +8 -6
  145. nautobot/extras/forms/base.py +2 -2
  146. nautobot/extras/forms/forms.py +139 -31
  147. nautobot/extras/forms/mixins.py +14 -6
  148. nautobot/extras/group_sync.py +3 -3
  149. nautobot/extras/health_checks.py +1 -2
  150. nautobot/extras/jobs.py +85 -18
  151. nautobot/extras/managers.py +3 -1
  152. nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
  153. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  154. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  155. nautobot/extras/models/__init__.py +1 -1
  156. nautobot/extras/models/contacts.py +1 -1
  157. nautobot/extras/models/customfields.py +12 -11
  158. nautobot/extras/models/groups.py +11 -9
  159. nautobot/extras/models/jobs.py +23 -4
  160. nautobot/extras/models/models.py +2 -2
  161. nautobot/extras/plugins/__init__.py +13 -2
  162. nautobot/extras/plugins/marketplace_manifest.yml +84 -79
  163. nautobot/extras/plugins/tables.py +16 -14
  164. nautobot/extras/plugins/views.py +65 -69
  165. nautobot/extras/registry.py +1 -1
  166. nautobot/extras/secrets/__init__.py +2 -2
  167. nautobot/extras/tables.py +7 -5
  168. nautobot/extras/templates/extras/dynamicgroup.html +1 -9
  169. nautobot/extras/templates/extras/job_detail.html +16 -0
  170. nautobot/extras/templates/extras/job_edit.html +1 -0
  171. nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
  172. nautobot/extras/templates/extras/marketplace.html +29 -11
  173. nautobot/extras/templates/extras/plugin_detail.html +32 -15
  174. nautobot/extras/templates/extras/plugins_tiles.html +21 -10
  175. nautobot/extras/templatetags/job_buttons.py +4 -4
  176. nautobot/extras/test_jobs/api_test_job.py +1 -1
  177. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  178. nautobot/extras/test_jobs/dry_run.py +1 -1
  179. nautobot/extras/test_jobs/fail.py +5 -5
  180. nautobot/extras/test_jobs/file_output.py +1 -1
  181. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  182. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  183. nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
  184. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  185. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  186. nautobot/extras/test_jobs/log_redaction.py +1 -1
  187. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  188. nautobot/extras/test_jobs/modify_db.py +1 -1
  189. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  190. nautobot/extras/test_jobs/object_var_required.py +1 -1
  191. nautobot/extras/test_jobs/object_vars.py +1 -1
  192. nautobot/extras/test_jobs/pass.py +3 -3
  193. nautobot/extras/test_jobs/profiling.py +1 -1
  194. nautobot/extras/test_jobs/relative_import.py +3 -3
  195. nautobot/extras/test_jobs/singleton.py +16 -0
  196. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  197. nautobot/extras/test_jobs/task_queues.py +1 -1
  198. nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
  199. nautobot/extras/tests/test_api.py +13 -13
  200. nautobot/extras/tests/test_customfields.py +1 -1
  201. nautobot/extras/tests/test_datasources.py +2 -1
  202. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  203. nautobot/extras/tests/test_filters.py +6 -6
  204. nautobot/extras/tests/test_forms.py +33 -1
  205. nautobot/extras/tests/test_jobs.py +178 -32
  206. nautobot/extras/tests/test_models.py +16 -10
  207. nautobot/extras/tests/test_plugins.py +62 -9
  208. nautobot/extras/tests/test_relationships.py +120 -9
  209. nautobot/extras/tests/test_views.py +56 -194
  210. nautobot/extras/utils.py +3 -2
  211. nautobot/extras/views.py +30 -98
  212. nautobot/ipam/api/fields.py +3 -3
  213. nautobot/ipam/api/serializers.py +41 -33
  214. nautobot/ipam/api/views.py +68 -117
  215. nautobot/ipam/factory.py +1 -1
  216. nautobot/ipam/filters.py +3 -2
  217. nautobot/ipam/lookups.py +101 -62
  218. nautobot/ipam/models.py +66 -16
  219. nautobot/ipam/querysets.py +2 -2
  220. nautobot/ipam/tables.py +23 -7
  221. nautobot/ipam/templates/ipam/ipaddress.html +1 -9
  222. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  223. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  224. nautobot/ipam/templates/ipam/prefix.html +1 -9
  225. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  226. nautobot/ipam/templates/ipam/vlan.html +1 -9
  227. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  228. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  229. nautobot/ipam/tests/test_api.py +436 -3
  230. nautobot/ipam/tests/test_forms.py +49 -47
  231. nautobot/ipam/tests/test_migrations.py +30 -30
  232. nautobot/ipam/tests/test_models.py +95 -34
  233. nautobot/ipam/tests/test_querysets.py +63 -1
  234. nautobot/ipam/tests/test_views.py +3 -0
  235. nautobot/ipam/utils/__init__.py +36 -6
  236. nautobot/ipam/views.py +61 -87
  237. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  238. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  239. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  240. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  241. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  242. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  243. nautobot/project-static/docs/404.html +46 -4
  244. nautobot/project-static/docs/apps/index.html +46 -4
  245. nautobot/project-static/docs/apps/nautobot-apps.html +47 -6
  246. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  247. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
  248. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
  249. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +62 -10
  250. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +59 -7
  251. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +374 -122
  252. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +90 -18
  253. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +95 -21
  254. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +53 -6
  255. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +52 -5
  256. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +79 -17
  257. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +102 -28
  258. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +108 -21
  259. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +131 -38
  260. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +239 -65
  261. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +581 -165
  262. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +109 -36
  263. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +453 -167
  264. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +493 -211
  265. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +60 -8
  266. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +71 -15
  267. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +407 -55
  268. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +620 -205
  269. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +858 -412
  270. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +59 -7
  271. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +448 -186
  272. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +365 -147
  273. nautobot/project-static/docs/development/apps/api/configuration-view.html +46 -4
  274. nautobot/project-static/docs/development/apps/api/database-backend-config.html +46 -4
  275. nautobot/project-static/docs/development/apps/api/models/django-admin.html +46 -4
  276. nautobot/project-static/docs/development/apps/api/models/global-search.html +46 -4
  277. nautobot/project-static/docs/development/apps/api/models/graphql.html +46 -4
  278. nautobot/project-static/docs/development/apps/api/models/index.html +46 -4
  279. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +46 -4
  280. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +46 -4
  281. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +46 -4
  282. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +46 -4
  283. nautobot/project-static/docs/development/apps/api/platform-features/index.html +46 -4
  284. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +46 -4
  285. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +46 -4
  286. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +46 -4
  287. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +46 -4
  288. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +68 -7
  289. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +46 -4
  290. nautobot/project-static/docs/development/apps/api/prometheus.html +46 -4
  291. nautobot/project-static/docs/development/apps/api/setup.html +46 -4
  292. nautobot/project-static/docs/development/apps/api/testing.html +46 -4
  293. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +46 -4
  294. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +46 -4
  295. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +46 -4
  296. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +46 -4
  297. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +46 -4
  298. nautobot/project-static/docs/development/apps/api/views/base-template.html +46 -4
  299. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +46 -4
  300. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +46 -4
  301. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +46 -4
  302. nautobot/project-static/docs/development/apps/api/views/index.html +46 -4
  303. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +46 -4
  304. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +46 -4
  305. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +46 -4
  306. nautobot/project-static/docs/development/apps/api/views/notes.html +46 -4
  307. nautobot/project-static/docs/development/apps/api/views/rest-api.html +52 -6
  308. nautobot/project-static/docs/development/apps/api/views/urls.html +46 -4
  309. nautobot/project-static/docs/development/apps/index.html +46 -4
  310. nautobot/project-static/docs/development/apps/migration/code-updates.html +46 -4
  311. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +46 -4
  312. nautobot/project-static/docs/development/apps/migration/from-v1.html +46 -4
  313. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +46 -4
  314. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +46 -4
  315. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +46 -4
  316. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +46 -4
  317. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +50 -8
  318. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +46 -4
  319. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +211 -14
  320. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +46 -4
  321. nautobot/project-static/docs/development/apps/porting-from-netbox.html +46 -4
  322. nautobot/project-static/docs/development/core/application-registry.html +46 -4
  323. nautobot/project-static/docs/development/core/best-practices.html +46 -4
  324. nautobot/project-static/docs/development/core/bootstrap-ui.html +46 -4
  325. nautobot/project-static/docs/development/core/caching.html +46 -4
  326. nautobot/project-static/docs/development/core/controllers.html +46 -4
  327. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +73 -74
  328. nautobot/project-static/docs/development/core/generic-views.html +46 -4
  329. nautobot/project-static/docs/development/core/getting-started.html +249 -224
  330. nautobot/project-static/docs/development/core/homepage.html +49 -7
  331. nautobot/project-static/docs/development/core/index.html +46 -4
  332. nautobot/project-static/docs/development/core/{local-k8s.html → minikube-dev-environment-for-k8s-jobs.html} +469 -168
  333. nautobot/project-static/docs/development/core/model-checklist.html +56 -12
  334. nautobot/project-static/docs/development/core/model-features.html +46 -4
  335. nautobot/project-static/docs/development/core/natural-keys.html +46 -4
  336. nautobot/project-static/docs/development/core/navigation-menu.html +46 -4
  337. nautobot/project-static/docs/development/core/release-checklist.html +49 -7
  338. nautobot/project-static/docs/development/core/role-internals.html +46 -4
  339. nautobot/project-static/docs/development/core/settings.html +46 -4
  340. nautobot/project-static/docs/development/core/style-guide.html +49 -7
  341. nautobot/project-static/docs/development/core/templates.html +46 -4
  342. nautobot/project-static/docs/development/core/testing.html +46 -4
  343. nautobot/project-static/docs/development/core/ui-component-framework.html +369 -273
  344. nautobot/project-static/docs/development/core/user-preferences.html +46 -4
  345. nautobot/project-static/docs/development/index.html +46 -4
  346. nautobot/project-static/docs/development/jobs/index.html +216 -122
  347. nautobot/project-static/docs/development/jobs/migration/from-v1.html +46 -4
  348. nautobot/project-static/docs/index.html +54 -23
  349. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  350. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  351. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  352. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  353. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  354. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  355. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  356. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  357. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  358. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  359. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  360. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  361. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  362. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  363. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  364. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  365. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  366. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  367. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  368. nautobot/project-static/docs/objects.inv +0 -0
  369. nautobot/project-static/docs/overview/application_stack.html +47 -7
  370. nautobot/project-static/docs/overview/design_philosophy.html +46 -4
  371. nautobot/project-static/docs/release-notes/index.html +52 -12
  372. nautobot/project-static/docs/release-notes/version-1.0.html +234 -193
  373. nautobot/project-static/docs/release-notes/version-1.1.html +231 -190
  374. nautobot/project-static/docs/release-notes/version-1.2.html +306 -265
  375. nautobot/project-static/docs/release-notes/version-1.3.html +332 -291
  376. nautobot/project-static/docs/release-notes/version-1.4.html +417 -377
  377. nautobot/project-static/docs/release-notes/version-1.5.html +605 -566
  378. nautobot/project-static/docs/release-notes/version-1.6.html +904 -447
  379. nautobot/project-static/docs/release-notes/version-2.0.html +528 -489
  380. nautobot/project-static/docs/release-notes/version-2.1.html +363 -324
  381. nautobot/project-static/docs/release-notes/version-2.2.html +356 -317
  382. nautobot/project-static/docs/release-notes/version-2.3.html +997 -352
  383. nautobot/project-static/docs/release-notes/version-2.4.html +525 -101
  384. nautobot/project-static/docs/requirements.txt +2 -2
  385. nautobot/project-static/docs/search/search_index.json +1 -1
  386. nautobot/project-static/docs/sitemap.xml +295 -287
  387. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  388. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +46 -4
  389. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +46 -4
  390. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +48 -6
  391. nautobot/project-static/docs/user-guide/administration/configuration/index.html +46 -4
  392. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +46 -4
  393. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +110 -8
  394. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +46 -4
  395. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +46 -4
  396. nautobot/project-static/docs/user-guide/administration/guides/docker.html +46 -4
  397. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +46 -4
  398. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +46 -4
  399. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +46 -4
  400. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +46 -4
  401. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +46 -4
  402. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -6
  403. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +46 -4
  404. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +46 -4
  405. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +46 -4
  406. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +66 -8
  407. nautobot/project-static/docs/user-guide/administration/installation/index.html +46 -4
  408. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +47 -5
  409. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +46 -4
  410. nautobot/project-static/docs/user-guide/administration/installation/services.html +46 -4
  411. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +46 -4
  412. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +46 -4
  413. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +46 -4
  414. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +46 -4
  415. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +46 -4
  416. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +46 -4
  417. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +46 -4
  418. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +46 -4
  419. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +46 -4
  420. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +49 -8
  421. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +46 -4
  422. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +46 -4
  423. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +46 -4
  424. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +46 -4
  425. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +46 -4
  426. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +46 -4
  427. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +46 -4
  428. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +46 -4
  429. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +46 -4
  430. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +46 -4
  431. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +46 -4
  432. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +46 -4
  433. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +46 -4
  434. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +46 -4
  435. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +46 -4
  436. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +46 -4
  437. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +46 -4
  438. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +46 -4
  439. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +46 -4
  440. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +46 -4
  441. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +46 -4
  442. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +46 -4
  443. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +46 -4
  444. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +46 -4
  445. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +46 -4
  446. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +46 -4
  447. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +46 -4
  448. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +46 -4
  449. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +46 -4
  450. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +46 -4
  451. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +46 -4
  452. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +46 -4
  453. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +46 -4
  454. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +46 -4
  455. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +46 -4
  456. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +46 -4
  457. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +46 -4
  458. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +46 -4
  459. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +46 -4
  460. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +46 -4
  461. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +46 -4
  462. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +46 -4
  463. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +46 -4
  464. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +46 -4
  465. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +46 -4
  466. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +46 -4
  467. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +46 -4
  468. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +46 -4
  469. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +46 -4
  470. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +46 -4
  471. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +46 -4
  472. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +46 -4
  473. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +46 -4
  474. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +46 -4
  475. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +46 -4
  476. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +46 -4
  477. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +46 -4
  478. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +50 -12
  479. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +46 -4
  480. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +46 -4
  481. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +46 -4
  482. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +46 -4
  483. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +46 -4
  484. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +46 -4
  485. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +46 -4
  486. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +46 -4
  487. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +46 -4
  488. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +46 -4
  489. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +46 -4
  490. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +46 -4
  491. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +49 -7
  492. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +46 -4
  493. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +46 -4
  494. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +46 -4
  495. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +46 -4
  496. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +46 -4
  497. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +46 -4
  498. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +46 -4
  499. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +46 -4
  500. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +46 -4
  501. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +46 -4
  502. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +46 -4
  503. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +46 -4
  504. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +46 -4
  505. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +46 -4
  506. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +46 -4
  507. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +46 -4
  508. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +46 -4
  509. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +46 -4
  510. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +46 -4
  511. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +46 -4
  512. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +46 -4
  513. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +46 -4
  514. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +51 -7
  515. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +46 -4
  516. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  517. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  518. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  519. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  520. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  521. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  522. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  523. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  524. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  525. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  526. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  527. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  528. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  529. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +46 -4
  530. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +46 -4
  531. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +49 -7
  532. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
  533. nautobot/project-static/docs/user-guide/index.html +46 -4
  534. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +46 -4
  535. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +50 -8
  536. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +46 -4
  537. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +46 -4
  538. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +46 -4
  539. nautobot/project-static/docs/user-guide/platform-functionality/events.html +46 -4
  540. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +46 -4
  541. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +46 -4
  542. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +46 -4
  543. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +46 -4
  544. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +46 -4
  545. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +46 -4
  546. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +50 -7
  547. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +46 -4
  548. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +49 -7
  549. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +46 -4
  550. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +46 -4
  551. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
  552. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +46 -4
  553. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +46 -4
  554. nautobot/project-static/docs/user-guide/platform-functionality/note.html +46 -4
  555. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +46 -4
  556. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +47 -5
  557. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +46 -4
  558. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +46 -4
  559. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +94 -25
  560. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +74 -5
  561. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +46 -4
  562. nautobot/project-static/docs/user-guide/platform-functionality/role.html +46 -4
  563. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +46 -4
  564. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +46 -4
  565. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +46 -4
  566. nautobot/project-static/docs/user-guide/platform-functionality/status.html +46 -4
  567. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +46 -4
  568. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +46 -4
  569. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +46 -4
  570. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +46 -4
  571. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +46 -4
  572. nautobot/project-static/js/forms.js +1 -1
  573. nautobot/tenancy/api/views.py +9 -13
  574. nautobot/tenancy/views.py +4 -2
  575. nautobot/users/admin.py +1 -1
  576. nautobot/users/api/serializers.py +5 -4
  577. nautobot/users/api/views.py +3 -3
  578. nautobot/virtualization/api/serializers.py +4 -4
  579. nautobot/virtualization/api/views.py +5 -24
  580. nautobot/virtualization/filters.py +20 -3
  581. nautobot/virtualization/models.py +1 -1
  582. nautobot/virtualization/tables.py +2 -2
  583. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  584. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
  585. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  586. nautobot/virtualization/tests/test_filters.py +17 -0
  587. nautobot/wireless/filters.py +2 -2
  588. nautobot/wireless/forms.py +1 -1
  589. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
  590. nautobot/wireless/tests/integration/__init__.py +0 -0
  591. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  592. nautobot/wireless/tests/test_filters.py +29 -1
  593. nautobot/wireless/tests/test_views.py +22 -1
  594. nautobot/wireless/views.py +0 -10
  595. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/METADATA +6 -6
  596. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/RECORD +600 -550
  597. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/WHEEL +1 -1
  598. nautobot/core/fixtures/user-data.json +0 -59
  599. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/LICENSE.txt +0 -0
  600. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/NOTICE +0 -0
  601. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/entry_points.txt +0 -0
nautobot/dcim/forms.py CHANGED
@@ -588,7 +588,7 @@ class RackBulkEditForm(
588
588
  required=False,
589
589
  widget=StaticSelect2(),
590
590
  )
591
- u_height = forms.IntegerField(required=False, label="Height (U)")
591
+ u_height = forms.IntegerField(required=False, label="Height (U)", min_value=1, max_value=100)
592
592
  desc_units = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect, label="Descending units")
593
593
  outer_width = forms.IntegerField(required=False, min_value=1)
594
594
  outer_depth = forms.IntegerField(required=False, min_value=1)
@@ -796,7 +796,7 @@ class DeviceFamilyFilterForm(NautobotFilterForm):
796
796
  tags = TagFilterField(model)
797
797
 
798
798
 
799
- class DeviceFamilyBulkEditForm(NautobotBulkEditForm, TagsBulkEditFormMixin):
799
+ class DeviceFamilyBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
800
800
  pk = forms.ModelMultipleChoiceField(queryset=DeviceFamily.objects.all(), widget=forms.MultipleHiddenInput())
801
801
  description = forms.CharField(required=False)
802
802
 
@@ -878,7 +878,7 @@ class DeviceTypeBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
878
878
  manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
879
879
  device_family = DynamicModelChoiceField(queryset=DeviceFamily.objects.all(), required=False)
880
880
  software_image_files = DynamicModelMultipleChoiceField(queryset=SoftwareImageFile.objects.all(), required=False)
881
- u_height = forms.IntegerField(required=False)
881
+ u_height = forms.IntegerField(required=False, min_value=0)
882
882
  is_full_depth = forms.NullBooleanField(required=False, widget=BulkEditNullBooleanSelect(), label="Is full depth")
883
883
  comments = CommentField(label="Comments", required=False)
884
884
 
@@ -1655,6 +1655,8 @@ class ComponentTemplateImportForm(BootstrapMixin, CustomFieldModelCSVForm):
1655
1655
  netbox-community/devicetype-library repository.
1656
1656
  """
1657
1657
 
1658
+ Meta: type # to be defined by concrete subclasses
1659
+
1658
1660
  def __init__(self, data=None, *args, **kwargs):
1659
1661
  super().__init__(data, *args, **kwargs)
1660
1662
 
@@ -2127,6 +2129,8 @@ class DeviceBulkEditForm(
2127
2129
  rack_group = DynamicModelChoiceField(
2128
2130
  queryset=RackGroup.objects.all(), required=False, query_params={"location": "$location"}
2129
2131
  )
2132
+ cluster = DynamicModelChoiceField(queryset=Cluster.objects.all(), required=False)
2133
+ comments = CommentField(widget=SmallTextarea, label="Comments")
2130
2134
  tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
2131
2135
  platform = DynamicModelChoiceField(queryset=Platform.objects.all(), required=False)
2132
2136
  serial = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False, label="Serial Number")
@@ -2150,6 +2154,8 @@ class DeviceBulkEditForm(
2150
2154
  "position",
2151
2155
  "face",
2152
2156
  "rack_group",
2157
+ "cluster",
2158
+ "comments",
2153
2159
  "secrets_group",
2154
2160
  "device_redundancy_group",
2155
2161
  "device_redundancy_group_priority",
@@ -3214,9 +3220,6 @@ class InterfaceBulkEditForm(
3214
3220
  untagged_vlan = DynamicModelChoiceField(
3215
3221
  queryset=VLAN.objects.all(),
3216
3222
  required=False,
3217
- query_params={
3218
- "locations": "null",
3219
- },
3220
3223
  )
3221
3224
  tagged_vlans = DynamicModelMultipleChoiceField(
3222
3225
  queryset=VLAN.objects.all(),
@@ -3266,8 +3269,12 @@ class InterfaceBulkEditForm(
3266
3269
  # Limit VLAN choices by Location
3267
3270
  if locations.count() == 1:
3268
3271
  location = locations.first()
3269
- self.fields["untagged_vlan"].widget.add_query_param("locations", location.pk)
3272
+ # In the case of a single location, use the available_on_device query param to limit untagged VLAN choices
3273
+ # to those available on the devices in that location and in the ancestors of the location.
3274
+ self.fields["untagged_vlan"].widget.add_query_param("available_on_device", device.pk)
3270
3275
  self.fields["tagged_vlans"].widget.add_query_param("locations", location.pk)
3276
+ else:
3277
+ self.fields["tagged_vlans"].widget.add_query_param("locations", "null")
3271
3278
 
3272
3279
  # Restrict parent/bridge/LAG interface assignment by device (or VC master)
3273
3280
  if device_count == 1:
@@ -4982,10 +4989,6 @@ class ControllerForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
4982
4989
  queryset=Platform.objects.all(),
4983
4990
  required=False,
4984
4991
  )
4985
- tenant = DynamicModelChoiceField(
4986
- queryset=Tenant.objects.all(),
4987
- required=False,
4988
- )
4989
4992
  external_integration = DynamicModelChoiceField(
4990
4993
  queryset=ExternalIntegration.objects.all(),
4991
4994
  required=False,
@@ -5007,6 +5010,7 @@ class ControllerForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
5007
5010
  "role",
5008
5011
  "description",
5009
5012
  "platform",
5013
+ "tenant_group",
5010
5014
  "tenant",
5011
5015
  "location",
5012
5016
  "capabilities",
@@ -5059,6 +5063,7 @@ class ControllerFilterForm(
5059
5063
  "description",
5060
5064
  "location",
5061
5065
  "platform",
5066
+ "tenant_group",
5062
5067
  "tenant",
5063
5068
  "external_integration",
5064
5069
  "controller_device",
@@ -5085,7 +5090,7 @@ class ControllerBulkEditForm(
5085
5090
  required=False,
5086
5091
  )
5087
5092
  capabilities = JSONArrayFormField(
5088
- choices=add_blank_choice(ControllerCapabilitiesChoices),
5093
+ choices=ControllerCapabilitiesChoices,
5089
5094
  base_field=forms.CharField(),
5090
5095
  required=False,
5091
5096
  )
@@ -5114,15 +5119,18 @@ class ControllerBulkEditForm(
5114
5119
  "description",
5115
5120
  "location",
5116
5121
  "platform",
5117
- "tenant",
5118
5122
  "external_integration",
5119
5123
  "controller_device",
5120
5124
  "controller_device_redundancy_group",
5121
5125
  "tags",
5122
5126
  )
5127
+ nullable_fields = (
5128
+ "tenant",
5129
+ "capabilities",
5130
+ )
5123
5131
 
5124
5132
 
5125
- class ControllerManagedDeviceGroupForm(NautobotModelForm):
5133
+ class ControllerManagedDeviceGroupForm(NautobotModelForm, TenancyForm):
5126
5134
  """ControllerManagedDeviceGroup create/edit form."""
5127
5135
 
5128
5136
  controller = DynamicModelChoiceField(queryset=Controller.objects.all(), required=True)
@@ -5139,12 +5147,15 @@ class ControllerManagedDeviceGroupForm(NautobotModelForm):
5139
5147
  fields = (
5140
5148
  "controller",
5141
5149
  "name",
5150
+ "description",
5142
5151
  "devices",
5143
5152
  "parent",
5144
5153
  "capabilities",
5145
5154
  "weight",
5146
5155
  "radio_profiles",
5147
5156
  "tags",
5157
+ "tenant_group",
5158
+ "tenant",
5148
5159
  )
5149
5160
 
5150
5161
  def __init__(self, *args, **kwargs):
@@ -5159,12 +5170,13 @@ class ControllerManagedDeviceGroupForm(NautobotModelForm):
5159
5170
  return instance
5160
5171
 
5161
5172
 
5162
- class ControllerManagedDeviceGroupFilterForm(NautobotFilterForm):
5173
+ class ControllerManagedDeviceGroupFilterForm(NautobotFilterForm, TenancyFilterForm):
5163
5174
  """ControllerManagedDeviceGroup basic filter form."""
5164
5175
 
5165
5176
  model = ControllerManagedDeviceGroup
5166
5177
  q = forms.CharField(required=False, label="Search")
5167
5178
  name = forms.CharField(required=False, label="Name")
5179
+ description = forms.CharField(required=False, label="Description")
5168
5180
  controller = DynamicModelChoiceField(
5169
5181
  queryset=Controller.objects.all(),
5170
5182
  required=False,
@@ -5185,11 +5197,14 @@ class ControllerManagedDeviceGroupFilterForm(NautobotFilterForm):
5185
5197
  field_order = (
5186
5198
  "q",
5187
5199
  "name",
5200
+ "description",
5188
5201
  "controller",
5189
5202
  "parent",
5190
5203
  "weight",
5191
5204
  "subtree",
5192
5205
  "tags",
5206
+ "tenant",
5207
+ "tenant_group",
5193
5208
  )
5194
5209
 
5195
5210
 
@@ -5214,10 +5229,11 @@ class ControllerManagedDeviceGroupBulkEditForm(TagsBulkEditFormMixin, NautobotBu
5214
5229
  label="Remove Radio Profiles",
5215
5230
  )
5216
5231
  capabilities = JSONArrayFormField(
5217
- choices=add_blank_choice(ControllerCapabilitiesChoices),
5232
+ choices=ControllerCapabilitiesChoices,
5218
5233
  base_field=forms.CharField(),
5219
5234
  required=False,
5220
5235
  )
5236
+ tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
5221
5237
 
5222
5238
  class Meta:
5223
5239
  model = ControllerManagedDeviceGroup
@@ -5225,9 +5241,12 @@ class ControllerManagedDeviceGroupBulkEditForm(TagsBulkEditFormMixin, NautobotBu
5225
5241
  "controller",
5226
5242
  "parent",
5227
5243
  "weight",
5228
- "capabilities",
5229
5244
  "tags",
5230
5245
  )
5246
+ nullable_fields = (
5247
+ "tenant",
5248
+ "capabilities",
5249
+ )
5231
5250
 
5232
5251
 
5233
5252
  #
@@ -98,13 +98,13 @@ class CableType(OptimizedNautobotObjectType):
98
98
 
99
99
  def resolve_termination_a_type(self, args):
100
100
  if self.termination_a_type:
101
- model = self.termination_a_type.model_class()
101
+ model = self.termination_a_type.model_class() # pylint: disable=no-member
102
102
  return f"{model._meta.app_label}.{model._meta.model_name}"
103
103
  return None
104
104
 
105
105
  def resolve_termination_b_type(self, args):
106
106
  if self.termination_b_type:
107
- model = self.termination_b_type.model_class()
107
+ model = self.termination_b_type.model_class() # pylint: disable=no-member
108
108
  return f"{model._meta.app_label}.{model._meta.model_name}"
109
109
  return None
110
110
 
@@ -0,0 +1,25 @@
1
+ # Generated by Django 4.2.16 on 2024-11-21 12:35
2
+
3
+ from django.db import migrations, models
4
+ import django.db.models.deletion
5
+
6
+
7
+ class Migration(migrations.Migration):
8
+ dependencies = [
9
+ ("tenancy", "0009_update_all_charfields_max_length_to_255"),
10
+ ("dcim", "0066_controllermanageddevicegroup_radio_profiles_and_more"),
11
+ ]
12
+
13
+ operations = [
14
+ migrations.AddField(
15
+ model_name="controllermanageddevicegroup",
16
+ name="tenant",
17
+ field=models.ForeignKey(
18
+ blank=True,
19
+ null=True,
20
+ on_delete=django.db.models.deletion.PROTECT,
21
+ related_name="controller_managed_device_groups",
22
+ to="tenancy.tenant",
23
+ ),
24
+ ),
25
+ ]
@@ -63,12 +63,12 @@ __all__ = (
63
63
  "Device",
64
64
  "DeviceBay",
65
65
  "DeviceBayTemplate",
66
+ "DeviceFamily",
66
67
  "DeviceRedundancyGroup",
67
68
  "DeviceType",
68
69
  "DeviceTypeToSoftwareImageFile",
69
70
  "FrontPort",
70
71
  "FrontPortTemplate",
71
- "DeviceFamily",
72
72
  "Interface",
73
73
  "InterfaceRedundancyGroup",
74
74
  "InterfaceRedundancyGroupAssociation",
@@ -100,7 +100,7 @@ class ComponentTemplateModel(
100
100
  def get_absolute_url(self, api=False):
101
101
  # TODO: in the new UI, this should be able to link directly to the object, instead of the device-type.
102
102
  if not api:
103
- return self.device_type.get_absolute_url(api=api)
103
+ return self.device_type.get_absolute_url(api=api) # pylint: disable=no-member
104
104
  return super().get_absolute_url(api=api)
105
105
 
106
106
  def instantiate_model(self, model, device, **kwargs):
@@ -460,7 +460,7 @@ class DeviceBayTemplate(ComponentTemplateModel):
460
460
  return self.instantiate_model(model=DeviceBay, device=device)
461
461
 
462
462
  def clean(self):
463
- if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT:
463
+ if self.device_type and self.device_type.subdevice_role != SubdeviceRoleChoices.ROLE_PARENT: # pylint: disable=no-member
464
464
  raise ValidationError(
465
465
  f'Subdevice role of device type ({self.device_type}) must be set to "parent" to allow device bays.'
466
466
  )
@@ -138,7 +138,7 @@ class ModularComponentModel(ComponentModel):
138
138
  @property
139
139
  def parent(self):
140
140
  """Device that this component belongs to, walking up module inheritance if necessary."""
141
- return self.module.device if self.module else self.device
141
+ return self.module.device if self.module else self.device # pylint: disable=no-member
142
142
 
143
143
  def render_name_template(self, save=False):
144
144
  """
@@ -161,9 +161,9 @@ class ModularComponentModel(ComponentModel):
161
161
 
162
162
  The deeply nested interface would be named "A{module.parent}" after calling this method.
163
163
  """
164
- if self.module and self.module.parent_module_bay and "{module" in self.name:
164
+ if self.module and self.module.parent_module_bay and "{module" in self.name: # pylint: disable=no-member
165
165
  name = ""
166
- module_bay = self.module.parent_module_bay
166
+ module_bay = self.module.parent_module_bay # pylint: disable=no-member
167
167
  positions = []
168
168
  while module_bay is not None:
169
169
  position = getattr(module_bay, "position", None)
@@ -291,11 +291,11 @@ class PathEndpoint(models.Model):
291
291
  return []
292
292
 
293
293
  # Construct the complete path
294
- path = [self, *self._path.get_path()]
294
+ path = [self, *self._path.get_path()] # pylint: disable=no-member
295
295
  while (len(path) + 1) % 3:
296
296
  # Pad to ensure we have complete three-tuples (e.g. for paths that end at a RearPort)
297
297
  path.append(None)
298
- path.append(self._path.destination)
298
+ path.append(self._path.destination) # pylint: disable=no-member
299
299
 
300
300
  # Return the path as a list of three-tuples (A termination, cable, B termination)
301
301
  return list(zip(*[iter(path)] * 3))
@@ -555,7 +555,7 @@ class BaseInterface(RelationshipModel):
555
555
 
556
556
  def clean(self):
557
557
  # Remove untagged VLAN assignment for non-802.1Q interfaces
558
- if not self.mode and self.untagged_vlan is not None:
558
+ if not self.mode and self.untagged_vlan is not None: # pylint: disable=no-member # Intf/VMIntf both have untagged_vlan
559
559
  raise ValidationError({"untagged_vlan": "Mode must be set when specifying untagged_vlan"})
560
560
 
561
561
  def save(self, *args, **kwargs):
@@ -569,8 +569,8 @@ class BaseInterface(RelationshipModel):
569
569
  self.status = status
570
570
 
571
571
  # Only "tagged" interfaces may have tagged VLANs assigned. ("tagged all" implies all VLANs are assigned.)
572
- if self.present_in_database and self.mode != InterfaceModeChoices.MODE_TAGGED:
573
- self.tagged_vlans.clear()
572
+ if self.present_in_database and self.mode != InterfaceModeChoices.MODE_TAGGED: # pylint: disable=no-member
573
+ self.tagged_vlans.clear() # pylint: disable=no-member # Intf/VMIntf both have tagged_vlans
574
574
 
575
575
  return super().save(*args, **kwargs)
576
576
 
@@ -710,18 +710,19 @@ class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInter
710
710
  )
711
711
 
712
712
  # An interface's parent must belong to the same device or virtual chassis
713
- if self.parent and self.parent_interface.parent != self.parent:
713
+ if self.parent and self.parent_interface.parent != self.parent: # pylint: disable=no-member
714
714
  if getattr(self.parent, "virtual_chassis", None) is None:
715
715
  raise ValidationError(
716
- {
717
- "parent_interface": f"The selected parent interface ({self.parent_interface}) belongs to a different device "
718
- f"({self.parent_interface.parent})."
716
+ { # pylint: disable=no-member # false positive on parent_interface.parent
717
+ "parent_interface": f"The selected parent interface ({self.parent_interface}) belongs "
718
+ f"to a different device ({self.parent_interface.parent})."
719
719
  }
720
720
  )
721
- elif self.parent_interface.parent.virtual_chassis != self.parent.virtual_chassis:
721
+ elif self.parent_interface.parent.virtual_chassis != self.parent.virtual_chassis: # pylint: disable=no-member
722
722
  raise ValidationError(
723
- {
724
- "parent_interface": f"The selected parent interface ({self.parent_interface}) belongs to {self.parent_interface.parent}, which "
723
+ { # pylint: disable=no-member # false positive on parent_interface.parent
724
+ "parent_interface": f"The selected parent interface ({self.parent_interface}) belongs "
725
+ f"to {self.parent_interface.parent}, which "
725
726
  f"is not part of virtual chassis {self.parent.virtual_chassis}."
726
727
  }
727
728
  )
@@ -754,21 +755,22 @@ class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInter
754
755
  raise ValidationError({"bridge": "An interface cannot be bridged to itself."})
755
756
 
756
757
  # A bridged interface belong to the same device or virtual chassis
757
- if self.parent and self.bridge.parent != self.parent:
758
+ if self.parent and self.bridge.parent != self.parent: # pylint: disable=no-member
758
759
  if getattr(self.parent, "virtual_chassis", None) is None:
759
760
  raise ValidationError(
760
761
  {
761
762
  "bridge": (
763
+ # pylint: disable=no-member # false positive on bridge.parent
762
764
  f"The selected bridge interface ({self.bridge}) belongs to a different device "
763
765
  f"({self.bridge.parent})."
764
766
  )
765
767
  }
766
768
  )
767
- elif self.bridge.parent.virtual_chassis_id != self.parent.virtual_chassis_id:
769
+ elif self.bridge.parent.virtual_chassis_id != self.parent.virtual_chassis_id: # pylint: disable=no-member
768
770
  raise ValidationError(
769
771
  {
770
772
  "bridge": (
771
- f"The selected bridge interface ({self.bridge}) belongs to {self.bridge.parent}, which "
773
+ f"The selected bridge interface ({self.bridge}) belongs to {self.bridge.parent}, which " # pylint: disable=no-member
772
774
  f"is not part of virtual chassis {self.parent.virtual_chassis}."
773
775
  )
774
776
  }
@@ -1084,8 +1086,8 @@ class DeviceBay(ComponentModel):
1084
1086
  super().clean()
1085
1087
 
1086
1088
  # Validate that the parent Device can have DeviceBays
1087
- if not self.device.device_type.is_parent_device:
1088
- raise ValidationError(f"This type of device ({self.device.device_type}) does not support device bays.")
1089
+ if not self.device.device_type.is_parent_device: # pylint: disable=no-member
1090
+ raise ValidationError(f"This type of device ({self.device.device_type}) does not support device bays.") # pylint: disable=no-member
1089
1091
 
1090
1092
  # Cannot install a device into itself, obviously
1091
1093
  if self.device == self.installed_device:
@@ -48,6 +48,7 @@ __all__ = (
48
48
  "Controller",
49
49
  "ControllerManagedDeviceGroup",
50
50
  "Device",
51
+ "DeviceFamily",
51
52
  "DeviceRedundancyGroup",
52
53
  "DeviceType",
53
54
  "InterfaceVDCAssignment",
@@ -823,6 +824,7 @@ class Device(PrimaryModel, ConfigContextModel):
823
824
 
824
825
  # If any software image file is specified, validate that
825
826
  # each of the software image files belongs to the device's device type or is a default image
827
+ # TODO: this is incorrect as we cannot validate a ManyToMany during clean() - nautobot/nautobot#6344
826
828
  for image_file in self.software_image_files.all():
827
829
  if not image_file.default_image and self.device_type not in image_file.device_types.all():
828
830
  raise ValidationError(
@@ -1481,6 +1483,13 @@ class ControllerManagedDeviceGroup(TreeModel, PrimaryModel):
1481
1483
  null=True,
1482
1484
  help_text="List of capabilities supported by the controller device group, these capabilities are used to enhance views in Nautobot.",
1483
1485
  )
1486
+ tenant = models.ForeignKey(
1487
+ to="tenancy.Tenant",
1488
+ on_delete=models.PROTECT,
1489
+ related_name="controller_managed_device_groups",
1490
+ blank=True,
1491
+ null=True,
1492
+ )
1484
1493
 
1485
1494
  class Meta:
1486
1495
  ordering = ("weight",)
@@ -1500,7 +1509,7 @@ class ControllerManagedDeviceGroup(TreeModel, PrimaryModel):
1500
1509
  if self.controller == self._original_controller and self.parent == self._original_parent:
1501
1510
  return
1502
1511
 
1503
- if self.parent and self.controller and self.controller != self.parent.controller:
1512
+ if self.parent and self.controller and self.controller != self.parent.controller: # pylint: disable=no-member
1504
1513
  raise ValidationError(
1505
1514
  {"controller": "Controller device group must have the same controller as the parent group."}
1506
1515
  )
@@ -283,7 +283,7 @@ class Location(TreeModel, PrimaryModel):
283
283
  # We shouldn't have a parent, *unless* our own location type is permitted to be nested.
284
284
  if self.parent is not None:
285
285
  if self.location_type.nestable:
286
- if self.parent.location_type != self.location_type:
286
+ if self.parent.location_type != self.location_type: # pylint: disable=no-member
287
287
  raise ValidationError(
288
288
  {
289
289
  "parent": f"A Location of type {self.location_type} may only have "
@@ -304,7 +304,7 @@ class Location(TreeModel, PrimaryModel):
304
304
 
305
305
  # Is the parent location of a correct type?
306
306
  if self.location_type.nestable:
307
- if self.parent.location_type not in (self.location_type, self.location_type.parent):
307
+ if self.parent.location_type not in (self.location_type, self.location_type.parent): # pylint: disable=no-member
308
308
  raise ValidationError(
309
309
  {
310
310
  "parent": f"A Location of type {self.location_type} can only have a Location "
@@ -312,7 +312,7 @@ class Location(TreeModel, PrimaryModel):
312
312
  }
313
313
  )
314
314
  else:
315
- if self.parent.location_type != self.location_type.parent:
315
+ if self.parent.location_type != self.location_type.parent: # pylint: disable=no-member
316
316
  raise ValidationError(
317
317
  {
318
318
  "parent": f"A Location of type {self.location_type} can only have a Location "
@@ -73,11 +73,11 @@ class PowerPanel(PrimaryModel):
73
73
  if self.rack_group:
74
74
  if (
75
75
  self.location is not None
76
- and self.rack_group.location is not None
77
- and self.rack_group.location not in self.location.ancestors(include_self=True)
76
+ and self.rack_group.location is not None # pylint: disable=no-member
77
+ and self.rack_group.location not in self.location.ancestors(include_self=True) # pylint: disable=no-member
78
78
  ):
79
79
  raise ValidationError(
80
- {
80
+ { # pylint: disable=no-member # false positive on rack_group.location
81
81
  "rack_group": f'Rack group "{self.rack_group}" belongs to a location '
82
82
  f'("{self.rack_group.location}") that does not contain "{self.location}".'
83
83
  }
@@ -151,9 +151,10 @@ class PowerFeed(PrimaryModel, PathEndpoint, CableTermination):
151
151
  super().clean()
152
152
 
153
153
  # Rack must belong to same Location as PowerPanel
154
- if self.rack and self.rack.location != self.power_panel.location:
154
+ if self.rack and self.rack.location != self.power_panel.location: # pylint: disable=no-member
155
155
  raise ValidationError(
156
- f"Rack {self.rack} ({self.rack.location}) and power panel {self.power_panel} ({self.power_panel.location}) are in different locations"
156
+ f"Rack {self.rack} ({self.rack.location}) and " # pylint: disable=no-member
157
+ f"power panel {self.power_panel} ({self.power_panel.location}) are in different locations"
157
158
  )
158
159
 
159
160
  # AC voltage cannot be negative
@@ -77,11 +77,11 @@ class RackGroup(TreeModel, OrganizationalModel):
77
77
  # Parent RackGroup (if any) must belong to the same or ancestor Location
78
78
  if (
79
79
  self.parent is not None
80
- and self.parent.location is not None
81
- and self.parent.location not in self.location.ancestors(include_self=True)
80
+ and self.parent.location is not None # pylint: disable=no-member
81
+ and self.parent.location not in self.location.ancestors(include_self=True) # pylint: disable=no-member
82
82
  ):
83
83
  raise ValidationError(
84
- {
84
+ { # pylint: disable=no-member # false positive on parent.location
85
85
  "location": f'Location "{self.location}" is not descended from '
86
86
  f'parent rack group "{self.parent}" location "{self.parent.location}".'
87
87
  }
@@ -296,7 +296,7 @@ class Rack(PrimaryModel):
296
296
  # Determine which devices the user has permission to view
297
297
  permitted_device_ids = []
298
298
  if user is not None:
299
- permitted_device_ids = self.devices.restrict(user, "view").values_list("pk", flat=True)
299
+ permitted_device_ids = self.devices.restrict(user, "view").values_list("pk", flat=True) # pylint: disable=no-member
300
300
 
301
301
  for device in queryset:
302
302
  if expand_devices:
@@ -145,7 +145,7 @@ class ConsoleConnectionTable(BaseTable):
145
145
  linkify=True,
146
146
  verbose_name="Port",
147
147
  )
148
- device = tables.Column(linkify=True, accessor="parent")
148
+ device = tables.Column(linkify=True, accessor="parent", orderable=False)
149
149
  name = tables.Column(linkify=True, verbose_name="Console Port")
150
150
  reachable = BooleanColumn(accessor=Accessor("_path__is_active"), verbose_name="Reachable")
151
151
 
@@ -173,7 +173,7 @@ class PowerConnectionTable(BaseTable):
173
173
  linkify=True,
174
174
  verbose_name="Outlet",
175
175
  )
176
- device = tables.Column(linkify=True, accessor="parent")
176
+ device = tables.Column(linkify=True, accessor="parent", orderable=False)
177
177
  name = tables.Column(linkify=True, verbose_name="Power Port")
178
178
  reachable = BooleanColumn(accessor=Accessor("_path__is_active"), verbose_name="Reachable")
179
179
 
@@ -183,7 +183,7 @@ class PowerConnectionTable(BaseTable):
183
183
 
184
184
 
185
185
  class InterfaceConnectionTable(BaseTable):
186
- device_a = tables.Column(accessor=Accessor("parent"), linkify=True, verbose_name="Device A")
186
+ device_a = tables.Column(accessor=Accessor("parent"), linkify=True, verbose_name="Device A", orderable=False)
187
187
  interface_a = tables.Column(accessor=Accessor("name"), linkify=True, verbose_name="Interface A")
188
188
  device_b = tables.Column(
189
189
  accessor=Accessor("_path__destination__parent"),
@@ -64,8 +64,8 @@ from .template_code import (
64
64
  __all__ = (
65
65
  "ConsolePortTable",
66
66
  "ConsoleServerPortTable",
67
- "ControllerTable",
68
67
  "ControllerManagedDeviceGroupTable",
68
+ "ControllerTable",
69
69
  "DeviceBayTable",
70
70
  "DeviceDeviceBayTable",
71
71
  "DeviceImportTable",
@@ -75,19 +75,19 @@ __all__ = (
75
75
  "DeviceModuleConsoleServerPortTable",
76
76
  "DeviceModuleFrontPortTable",
77
77
  "DeviceModuleInterfaceTable",
78
- "DeviceModulePowerPortTable",
79
78
  "DeviceModulePowerOutletTable",
79
+ "DeviceModulePowerPortTable",
80
80
  "DeviceModuleRearPortTable",
81
81
  "DeviceRedundancyGroupTable",
82
82
  "DeviceTable",
83
83
  "FrontPortTable",
84
- "InterfaceTable",
85
- "InterfaceRedundancyGroupTable",
86
84
  "InterfaceRedundancyGroupAssociationTable",
85
+ "InterfaceRedundancyGroupTable",
86
+ "InterfaceTable",
87
87
  "InventoryItemTable",
88
- "ModuleTable",
89
88
  "ModuleBayTable",
90
89
  "ModuleModuleBayTable",
90
+ "ModuleTable",
91
91
  "PlatformTable",
92
92
  "PowerOutletTable",
93
93
  "PowerPortTable",
@@ -1409,6 +1409,7 @@ class ControllerManagedDeviceGroupTable(BaseTable):
1409
1409
  name = tables.TemplateColumn(template_code=TREE_LINK, attrs={"td": {"class": "text-nowrap"}})
1410
1410
  weight = tables.Column()
1411
1411
  controller = tables.Column(linkify=True)
1412
+ tenant = TenantColumn()
1412
1413
  capabilities = tables.Column()
1413
1414
  tags = TagColumn(url_name="dcim:controllermanageddevicegroup_list")
1414
1415
  actions = ButtonsColumn(ControllerManagedDeviceGroup)
@@ -1440,6 +1441,7 @@ class ControllerManagedDeviceGroupTable(BaseTable):
1440
1441
  "wireless_networks_count",
1441
1442
  "controller",
1442
1443
  "weight",
1444
+ "tenant",
1443
1445
  "capabilities",
1444
1446
  "tags",
1445
1447
  "actions",
@@ -253,7 +253,7 @@ class PowerOutletTemplateTable(ComponentTemplateTable):
253
253
  "name",
254
254
  "label",
255
255
  "type",
256
- "power_port",
256
+ "power_port_template",
257
257
  "feed_leg",
258
258
  "description",
259
259
  "actions",
@@ -290,7 +290,7 @@ class FrontPortTemplateTable(ComponentTemplateTable):
290
290
  "name",
291
291
  "label",
292
292
  "type",
293
- "rear_port",
293
+ "rear_port_template",
294
294
  "rear_port_position",
295
295
  "description",
296
296
  "actions",
@@ -15,10 +15,10 @@ from nautobot.tenancy.tables import TenantColumn
15
15
  from .template_code import RACKGROUP_ELEVATIONS, TREE_LINK, UTILIZATION_GRAPH
16
16
 
17
17
  __all__ = (
18
- "RackTable",
19
18
  "RackDetailTable",
20
19
  "RackGroupTable",
21
20
  "RackReservationTable",
21
+ "RackTable",
22
22
  )
23
23
 
24
24
 
@@ -34,13 +34,7 @@
34
34
  {% endwith %}
35
35
  </div>
36
36
  </div>
37
- <div class="panel panel-default">
38
- <div class="panel-heading"><strong>Tenancy</strong></div>
39
- <div class="panel-body">
40
- {% render_field form.tenant_group %}
41
- {% render_field form.tenant %}
42
- </div>
43
- </div>
37
+ {% include 'inc/tenancy_form_panel.html' %}
44
38
  {% include 'inc/extras_features_edit_form_fields.html' %}
45
39
  {% endblock form %}
46
40
 
@@ -34,15 +34,7 @@
34
34
  <td>Platform</td>
35
35
  <td>{{ object.platform|hyperlinked_object }}</td>
36
36
  </tr>
37
- <tr>
38
- <td>Tenant</td>
39
- <td>
40
- {% if object.tenant and object.tenant.tenant_group %}
41
- {{ object.tenant.tenant_group|hyperlinked_object }} /
42
- {% endif %}
43
- {{ object.tenant|hyperlinked_object }}
44
- </td>
45
- </tr>
37
+ {% include 'inc/tenant_table_row.html' %}
46
38
  <tr>
47
39
  <td>Description</td>
48
40
  <td>{{ object.description|placeholder }}</td>