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/ipam/lookups.py CHANGED
@@ -3,7 +3,9 @@ from django.db.models import Lookup, lookups
3
3
  import netaddr
4
4
 
5
5
 
6
- def _mysql_varbin_to_broadcast():
6
+ def _mysql_varbin_to_broadcast(alias=None):
7
+ if alias:
8
+ return f"HEX({alias}.broadcast)"
7
9
  return "HEX(broadcast)"
8
10
 
9
11
 
@@ -13,11 +15,15 @@ def _mysql_varbin_to_hex(lhs, alias=None):
13
15
  return f"HEX({lhs})"
14
16
 
15
17
 
16
- def _mysql_varbin_to_network():
18
+ def _mysql_varbin_to_network(alias=None):
19
+ if alias:
20
+ return f"HEX({alias}.network)"
17
21
  return "HEX(network)"
18
22
 
19
23
 
20
- def _postgresql_varbin_to_broadcast(length):
24
+ def _postgresql_varbin_to_broadcast(length, alias=None):
25
+ if alias:
26
+ return f"right({alias}.broadcast::text, -1)::varbit::bit({length})"
21
27
  return f"right(broadcast::text, -1)::varbit::bit({length})"
22
28
 
23
29
 
@@ -27,8 +33,10 @@ def _postgresql_varbin_to_integer(lhs, length, alias=None):
27
33
  return f"right({lhs}::text, -1)::varbit::bit({length})"
28
34
 
29
35
 
30
- def _postgresql_varbin_to_network(lhs, length):
36
+ def _postgresql_varbin_to_network(lhs, length, alias=None):
31
37
  # convert to bitstring, 0 out everything larger than prefix_length
38
+ if alias:
39
+ return f"lpad(right({alias}.{lhs}::text, -1)::varbit::text, {alias}.prefix_length, '0')::bit({length})"
32
40
  return f"lpad(right({lhs}::text, -1)::varbit::text, prefix_length, '0')::bit({length})"
33
41
 
34
42
 
@@ -52,8 +60,8 @@ def get_ip_info(field_name, ip_str, alias=None):
52
60
  ip_details.rhs = py_to_hex(ip.ip, ip_details.length)
53
61
  ip_details.net_addr = f"'{py_to_hex(ip.network, ip_details.length)}'"
54
62
  ip_details.bcast_addr = f"'{py_to_hex(ip[-1], ip_details.length)}'"
55
- ip_details.q_net = _mysql_varbin_to_network()
56
- ip_details.q_bcast = _mysql_varbin_to_broadcast()
63
+ ip_details.q_net = _mysql_varbin_to_network(alias=alias)
64
+ ip_details.q_bcast = _mysql_varbin_to_broadcast(alias=alias)
57
65
  ip_details.q_ip = _mysql_varbin_to_hex(field_name, alias=alias)
58
66
 
59
67
  elif _connection.vendor == "postgresql":
@@ -61,8 +69,8 @@ def get_ip_info(field_name, ip_str, alias=None):
61
69
  ip_details.addr_str = f"B'{bin(int(ip_details.addr))[2:].zfill(ip_details.length)}'"
62
70
  ip_details.net_addr = f"B'{bin(int(ip.network))[2:].zfill(ip_details.length)}'"
63
71
  ip_details.bcast_addr = f"B'{bin(int(ip[-1]))[2:].zfill(ip_details.length)}'"
64
- ip_details.q_net = _postgresql_varbin_to_network(field_name, ip_details.length)
65
- ip_details.q_bcast = _postgresql_varbin_to_broadcast(ip_details.length)
72
+ ip_details.q_net = _postgresql_varbin_to_network(field_name, ip_details.length, alias=alias)
73
+ ip_details.q_bcast = _postgresql_varbin_to_broadcast(ip_details.length, alias=alias)
66
74
  ip_details.q_ip = _postgresql_varbin_to_integer(field_name, ip_details.length, alias=alias)
67
75
 
68
76
  return ip_details
@@ -71,25 +79,38 @@ def get_ip_info(field_name, ip_str, alias=None):
71
79
  class IPDetails:
72
80
  """Class for setting up all details about an IP they may be needed"""
73
81
 
74
- net = None
75
- addr = None
76
- ip = None
77
- prefix = None
78
- length = None
79
- addr_str = None
80
- rhs = None
81
- net_addr = None
82
- bcast_addr = None
83
- q_net = None
84
- q_bcast = None
85
- q_ip = None
82
+ addr = None # 10.0.0.0
83
+ ip = None # 10.0.0.0/8
84
+ prefix = None # 8
85
+ length = None # 32
86
+ addr_str = None # B'00001010000000000000000000000000'
87
+ rhs = None # 00001010000000000000000000000000
88
+ net_addr = None # B'00001010000000000000000000000000'
89
+ bcast_addr = None # B'00001010111111111111111111111111'
90
+ q_net = None # mysql or postgres specific
91
+ q_bcast = None # mysql or postgres specific
92
+ q_ip = None # mysql or postgres specific
86
93
  to_len = {4: 32, 6: 128}
87
94
 
95
+ def __str__(self):
96
+ return f"""\
97
+ addr: {self.addr}
98
+ ip: {self.ip}
99
+ prefix: {self.prefix}
100
+ length: {self.length}
101
+ addr_str: {self.addr_str}
102
+ rhs: {self.rhs}
103
+ net_addr: {self.net_addr}
104
+ bcast_addr: {self.bcast_addr}
105
+ q_net: {self.q_net}
106
+ q_bcast: {self.q_bcast}
107
+ q_ip: {self.q_ip}"""
108
+
88
109
 
89
110
  class StringMatchMixin:
90
- def process_lhs(self, qn, connection, lhs=None):
111
+ def process_lhs(self, compiler, connection, lhs=None):
91
112
  lhs = lhs or self.lhs
92
- lhs_string, lhs_params = qn.compile(lhs)
113
+ lhs_string, lhs_params = compiler.compile(lhs)
93
114
  if connection.vendor == "postgresql":
94
115
  raise NotSupportedError("Lookup not supported on postgresql.")
95
116
  return f"INET6_NTOA({lhs_string})", lhs_params
@@ -129,6 +150,7 @@ class IRegex(StringMatchMixin, lookups.IRegex):
129
150
 
130
151
  class NetworkFieldMixin:
131
152
  def get_prep_lookup(self):
153
+ self.alias = self.lhs.alias
132
154
  field_name = self.lhs.field.name
133
155
  if field_name not in ["host", "network"]:
134
156
  raise NotSupportedError(f"Lookup only provided on the host and network fields, not {field_name}.")
@@ -139,8 +161,8 @@ class NetworkFieldMixin:
139
161
  self.ip = get_ip_info(field_name, self.rhs, alias=self.lhs.alias)
140
162
  return str(self.ip.ip)
141
163
 
142
- def process_rhs(self, qn, connection):
143
- sql, params = super().process_rhs(qn, connection)
164
+ def process_rhs(self, compiler, connection):
165
+ sql, params = super().process_rhs(compiler, connection)
144
166
  params[0] = self.ip.rhs
145
167
  return sql, params
146
168
 
@@ -148,50 +170,67 @@ class NetworkFieldMixin:
148
170
  class NetEquals(NetworkFieldMixin, Lookup):
149
171
  lookup_name = "net_equals"
150
172
 
151
- def as_sql(self, qn, connection):
152
- _, lhs_params = self.process_lhs(qn, connection)
153
- rhs, rhs_params = self.process_rhs(qn, connection)
154
- query = f"prefix_length = {self.ip.prefix} AND {rhs} = {self.ip.q_ip}"
173
+ def as_sql(self, compiler, connection):
174
+ _, lhs_params = self.process_lhs(compiler, connection)
175
+ rhs, rhs_params = self.process_rhs(compiler, connection)
176
+ if self.alias:
177
+ query = f"{self.alias}.prefix_length = {self.ip.prefix} AND {rhs} = {self.ip.q_ip}"
178
+ else:
179
+ query = f"prefix_length = {self.ip.prefix} AND {rhs} = {self.ip.q_ip}"
155
180
  return query, lhs_params + rhs_params
156
181
 
157
182
 
158
183
  class NetContainsOrEquals(NetworkFieldMixin, Lookup):
159
184
  lookup_name = "net_contains_or_equals"
160
185
 
161
- def as_sql(self, qn, connection):
162
- _, lhs_params = self.process_lhs(qn, connection)
163
- rhs, rhs_params = self.process_rhs(qn, connection)
164
- query = f"prefix_length <= {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
186
+ def as_sql(self, compiler, connection):
187
+ _, lhs_params = self.process_lhs(compiler, connection)
188
+ rhs, rhs_params = self.process_rhs(compiler, connection)
189
+ if self.alias:
190
+ query = f"{self.alias}.prefix_length <= {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
191
+ else:
192
+ query = f"prefix_length <= {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
165
193
  return query, lhs_params + rhs_params
166
194
 
167
195
 
168
196
  class NetContains(NetworkFieldMixin, Lookup):
169
197
  lookup_name = "net_contains"
170
198
 
171
- def as_sql(self, qn, connection):
172
- _, lhs_params = self.process_lhs(qn, connection)
173
- rhs, rhs_params = self.process_rhs(qn, connection)
174
- query = f"prefix_length < {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
199
+ def as_sql(self, compiler, connection):
200
+ _, lhs_params = self.process_lhs(compiler, connection)
201
+ rhs, rhs_params = self.process_rhs(compiler, connection)
202
+ if self.alias:
203
+ query = (
204
+ f"{self.alias}.prefix_length < {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
205
+ )
206
+ else:
207
+ query = f"prefix_length < {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
175
208
  return query, lhs_params + rhs_params
176
209
 
177
210
 
178
211
  class NetContainedOrEqual(NetworkFieldMixin, Lookup):
179
212
  lookup_name = "net_contained_or_equal"
180
213
 
181
- def as_sql(self, qn, connection):
182
- _, lhs_params = self.process_lhs(qn, connection)
183
- rhs, rhs_params = self.process_rhs(qn, connection)
184
- query = f"prefix_length >= {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
214
+ def as_sql(self, compiler, connection):
215
+ _, lhs_params = self.process_lhs(compiler, connection)
216
+ rhs, rhs_params = self.process_rhs(compiler, connection)
217
+ if self.alias:
218
+ query = f"{self.alias}.prefix_length >= {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
219
+ else:
220
+ query = f"prefix_length >= {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
185
221
  return query, lhs_params + rhs_params
186
222
 
187
223
 
188
224
  class NetContained(NetworkFieldMixin, Lookup):
189
225
  lookup_name = "net_contained"
190
226
 
191
- def as_sql(self, qn, connection):
192
- _, lhs_params = self.process_lhs(qn, connection)
193
- rhs, rhs_params = self.process_rhs(qn, connection)
194
- query = f"prefix_length > {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
227
+ def as_sql(self, compiler, connection):
228
+ _, lhs_params = self.process_lhs(compiler, connection)
229
+ rhs, rhs_params = self.process_rhs(compiler, connection)
230
+ if self.alias:
231
+ query = f"{self.alias}.prefix_length > {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
232
+ else:
233
+ query = f"prefix_length > {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
195
234
  return query, lhs_params + rhs_params
196
235
 
197
236
 
@@ -205,19 +244,19 @@ class NetHost(Lookup):
205
244
  self.ip = get_ip_info(field_name, self.rhs, alias=self.lhs.alias)
206
245
  return str(self.ip.ip)
207
246
 
208
- def process_rhs(self, qn, connection):
209
- sql, params = super().process_rhs(qn, connection)
247
+ def process_rhs(self, compiler, connection):
248
+ sql, params = super().process_rhs(compiler, connection)
210
249
  params[0] = self.ip.rhs
211
250
  return sql, params
212
251
 
213
- def process_lhs(self, qn, connection, lhs=None):
252
+ def process_lhs(self, compiler, connection, lhs=None):
214
253
  lhs = lhs or self.lhs
215
- _, lhs_params = qn.compile(lhs)
254
+ _, lhs_params = compiler.compile(lhs)
216
255
  return self.ip.q_ip, lhs_params
217
256
 
218
- def as_sql(self, qn, connection):
219
- lhs, lhs_params = self.process_lhs(qn, connection)
220
- rhs, rhs_params = self.process_rhs(qn, connection)
257
+ def as_sql(self, compiler, connection):
258
+ lhs, lhs_params = self.process_lhs(compiler, connection)
259
+ rhs, rhs_params = self.process_rhs(compiler, connection)
221
260
  return f"{lhs} = {rhs}", lhs_params + rhs_params
222
261
 
223
262
 
@@ -242,9 +281,9 @@ class NetIn(Lookup):
242
281
  self.query_starter = "'1' != ANY(%s) AND "
243
282
  return self.rhs
244
283
 
245
- def as_sql(self, qn, connection):
246
- _, lhs_params = self.process_lhs(qn, connection)
247
- _, rhs_params = self.process_rhs(qn, connection)
284
+ def as_sql(self, compiler, connection):
285
+ _, lhs_params = self.process_lhs(compiler, connection)
286
+ _, rhs_params = self.process_rhs(compiler, connection)
248
287
  query = self.query_starter
249
288
  query += "OR ".join(f"{ip.q_ip} BETWEEN {ip.net_addr} AND {ip.bcast_addr} " for ip in self.ips)
250
289
  return query, lhs_params + rhs_params
@@ -253,9 +292,9 @@ class NetIn(Lookup):
253
292
  class NetHostContained(NetworkFieldMixin, Lookup):
254
293
  lookup_name = "net_host_contained"
255
294
 
256
- def as_sql(self, qn, connection):
257
- _, lhs_params = self.process_lhs(qn, connection)
258
- rhs, rhs_params = self.process_rhs(qn, connection)
295
+ def as_sql(self, compiler, connection):
296
+ _, lhs_params = self.process_lhs(compiler, connection)
297
+ rhs, rhs_params = self.process_rhs(compiler, connection)
259
298
  query = f"{self.ip.q_ip} BETWEEN {rhs} AND {self.ip.bcast_addr}"
260
299
  return query, lhs_params + rhs_params
261
300
 
@@ -270,12 +309,12 @@ class NetFamily(Lookup):
270
309
  self.rhs = 16
271
310
  return self.rhs
272
311
 
273
- def process_lhs(self, qn, connection, lhs=None):
312
+ def process_lhs(self, compiler, connection, lhs=None):
274
313
  lhs = lhs or self.lhs
275
- lhs_string, lhs_params = qn.compile(lhs)
314
+ lhs_string, lhs_params = compiler.compile(lhs)
276
315
  return f"LENGTH({lhs_string})", lhs_params
277
316
 
278
- def as_sql(self, qn, connection):
279
- lhs, lhs_params = self.process_lhs(qn, connection)
280
- rhs, rhs_params = self.process_rhs(qn, connection)
317
+ def as_sql(self, compiler, connection):
318
+ lhs, lhs_params = self.process_lhs(compiler, connection)
319
+ rhs, rhs_params = self.process_rhs(compiler, connection)
281
320
  return f"{lhs} = {rhs}", lhs_params + rhs_params
nautobot/ipam/models.py CHANGED
@@ -27,18 +27,18 @@ from .querysets import IPAddressQuerySet, PrefixQuerySet, RIRQuerySet, VLANQuery
27
27
  from .validators import DNSValidator
28
28
 
29
29
  __all__ = (
30
+ "RIR",
31
+ "VLAN",
32
+ "VRF",
30
33
  "IPAddress",
31
34
  "IPAddressToInterface",
32
35
  "Namespace",
33
36
  "Prefix",
34
37
  "PrefixLocationAssignment",
35
- "RIR",
36
38
  "RouteTarget",
37
39
  "Service",
38
- "VLAN",
39
40
  "VLANGroup",
40
41
  "VLANLocationAssignment",
41
- "VRF",
42
42
  "VRFDeviceAssignment",
43
43
  "VRFPrefixAssignment",
44
44
  )
@@ -531,8 +531,32 @@ class Prefix(PrimaryModel):
531
531
  prefix = kwargs.pop("prefix", None)
532
532
  self._location = kwargs.pop("location", None)
533
533
  super().__init__(*args, **kwargs)
534
+
535
+ # Initialize cached fields
536
+ self._parent = None
537
+ self._network = None
538
+ self._prefix_length = None
539
+ self._namespace_id = None
540
+
534
541
  self._deconstruct_prefix(prefix)
535
542
 
543
+ @staticmethod
544
+ def _extract_field_value(field_name, field_names, values):
545
+ for current_field, field_value in zip(field_names, values):
546
+ if field_name == current_field:
547
+ return field_value
548
+ return None
549
+
550
+ @classmethod
551
+ def from_db(cls, db, field_names, values):
552
+ instance = super().from_db(db, field_names, values)
553
+ # These cached values are used to detect changes during save,
554
+ # avoiding unnecessary re-parenting of subnets and IPs if these fields have not been updated.
555
+ instance._network = cls._extract_field_value("network", field_names, values)
556
+ instance._prefix_length = cls._extract_field_value("prefix_length", field_names, values)
557
+ instance._namespace_id = cls._extract_field_value("namespace_id", field_names, values)
558
+ return instance
559
+
536
560
  def __str__(self):
537
561
  return str(self.prefix)
538
562
 
@@ -612,18 +636,30 @@ class Prefix(PrimaryModel):
612
636
  protected_objects.update(parent=self.parent)
613
637
  return super().delete(*args, **kwargs)
614
638
 
615
- def save(self, *args, **kwargs):
616
- if isinstance(self.prefix, netaddr.IPNetwork):
639
+ def get_parent(self):
640
+ # Determine if a parent exists and set it to the closest ancestor by `prefix_length`.
641
+ if self._parent is not None:
642
+ return self._parent
643
+
644
+ if supernets := self.supernets():
645
+ parent = max(supernets, key=operator.attrgetter("prefix_length"))
646
+ self._parent = parent
647
+ return parent
648
+ return None
649
+
650
+ def clean(self):
651
+ if self.prefix is not None: # missing network/prefix_length will be caught by super().clean()
617
652
  # Clear host bits from prefix
618
653
  # This also has the subtle side effect of calling self._deconstruct_prefix(),
619
654
  # which will (re)set the broadcast and ip_version values of this instance to their correct values.
620
655
  self.prefix = self.prefix.cidr
621
656
 
622
- # Determine if a parent exists and set it to the closest ancestor by `prefix_length`.
623
- supernets = self.supernets()
624
- if supernets:
625
- parent = max(supernets, key=operator.attrgetter("prefix_length"))
626
- self.parent = parent
657
+ self.parent = self.get_parent()
658
+
659
+ super().clean()
660
+
661
+ def save(self, *args, **kwargs):
662
+ self.clean()
627
663
 
628
664
  # Validate that creation of this prefix does not create an invalid parent/child relationship
629
665
  # 3.0 TODO: uncomment this to enforce this constraint
@@ -655,15 +691,26 @@ class Prefix(PrimaryModel):
655
691
  # )
656
692
  # raise ValidationError({"__all__": err_msg})
657
693
 
694
+ # cache the value of present_in_database; because after `super().save()`
695
+ # `self.present_in_database` would always return True`
696
+ present_in_database = self.present_in_database
697
+
658
698
  with transaction.atomic():
659
699
  super().save(*args, **kwargs)
660
700
  if self._location is not None:
661
701
  self.location = self._location
662
702
 
663
- # Determine the subnets and reparent them to this prefix.
664
- self.reparent_subnets()
665
- # Determine the child IPs and reparent them to this prefix.
666
- self.reparent_ips()
703
+ # Only reparent subnets and ips if any of these fields has been updated.
704
+ if (
705
+ not present_in_database
706
+ or self._network != self.network
707
+ or self._namespace_id != self.namespace_id
708
+ or self._prefix_length != self.prefix_length
709
+ ):
710
+ # Determine the subnets and reparent them to this prefix.
711
+ self.reparent_subnets()
712
+ # Determine the child IPs and reparent them to this prefix.
713
+ self.reparent_ips()
667
714
 
668
715
  @property
669
716
  def cidr_str(self):
@@ -739,6 +786,7 @@ class Prefix(PrimaryModel):
739
786
  Returns:
740
787
  QuerySet
741
788
  """
789
+
742
790
  query = Prefix.objects.all()
743
791
 
744
792
  if for_update:
@@ -750,7 +798,7 @@ class Prefix(PrimaryModel):
750
798
  if not include_self:
751
799
  query = query.exclude(id=self.id)
752
800
 
753
- return query.filter(
801
+ supernets = query.filter(
754
802
  ip_version=self.ip_version,
755
803
  prefix_length__lte=self.prefix_length,
756
804
  network__lte=self.network,
@@ -758,6 +806,8 @@ class Prefix(PrimaryModel):
758
806
  namespace=self.namespace,
759
807
  )
760
808
 
809
+ return supernets
810
+
761
811
  def subnets(self, direct=False, include_self=False, for_update=False):
762
812
  """
763
813
  Return subnets of this Prefix.
@@ -867,7 +917,7 @@ class Prefix(PrimaryModel):
867
917
  Return all available IPs within this prefix as an IPSet.
868
918
  """
869
919
  prefix = netaddr.IPSet(self.prefix)
870
- child_ips = netaddr.IPSet([ip.address.ip for ip in self.ip_addresses.all()])
920
+ child_ips = netaddr.IPSet([ip.address.ip for ip in self.get_all_ips()])
871
921
  available_ips = prefix - child_ips
872
922
 
873
923
  # IPv6, pool, or IPv4 /31-32 sets are fully usable
@@ -398,7 +398,7 @@ class IPAddressQuerySet(BaseNetworkQuerySet):
398
398
  """
399
399
  return super().order_by("host")
400
400
 
401
- def get_or_create(self, **kwargs):
401
+ def get_or_create(self, defaults=None, **kwargs):
402
402
  from nautobot.ipam.models import get_default_namespace, Prefix
403
403
 
404
404
  parent = kwargs.get("parent")
@@ -421,7 +421,7 @@ class IPAddressQuerySet(BaseNetworkQuerySet):
421
421
  raise ValidationError(f"{cidr} does not appear to be an IPv4 or IPv6 network.") from err
422
422
  parent = Prefix.objects.filter(namespace=namespace).get_closest_parent(cidr=cidr, include_self=True)
423
423
  kwargs["parent"] = parent
424
- return super().get_or_create(**kwargs)
424
+ return super().get_or_create(defaults=defaults, **kwargs)
425
425
 
426
426
  def string_search(self, search):
427
427
  """
nautobot/ipam/tables.py CHANGED
@@ -43,9 +43,11 @@ UTILIZATION_GRAPH = """
43
43
  """
44
44
 
45
45
 
46
+ # record: the Prefix being rendered in this row
47
+ # object: the base ancestor Prefix, in the case of PrefixDetailTable, else None
46
48
  PREFIX_COPY_LINK = """
47
49
  {% load helpers %}
48
- {% tree_hierarchy_ui_representation record.ancestors.count|as_range table.hide_hierarchy_ui%}
50
+ {% tree_hierarchy_ui_representation record.ancestors.count|as_range table.hide_hierarchy_ui base_tree_depth|default:0 %}
49
51
  <span class="hover_copy">
50
52
  <a href="\
51
53
  {% if record.present_in_database %}\
@@ -404,7 +406,7 @@ class PrefixDetailTable(PrefixTable):
404
406
  "type",
405
407
  "status",
406
408
  "children",
407
- # "vrf",
409
+ "vrf_count",
408
410
  "utilization",
409
411
  "tenant",
410
412
  "location_count",
@@ -420,7 +422,7 @@ class PrefixDetailTable(PrefixTable):
420
422
  "type",
421
423
  "status",
422
424
  "children",
423
- # "vrf",
425
+ "vrf_count",
424
426
  "utilization",
425
427
  "tenant",
426
428
  "location_count",
@@ -442,13 +444,27 @@ class IPAddressTable(StatusTableMixin, RoleTableMixin, BaseTable):
442
444
  )
443
445
  tenant = TenantColumn()
444
446
  parent__namespace = tables.Column(linkify=True)
445
- # Interface, Device, and VirtualMachine tables aren't currently filterable by IP address (?) so no LinkedCountColumn
446
- interface_count = tables.Column(verbose_name="Interfaces")
447
- interface_parent_count = tables.Column(verbose_name="Devices")
447
+ interface_count = LinkedCountColumn(
448
+ viewname="dcim:interface_list", url_params={"ip_addresses": "pk"}, verbose_name="Interfaces"
449
+ )
450
+ # TODO: what about interfaces assigned to modules?
451
+ interface_parent_count = LinkedCountColumn(
452
+ viewname="dcim:device_list",
453
+ url_params={"ip_addresses": "pk"},
454
+ reverse_lookup="interfaces__ip_addresses",
455
+ distinct=True,
456
+ verbose_name="Devices",
457
+ )
448
458
  vm_interface_count = LinkedCountColumn(
449
459
  viewname="virtualization:vminterface_list", url_params={"ip_addresses": "pk"}, verbose_name="VM Interfaces"
450
460
  )
451
- vm_interface_parent_count = tables.Column(verbose_name="Virtual Machines")
461
+ vm_interface_parent_count = LinkedCountColumn(
462
+ viewname="virtualization:virtualmachine_list",
463
+ url_params={"ip_addresses": "pk"},
464
+ reverse_lookup="interfaces__ip_addresses",
465
+ distinct=True,
466
+ verbose_name="Virtual Machines",
467
+ )
452
468
 
453
469
  class Meta(BaseTable.Meta):
454
470
  model = IPAddress
@@ -83,15 +83,7 @@
83
83
  <strong>Operational Details</strong>
84
84
  </div>
85
85
  <table class="table table-hover panel-body attr-table">
86
- <tr>
87
- <td>Tenant</td>
88
- <td>
89
- {% if object.tenant and object.tenant.tenant_group %}
90
- {{ object.tenant.tenant_group|hyperlinked_object }} /
91
- {% endif %}
92
- {{ object.tenant|hyperlinked_object }}
93
- </td>
94
- </tr>
86
+ {% include 'inc/tenant_table_row.html' %}
95
87
  <tr>
96
88
  <td>Assignment</td>
97
89
  <td>
@@ -21,12 +21,6 @@
21
21
  {% render_field model_form.description %}
22
22
  </div>
23
23
  </div>
24
- <div class="panel panel-default">
25
- <div class="panel-heading"><strong>Tenancy</strong></div>
26
- <div class="panel-body">
27
- {% render_field model_form.tenant_group %}
28
- {% render_field model_form.tenant %}
29
- </div>
30
- </div>
24
+ {% include 'inc/tenancy_form_panel.html' %}
31
25
  {% include 'inc/extras_features_edit_form_fields.html' with form=model_form %}
32
26
  {% endblock %}
@@ -22,13 +22,7 @@
22
22
  {% render_field form.description %}
23
23
  </div>
24
24
  </div>
25
- <div class="panel panel-default">
26
- <div class="panel-heading"><strong>Tenancy</strong></div>
27
- <div class="panel-body">
28
- {% render_field form.tenant_group %}
29
- {% render_field form.tenant %}
30
- </div>
31
- </div>
25
+ {% include 'inc/tenancy_form_panel.html' %}
32
26
  <div class="panel panel-default">
33
27
  <div class="panel-heading"><strong>NAT IP (Inside)</strong></div>
34
28
  <div class="panel-body">
@@ -68,15 +68,7 @@
68
68
  {{ object.get_type_display }}
69
69
  </td>
70
70
  </tr>
71
- <tr>
72
- <td>Tenant</td>
73
- <td>
74
- {% if object.tenant and object.tenant.tenant_group %}
75
- {{ object.tenant.tenant_group|hyperlinked_object }} /
76
- {% endif %}
77
- {{ object.tenant|hyperlinked_object }}
78
- </td>
79
- </tr>
71
+ {% include 'inc/tenant_table_row.html' %}
80
72
  <tr>
81
73
  <td>Locations</td>
82
74
  <td>
@@ -29,12 +29,6 @@
29
29
  {% render_field form.vlan %}
30
30
  </div>
31
31
  </div>
32
- <div class="panel panel-default">
33
- <div class="panel-heading"><strong>Tenancy</strong></div>
34
- <div class="panel-body">
35
- {% render_field form.tenant_group %}
36
- {% render_field form.tenant %}
37
- </div>
38
- </div>
32
+ {% include 'inc/tenancy_form_panel.html' %}
39
33
  {% include 'inc/extras_features_edit_form_fields.html' %}
40
34
  {% endblock %}
@@ -44,15 +44,7 @@
44
44
  <td>Name</td>
45
45
  <td>{{ object.name }}</td>
46
46
  </tr>
47
- <tr>
48
- <td>Tenant</td>
49
- <td>
50
- {% if object.tenant and object.tenant.tenant_group %}
51
- {{ object.tenant.tenant_group|hyperlinked_object }} /
52
- {% endif %}
53
- {{ object.tenant|hyperlinked_object }}
54
- </td>
55
- </tr>
47
+ {% include 'inc/tenant_table_row.html' %}
56
48
  <tr>
57
49
  <td>Status</td>
58
50
  <td>
@@ -19,12 +19,6 @@
19
19
  {% render_field form.vlan_group %}
20
20
  </div>
21
21
  </div>
22
- <div class="panel panel-default">
23
- <div class="panel-heading"><strong>Tenancy</strong></div>
24
- <div class="panel-body">
25
- {% render_field form.tenant_group %}
26
- {% render_field form.tenant %}
27
- </div>
28
- </div>
22
+ {% include 'inc/tenancy_form_panel.html' %}
29
23
  {% include 'inc/extras_features_edit_form_fields.html' %}
30
24
  {% endblock %}
@@ -37,12 +37,6 @@
37
37
  {% render_field form.export_targets %}
38
38
  </div>
39
39
  </div>
40
- <div class="panel panel-default">
41
- <div class="panel-heading"><strong>Tenancy</strong></div>
42
- <div class="panel-body">
43
- {% render_field form.tenant_group %}
44
- {% render_field form.tenant %}
45
- </div>
46
- </div>
40
+ {% include 'inc/tenancy_form_panel.html' %}
47
41
  {% include 'inc/extras_features_edit_form_fields.html' %}
48
42
  {% endblock %}