nautobot 2.2.9__py3-none-any.whl → 2.3.0__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 (697) hide show
  1. nautobot/apps/forms.py +4 -0
  2. nautobot/apps/models.py +10 -1
  3. nautobot/circuits/__init__.py +0 -1
  4. nautobot/circuits/apps.py +1 -0
  5. nautobot/circuits/factory.py +15 -3
  6. nautobot/circuits/filters.py +13 -0
  7. nautobot/circuits/forms.py +13 -0
  8. nautobot/circuits/migrations/0021_alter_circuit_status_alter_circuittermination__path.py +32 -0
  9. nautobot/circuits/migrations/0022_circuittermination_cloud_network.py +25 -0
  10. nautobot/circuits/models.py +16 -3
  11. nautobot/circuits/tables.py +16 -2
  12. nautobot/circuits/templates/circuits/circuittermination_create.html +10 -2
  13. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +6 -0
  14. nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -1
  15. nautobot/circuits/tests/test_api.py +7 -5
  16. nautobot/circuits/tests/test_filters.py +12 -5
  17. nautobot/circuits/tests/test_models.py +33 -2
  18. nautobot/circuits/views.py +2 -3
  19. nautobot/cloud/__init__.py +0 -0
  20. nautobot/cloud/api/__init__.py +0 -0
  21. nautobot/cloud/api/serializers.py +54 -0
  22. nautobot/cloud/api/urls.py +16 -0
  23. nautobot/cloud/api/views.py +48 -0
  24. nautobot/cloud/apps.py +13 -0
  25. nautobot/cloud/factory.py +113 -0
  26. nautobot/cloud/filters.py +187 -0
  27. nautobot/cloud/forms.py +339 -0
  28. nautobot/cloud/homepage.py +43 -0
  29. nautobot/cloud/migrations/0001_initial.py +304 -0
  30. nautobot/cloud/migrations/__init__.py +0 -0
  31. nautobot/cloud/models.py +246 -0
  32. nautobot/cloud/navigation.py +85 -0
  33. nautobot/cloud/tables.py +157 -0
  34. nautobot/cloud/templates/cloud/cloudaccount_retrieve.html +43 -0
  35. nautobot/cloud/templates/cloud/cloudnetwork_retrieve.html +122 -0
  36. nautobot/cloud/templates/cloud/cloudnetwork_update.html +33 -0
  37. nautobot/cloud/templates/cloud/cloudresourcetype_retrieve.html +111 -0
  38. nautobot/cloud/templates/cloud/cloudservice_retrieve.html +69 -0
  39. nautobot/cloud/templates/cloud/cloudservice_update.html +25 -0
  40. nautobot/cloud/tests/__init__.py +0 -0
  41. nautobot/cloud/tests/test_api.py +248 -0
  42. nautobot/cloud/tests/test_filters.py +125 -0
  43. nautobot/cloud/tests/test_models.py +43 -0
  44. nautobot/cloud/tests/test_views.py +153 -0
  45. nautobot/cloud/urls.py +14 -0
  46. nautobot/cloud/views.py +181 -0
  47. nautobot/core/__init__.py +0 -3
  48. nautobot/core/api/metadata.py +1 -0
  49. nautobot/core/api/parsers.py +7 -1
  50. nautobot/core/api/urls.py +1 -0
  51. nautobot/core/api/utils.py +1 -0
  52. nautobot/core/api/views.py +4 -0
  53. nautobot/core/apps/__init__.py +6 -3
  54. nautobot/core/constants.py +8 -0
  55. nautobot/core/factory.py +32 -1
  56. nautobot/core/filters.py +95 -13
  57. nautobot/core/forms/fields.py +10 -4
  58. nautobot/core/forms/forms.py +11 -3
  59. nautobot/core/forms/widgets.py +18 -1
  60. nautobot/core/graphql/schema.py +26 -4
  61. nautobot/core/jobs/__init__.py +16 -2
  62. nautobot/core/jobs/cleanup.py +100 -0
  63. nautobot/core/jobs/groups.py +38 -0
  64. nautobot/core/management/commands/generate_test_data.py +116 -3
  65. nautobot/core/models/__init__.py +34 -9
  66. nautobot/core/models/generics.py +19 -3
  67. nautobot/core/models/name_color_content_types.py +7 -28
  68. nautobot/core/models/querysets.py +4 -3
  69. nautobot/core/models/tree_queries.py +1 -1
  70. nautobot/core/models/utils.py +21 -5
  71. nautobot/core/settings.py +2 -17
  72. nautobot/core/settings.yaml +34 -13
  73. nautobot/core/settings_funcs.py +103 -0
  74. nautobot/core/tables.py +130 -56
  75. nautobot/core/templates/admin/search_form.html +1 -1
  76. nautobot/core/templates/buttons/add.html +11 -3
  77. nautobot/core/templates/buttons/consolidated_bulk_action_buttons.html +13 -0
  78. nautobot/core/templates/buttons/consolidated_detail_view_action_buttons.html +13 -0
  79. nautobot/core/templates/buttons/export.html +101 -53
  80. nautobot/core/templates/buttons/job_import.html +11 -3
  81. nautobot/core/templates/generic/object_bulk_destroy.html +3 -1
  82. nautobot/core/templates/generic/object_bulk_update.html +3 -1
  83. nautobot/core/templates/generic/object_changelog.html +0 -9
  84. nautobot/core/templates/generic/object_list.html +156 -17
  85. nautobot/core/templates/generic/object_retrieve.html +80 -16
  86. nautobot/core/templates/inc/extras_features_edit_form_fields.html +8 -0
  87. nautobot/core/templates/inc/javascript.html +2 -0
  88. nautobot/core/templates/inc/media.html +2 -2
  89. nautobot/core/templates/inc/nav_menu.html +1 -0
  90. nautobot/core/templates/inc/paginator.html +7 -7
  91. nautobot/core/templates/inc/search_panel.html +2 -2
  92. nautobot/core/templates/inc/table.html +2 -2
  93. nautobot/core/templates/nautobot_config.py.j2 +13 -8
  94. nautobot/core/templates/utilities/templatetags/dynamic_group_assignment_modal.html +37 -0
  95. nautobot/core/templates/utilities/templatetags/filter_form_modal.html +2 -2
  96. nautobot/core/templates/utilities/templatetags/saved_view_modal.html +38 -0
  97. nautobot/core/templates/utilities/theme_preview.html +25 -8
  98. nautobot/core/templates/utilities/worker_status.html +152 -0
  99. nautobot/core/templatetags/buttons.py +335 -38
  100. nautobot/core/templatetags/form_helpers.py +1 -1
  101. nautobot/core/templatetags/helpers.py +181 -11
  102. nautobot/core/testing/api.py +5 -4
  103. nautobot/core/testing/filters.py +63 -14
  104. nautobot/core/testing/mixins.py +46 -0
  105. nautobot/core/testing/models.py +22 -0
  106. nautobot/core/testing/schema.py +4 -8
  107. nautobot/core/testing/views.py +31 -14
  108. nautobot/core/tests/integration/test_import_objects_ui.py +1 -0
  109. nautobot/core/tests/integration/test_swagger.py +1 -1
  110. nautobot/core/tests/nautobot_config.py +0 -1
  111. nautobot/core/tests/runner.py +2 -2
  112. nautobot/core/tests/test_api.py +1 -0
  113. nautobot/core/tests/test_authentication.py +7 -2
  114. nautobot/core/tests/test_filters.py +11 -9
  115. nautobot/core/tests/test_forms.py +9 -0
  116. nautobot/core/tests/test_graphql.py +27 -16
  117. nautobot/core/tests/test_jobs.py +122 -0
  118. nautobot/core/tests/test_tables.py +3 -1
  119. nautobot/core/tests/test_templatetags_helpers.py +12 -5
  120. nautobot/core/tests/test_utils.py +31 -20
  121. nautobot/core/tests/test_views.py +6 -6
  122. nautobot/core/urls.py +8 -3
  123. nautobot/core/utils/deprecation.py +29 -0
  124. nautobot/core/utils/filtering.py +12 -9
  125. nautobot/core/utils/lookup.py +37 -2
  126. nautobot/core/utils/requests.py +4 -1
  127. nautobot/core/views/__init__.py +137 -24
  128. nautobot/core/views/generic.py +119 -67
  129. nautobot/core/views/mixins.py +105 -36
  130. nautobot/core/views/paginator.py +9 -3
  131. nautobot/core/views/renderers.py +121 -56
  132. nautobot/core/views/utils.py +81 -1
  133. nautobot/dcim/__init__.py +0 -1
  134. nautobot/dcim/api/serializers.py +180 -44
  135. nautobot/dcim/api/urls.py +7 -3
  136. nautobot/dcim/api/views.py +53 -7
  137. nautobot/dcim/apps.py +3 -0
  138. nautobot/dcim/choices.py +25 -0
  139. nautobot/dcim/constants.py +7 -0
  140. nautobot/dcim/factory.py +252 -18
  141. nautobot/dcim/filters/__init__.py +373 -193
  142. nautobot/dcim/filters/mixins.py +274 -1
  143. nautobot/dcim/forms.py +834 -121
  144. nautobot/dcim/graphql/types.py +2 -2
  145. nautobot/dcim/homepage.py +1 -1
  146. nautobot/dcim/migrations/0059_add_role_field_to_interface_models.py +27 -0
  147. nautobot/dcim/migrations/0060_alter_cable_status_alter_consoleport__path_and_more.py +303 -0
  148. nautobot/dcim/migrations/0061_module_models.py +862 -0
  149. nautobot/dcim/migrations/0062_module_data_migration.py +25 -0
  150. nautobot/dcim/models/__init__.py +8 -0
  151. nautobot/dcim/models/cables.py +15 -0
  152. nautobot/dcim/models/device_component_templates.py +207 -53
  153. nautobot/dcim/models/device_components.py +275 -99
  154. nautobot/dcim/models/devices.py +468 -13
  155. nautobot/dcim/models/racks.py +0 -1
  156. nautobot/dcim/navigation.py +47 -0
  157. nautobot/dcim/signals.py +3 -3
  158. nautobot/dcim/tables/__init__.py +35 -23
  159. nautobot/dcim/tables/devices.py +229 -43
  160. nautobot/dcim/tables/devicetypes.py +65 -9
  161. nautobot/dcim/tables/racks.py +5 -1
  162. nautobot/dcim/tables/template_code.py +46 -26
  163. nautobot/dcim/templates/dcim/cable_connect.html +76 -3
  164. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -5
  165. nautobot/dcim/templates/dcim/device/base.html +14 -6
  166. nautobot/dcim/templates/dcim/device/consoleports.html +2 -3
  167. nautobot/dcim/templates/dcim/device/consoleserverports.html +2 -3
  168. nautobot/dcim/templates/dcim/device/devicebays.html +6 -7
  169. nautobot/dcim/templates/dcim/device/frontports.html +2 -3
  170. nautobot/dcim/templates/dcim/device/interfaces.html +2 -3
  171. nautobot/dcim/templates/dcim/device/inventory.html +2 -3
  172. nautobot/dcim/templates/dcim/device/modulebays.html +49 -0
  173. nautobot/dcim/templates/dcim/device/poweroutlets.html +2 -3
  174. nautobot/dcim/templates/dcim/device/powerports.html +2 -3
  175. nautobot/dcim/templates/dcim/device/rearports.html +2 -3
  176. nautobot/dcim/templates/dcim/device.html +45 -1
  177. nautobot/dcim/templates/dcim/device_component.html +13 -5
  178. nautobot/dcim/templates/dcim/device_list.html +2 -1
  179. nautobot/dcim/templates/dcim/devicetype.html +99 -98
  180. nautobot/dcim/templates/dcim/devicetype_list.html +8 -16
  181. nautobot/dcim/templates/dcim/inc/devicetype_component_table.html +1 -1
  182. nautobot/dcim/templates/dcim/inc/moduletype_component_table.html +39 -0
  183. nautobot/dcim/templates/dcim/interface.html +17 -2
  184. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -5
  185. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  186. nautobot/dcim/templates/dcim/manufacturer.html +24 -0
  187. nautobot/dcim/templates/dcim/module/base.html +97 -0
  188. nautobot/dcim/templates/dcim/module_bulk_destroy.html +5 -0
  189. nautobot/dcim/templates/dcim/module_consoleports.html +53 -0
  190. nautobot/dcim/templates/dcim/module_consoleserverports.html +53 -0
  191. nautobot/dcim/templates/dcim/module_destroy.html +5 -0
  192. nautobot/dcim/templates/dcim/module_frontports.html +53 -0
  193. nautobot/dcim/templates/dcim/module_interfaces.html +57 -0
  194. nautobot/dcim/templates/dcim/module_list.html +20 -0
  195. nautobot/dcim/templates/dcim/module_modulebays.html +49 -0
  196. nautobot/dcim/templates/dcim/module_poweroutlets.html +53 -0
  197. nautobot/dcim/templates/dcim/module_powerports.html +53 -0
  198. nautobot/dcim/templates/dcim/module_rearports.html +53 -0
  199. nautobot/dcim/templates/dcim/module_retrieve.html +63 -0
  200. nautobot/dcim/templates/dcim/module_update.html +71 -0
  201. nautobot/dcim/templates/dcim/modulebay_bulk_destroy.html +5 -0
  202. nautobot/dcim/templates/dcim/modulebay_destroy.html +8 -0
  203. nautobot/dcim/templates/dcim/modulebay_retrieve.html +101 -0
  204. nautobot/dcim/templates/dcim/moduletype_list.html +11 -0
  205. nautobot/dcim/templates/dcim/moduletype_retrieve.html +159 -0
  206. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -5
  207. nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +65 -19
  208. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  209. nautobot/dcim/tests/test_api.py +693 -208
  210. nautobot/dcim/tests/test_filters.py +843 -217
  211. nautobot/dcim/tests/test_models.py +1072 -8
  212. nautobot/dcim/tests/test_views.py +1510 -341
  213. nautobot/dcim/urls.py +17 -2
  214. nautobot/dcim/utils.py +2 -3
  215. nautobot/dcim/views.py +1106 -116
  216. nautobot/extras/__init__.py +0 -1
  217. nautobot/extras/api/serializers.py +115 -3
  218. nautobot/extras/api/urls.py +12 -0
  219. nautobot/extras/api/views.py +66 -0
  220. nautobot/extras/apps.py +2 -2
  221. nautobot/extras/choices.py +43 -0
  222. nautobot/extras/context_managers.py +13 -8
  223. nautobot/extras/datasources/git.py +2 -0
  224. nautobot/extras/factory.py +460 -9
  225. nautobot/extras/filters/__init__.py +174 -3
  226. nautobot/extras/filters/mixins.py +46 -43
  227. nautobot/extras/forms/base.py +24 -5
  228. nautobot/extras/forms/forms.py +227 -8
  229. nautobot/extras/forms/mixins.py +93 -0
  230. nautobot/extras/graphql/types.py +23 -10
  231. nautobot/extras/homepage.py +14 -1
  232. nautobot/extras/management/__init__.py +1 -0
  233. nautobot/extras/management/commands/refresh_dynamic_group_member_caches.py +1 -16
  234. nautobot/extras/migrations/0021_customfield_changelog_data.py +1 -0
  235. nautobot/extras/migrations/0109_dynamicgroup_group_type_dynamicgroup_tags_and_more.py +108 -0
  236. nautobot/extras/migrations/0110_alter_configcontext_cluster_groups_and_more.py +111 -0
  237. nautobot/extras/migrations/0111_metadata.py +162 -0
  238. nautobot/extras/migrations/0112_dynamic_group_group_type_data_migration.py +28 -0
  239. nautobot/extras/migrations/0113_saved_views.py +77 -0
  240. nautobot/extras/models/__init__.py +15 -1
  241. nautobot/extras/models/change_logging.py +3 -3
  242. nautobot/extras/models/contacts.py +4 -0
  243. nautobot/extras/models/customfields.py +18 -3
  244. nautobot/extras/models/groups.py +389 -225
  245. nautobot/extras/models/jobs.py +6 -3
  246. nautobot/extras/models/metadata.py +441 -0
  247. nautobot/extras/models/mixins.py +72 -62
  248. nautobot/extras/models/models.py +118 -9
  249. nautobot/extras/models/relationships.py +9 -2
  250. nautobot/extras/models/tags.py +13 -2
  251. nautobot/extras/navigation.py +57 -0
  252. nautobot/extras/plugins/__init__.py +3 -1
  253. nautobot/extras/querysets.py +30 -66
  254. nautobot/extras/signals.py +95 -100
  255. nautobot/extras/tables.py +165 -12
  256. nautobot/extras/templates/extras/dynamicgroup.html +44 -15
  257. nautobot/extras/templates/extras/dynamicgroup_edit.html +2 -0
  258. nautobot/extras/templates/extras/job.html +1 -1
  259. nautobot/extras/templates/extras/jobresult.html +61 -74
  260. nautobot/extras/templates/extras/metadatatype_create.html +89 -0
  261. nautobot/extras/templates/extras/metadatatype_retrieve.html +67 -0
  262. nautobot/extras/templates/extras/object_dynamicgroups.html +7 -0
  263. nautobot/extras/templates/extras/objectchange_list.html +0 -12
  264. nautobot/extras/templates/extras/plugins_list.html +1 -3
  265. nautobot/extras/templates/extras/role_retrieve.html +48 -0
  266. nautobot/extras/templates/extras/staticgroupassociation_retrieve.html +20 -0
  267. nautobot/extras/tests/integration/test_customfields.py +1 -0
  268. nautobot/extras/tests/test_api.py +509 -23
  269. nautobot/extras/tests/test_changelog.py +20 -9
  270. nautobot/extras/tests/test_context_managers.py +22 -15
  271. nautobot/extras/tests/test_datasources.py +13 -1
  272. nautobot/extras/tests/test_dynamicgroups.py +201 -171
  273. nautobot/extras/tests/test_filters.py +211 -12
  274. nautobot/extras/tests/test_jobs.py +6 -6
  275. nautobot/extras/tests/test_models.py +501 -4
  276. nautobot/extras/tests/test_relationships.py +1 -0
  277. nautobot/extras/tests/test_views.py +565 -8
  278. nautobot/extras/tests/test_webhooks.py +1 -1
  279. nautobot/extras/urls.py +5 -0
  280. nautobot/extras/utils.py +51 -11
  281. nautobot/extras/views.py +542 -76
  282. nautobot/ipam/__init__.py +0 -1
  283. nautobot/ipam/apps.py +1 -0
  284. nautobot/ipam/factory.py +17 -19
  285. nautobot/ipam/filters.py +13 -0
  286. nautobot/ipam/forms.py +8 -4
  287. nautobot/ipam/graphql/types.py +2 -2
  288. nautobot/ipam/migrations/0047_alter_ipaddress_role_alter_ipaddress_status_and_more.py +59 -0
  289. nautobot/ipam/models.py +11 -8
  290. nautobot/ipam/querysets.py +1 -1
  291. nautobot/ipam/signals.py +4 -2
  292. nautobot/ipam/tables.py +5 -0
  293. nautobot/ipam/templates/ipam/ipaddress_interfaces.html +1 -1
  294. nautobot/ipam/templates/ipam/ipaddress_vm_interfaces.html +1 -1
  295. nautobot/ipam/templates/ipam/prefix.html +1 -0
  296. nautobot/ipam/tests/test_api.py +37 -18
  297. nautobot/ipam/tests/test_filters.py +26 -2
  298. nautobot/ipam/tests/test_models.py +6 -0
  299. nautobot/ipam/tests/test_querysets.py +1 -1
  300. nautobot/ipam/tests/test_views.py +3 -2
  301. nautobot/ipam/urls.py +2 -2
  302. nautobot/ipam/views.py +18 -26
  303. nautobot/project-static/css/base.css +20 -0
  304. nautobot/project-static/css/dark.css +11 -0
  305. nautobot/project-static/docs/404.html +892 -88
  306. nautobot/project-static/docs/apps/index.html +892 -88
  307. nautobot/project-static/docs/apps/nautobot-apps.html +892 -88
  308. nautobot/project-static/docs/assets/_mkdocstrings.css +5 -0
  309. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css +1 -0
  310. nautobot/project-static/docs/assets/stylesheets/main.3cba04c6.min.css.map +1 -0
  311. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +919 -120
  312. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +904 -101
  313. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1618 -903
  314. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +935 -144
  315. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +977 -188
  316. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +901 -99
  317. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +897 -93
  318. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +991 -193
  319. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +974 -131
  320. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1078 -272
  321. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1242 -334
  322. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1727 -875
  323. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1164 -381
  324. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2088 -1374
  325. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2246 -1422
  326. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +912 -111
  327. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +963 -163
  328. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1010 -223
  329. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1913 -1277
  330. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1846 -1102
  331. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +904 -101
  332. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +2331 -1699
  333. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1802 -1024
  334. nautobot/project-static/docs/development/apps/api/configuration-view.html +892 -88
  335. nautobot/project-static/docs/development/apps/api/database-backend-config.html +892 -88
  336. nautobot/project-static/docs/development/apps/api/models/django-admin.html +892 -88
  337. nautobot/project-static/docs/development/apps/api/models/global-search.html +892 -88
  338. nautobot/project-static/docs/development/apps/api/models/graphql.html +892 -88
  339. nautobot/project-static/docs/development/apps/api/models/index.html +942 -90
  340. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +892 -88
  341. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +892 -88
  342. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +892 -88
  343. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +892 -88
  344. nautobot/project-static/docs/development/apps/api/platform-features/index.html +892 -88
  345. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +892 -88
  346. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +892 -88
  347. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +892 -88
  348. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +892 -88
  349. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +892 -88
  350. nautobot/project-static/docs/development/apps/api/prometheus.html +892 -88
  351. nautobot/project-static/docs/development/apps/api/setup.html +892 -88
  352. nautobot/project-static/docs/development/apps/api/testing.html +892 -88
  353. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +892 -88
  354. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +892 -88
  355. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +892 -88
  356. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +892 -88
  357. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +892 -88
  358. nautobot/project-static/docs/development/apps/api/views/base-template.html +892 -88
  359. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +892 -88
  360. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +892 -88
  361. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +892 -88
  362. nautobot/project-static/docs/development/apps/api/views/index.html +892 -88
  363. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +892 -88
  364. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +892 -88
  365. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +892 -88
  366. nautobot/project-static/docs/development/apps/api/views/notes.html +892 -88
  367. nautobot/project-static/docs/development/apps/api/views/rest-api.html +892 -88
  368. nautobot/project-static/docs/development/apps/api/views/urls.html +892 -88
  369. nautobot/project-static/docs/development/apps/index.html +892 -88
  370. nautobot/project-static/docs/development/apps/migration/code-updates.html +892 -88
  371. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +892 -88
  372. nautobot/project-static/docs/development/apps/migration/from-v1.html +892 -88
  373. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +892 -88
  374. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +892 -88
  375. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +892 -88
  376. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +892 -88
  377. nautobot/project-static/docs/development/apps/porting-from-netbox.html +892 -88
  378. nautobot/project-static/docs/development/core/application-registry.html +892 -88
  379. nautobot/project-static/docs/development/core/best-practices.html +893 -88
  380. nautobot/project-static/docs/development/core/bootstrap-ui.html +892 -88
  381. nautobot/project-static/docs/development/core/caching.html +892 -88
  382. nautobot/project-static/docs/development/core/controllers.html +892 -88
  383. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +892 -88
  384. nautobot/project-static/docs/development/core/generic-views.html +892 -88
  385. nautobot/project-static/docs/development/core/getting-started.html +892 -88
  386. nautobot/project-static/docs/development/core/homepage.html +892 -88
  387. nautobot/project-static/docs/development/core/index.html +892 -88
  388. nautobot/project-static/docs/development/core/model-checklist.html +901 -89
  389. nautobot/project-static/docs/development/core/model-features.html +892 -88
  390. nautobot/project-static/docs/development/core/natural-keys.html +892 -88
  391. nautobot/project-static/docs/development/core/navigation-menu.html +892 -88
  392. nautobot/project-static/docs/development/core/release-checklist.html +895 -91
  393. nautobot/project-static/docs/development/core/role-internals.html +892 -88
  394. nautobot/project-static/docs/development/core/settings.html +892 -88
  395. nautobot/project-static/docs/development/core/style-guide.html +893 -89
  396. nautobot/project-static/docs/development/core/templates.html +904 -89
  397. nautobot/project-static/docs/development/core/testing.html +892 -88
  398. nautobot/project-static/docs/development/core/user-preferences.html +892 -88
  399. nautobot/project-static/docs/development/index.html +892 -88
  400. nautobot/project-static/docs/development/jobs/index.html +893 -89
  401. nautobot/project-static/docs/development/jobs/migration/from-v1.html +892 -88
  402. nautobot/project-static/docs/index.html +892 -88
  403. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_dark.png +0 -0
  404. nautobot/project-static/docs/media/models/cloud_aws_direct_connect_light.png +0 -0
  405. nautobot/project-static/docs/models/cloud/cloudaccount.html +15 -0
  406. nautobot/project-static/docs/models/cloud/cloudnetwork.html +15 -0
  407. nautobot/project-static/docs/models/cloud/cloudnetworkprefixassignment.html +15 -0
  408. nautobot/project-static/docs/models/cloud/cloudresourcetype.html +15 -0
  409. nautobot/project-static/docs/models/cloud/cloudservice.html +15 -0
  410. nautobot/project-static/docs/models/cloud/cloudservicenetworkassignment.html +15 -0
  411. nautobot/project-static/docs/models/dcim/module.html +15 -0
  412. nautobot/project-static/docs/models/dcim/modulebay.html +15 -0
  413. nautobot/project-static/docs/models/dcim/modulebaytemplate.html +15 -0
  414. nautobot/project-static/docs/models/dcim/moduletype.html +15 -0
  415. nautobot/project-static/docs/models/extras/metadatachoice.html +15 -0
  416. nautobot/project-static/docs/models/extras/metadatatype.html +15 -0
  417. nautobot/project-static/docs/models/extras/objectmetadata.html +15 -0
  418. nautobot/project-static/docs/models/extras/role.html +15 -0
  419. nautobot/project-static/docs/models/extras/savedview.html +15 -0
  420. nautobot/project-static/docs/models/extras/staticgroupassociation.html +15 -0
  421. nautobot/project-static/docs/models/extras/status.html +15 -0
  422. nautobot/project-static/docs/objects.inv +0 -0
  423. nautobot/project-static/docs/overview/application_stack.html +900 -89
  424. nautobot/project-static/docs/overview/design_philosophy.html +892 -88
  425. nautobot/project-static/docs/release-notes/index.html +1129 -92
  426. nautobot/project-static/docs/release-notes/version-1.0.html +892 -88
  427. nautobot/project-static/docs/release-notes/version-1.1.html +892 -88
  428. nautobot/project-static/docs/release-notes/version-1.2.html +892 -88
  429. nautobot/project-static/docs/release-notes/version-1.3.html +892 -88
  430. nautobot/project-static/docs/release-notes/version-1.4.html +892 -88
  431. nautobot/project-static/docs/release-notes/version-1.5.html +893 -89
  432. nautobot/project-static/docs/release-notes/version-1.6.html +893 -89
  433. nautobot/project-static/docs/release-notes/version-2.0.html +892 -88
  434. nautobot/project-static/docs/release-notes/version-2.1.html +892 -88
  435. nautobot/project-static/docs/release-notes/version-2.2.html +895 -91
  436. nautobot/project-static/docs/release-notes/version-2.3.html +9954 -0
  437. nautobot/project-static/docs/requirements.txt +5 -5
  438. nautobot/project-static/docs/search/search_index.json +1 -1
  439. nautobot/project-static/docs/sitemap.xml +331 -256
  440. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  441. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +892 -88
  442. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +892 -88
  443. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +892 -88
  444. nautobot/project-static/docs/user-guide/administration/configuration/index.html +892 -88
  445. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +992 -174
  446. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +892 -88
  447. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +892 -88
  448. nautobot/project-static/docs/user-guide/administration/guides/caching.html +892 -88
  449. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +896 -88
  450. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +892 -88
  451. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +892 -88
  452. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +892 -88
  453. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +892 -88
  454. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +892 -88
  455. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +892 -88
  456. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +892 -88
  457. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +892 -88
  458. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +944 -153
  459. nautobot/project-static/docs/user-guide/administration/installation/index.html +901 -93
  460. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +934 -122
  461. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +954 -157
  462. nautobot/project-static/docs/user-guide/administration/installation/services.html +913 -112
  463. nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +908 -99
  464. nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +892 -88
  465. nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +892 -88
  466. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +892 -88
  467. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +892 -88
  468. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +893 -89
  469. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +892 -88
  470. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +892 -88
  471. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +892 -88
  472. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +892 -88
  473. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +892 -88
  474. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +892 -88
  475. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +892 -88
  476. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +892 -88
  477. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +892 -88
  478. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +892 -88
  479. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +892 -88
  480. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +893 -89
  481. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +892 -88
  482. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +896 -88
  483. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +895 -91
  484. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +8984 -0
  485. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +8828 -0
  486. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +8829 -0
  487. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +8828 -0
  488. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +8829 -0
  489. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +8833 -0
  490. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +8828 -0
  491. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +906 -102
  492. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +923 -105
  493. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +923 -105
  494. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +918 -100
  495. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +923 -105
  496. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +906 -102
  497. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +906 -102
  498. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +913 -105
  499. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +920 -116
  500. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +921 -117
  501. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +918 -114
  502. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +906 -102
  503. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +914 -105
  504. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +926 -108
  505. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +936 -118
  506. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +928 -106
  507. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +906 -102
  508. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +937 -119
  509. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +928 -110
  510. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +918 -114
  511. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +921 -117
  512. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +923 -115
  513. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +8828 -0
  514. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +8846 -0
  515. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +8843 -0
  516. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +8823 -0
  517. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +916 -112
  518. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +906 -102
  519. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +940 -83
  520. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +924 -106
  521. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +906 -102
  522. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +943 -86
  523. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +921 -103
  524. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +929 -125
  525. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +918 -114
  526. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +906 -102
  527. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +922 -104
  528. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +924 -106
  529. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +906 -102
  530. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +906 -102
  531. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +906 -102
  532. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +936 -88
  533. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +892 -88
  534. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +897 -89
  535. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +897 -89
  536. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +892 -88
  537. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +892 -88
  538. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +892 -88
  539. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +892 -88
  540. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +892 -88
  541. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +892 -88
  542. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +892 -88
  543. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +892 -88
  544. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +892 -88
  545. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +892 -88
  546. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +901 -96
  547. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +892 -88
  548. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +892 -88
  549. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +892 -88
  550. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +892 -88
  551. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +892 -88
  552. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +897 -89
  553. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +892 -88
  554. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +892 -88
  555. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +892 -88
  556. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +892 -88
  557. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +892 -88
  558. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +892 -88
  559. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +892 -88
  560. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +892 -88
  561. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +892 -88
  562. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +892 -88
  563. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +892 -88
  564. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +892 -88
  565. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +892 -88
  566. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/clear-view-button.png +0 -0
  567. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/cleared-view.png +0 -0
  568. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/config-table-columns-to-locations.png +0 -0
  569. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/configure-button.png +0 -0
  570. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/create-saved-view-success.png +0 -0
  571. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/current-saved-view-drop-down-menu.png +0 -0
  572. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/default-location-list-view.png +0 -0
  573. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/dropdown-button-after-new-saved-view.png +0 -0
  574. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-application-to-locations.png +0 -0
  575. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/filter-button.png +0 -0
  576. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/global-default-location-list-view.png +0 -0
  577. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/location-list-view-with-saved-views.png +0 -0
  578. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/navigation-menu.png +0 -0
  579. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-as-new-view-drop-down.png +0 -0
  580. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/save-view-modal.png +0 -0
  581. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-buttons.png +0 -0
  582. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-success.png +0 -0
  583. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view-unchecked.png +0 -0
  584. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-admin-edit-view.png +0 -0
  585. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-different-user.png +0 -0
  586. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/saved-view-modal-unchecked.png +0 -0
  587. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-button.png +0 -0
  588. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/set-as-my-default-success.png +0 -0
  589. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/unsaved-saved-view.png +0 -0
  590. nautobot/project-static/docs/user-guide/feature-guides/images/saved-views/updated-saved-view.png +0 -0
  591. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +892 -88
  592. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +892 -88
  593. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +892 -88
  594. nautobot/project-static/docs/user-guide/index.html +892 -88
  595. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +892 -88
  596. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +892 -88
  597. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +892 -88
  598. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +892 -88
  599. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1258 -785
  600. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +895 -91
  601. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +892 -88
  602. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +892 -88
  603. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +892 -88
  604. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +892 -88
  605. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +892 -88
  606. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +892 -88
  607. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +892 -88
  608. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +892 -88
  609. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +892 -88
  610. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +896 -88
  611. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +892 -88
  612. nautobot/project-static/docs/user-guide/platform-functionality/note.html +895 -91
  613. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +9061 -0
  614. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +895 -91
  615. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +892 -88
  616. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +892 -88
  617. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +892 -88
  618. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +892 -88
  619. nautobot/project-static/docs/user-guide/platform-functionality/role.html +895 -91
  620. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +9137 -0
  621. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +895 -91
  622. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +8933 -0
  623. nautobot/project-static/docs/user-guide/platform-functionality/status.html +892 -88
  624. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +892 -88
  625. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +950 -121
  626. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +892 -88
  627. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +892 -88
  628. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +892 -88
  629. nautobot/project-static/js/forms.js +71 -0
  630. nautobot/project-static/js/table_sorting_indicator.js +46 -0
  631. nautobot/project-static/js/tableconfig.js +6 -1
  632. nautobot/project-static/materialdesignicons-7.4.47/css/materialdesignicons.min.css +3 -0
  633. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.eot +0 -0
  634. nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/fonts/materialdesignicons-webfont.ttf +0 -0
  635. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff +0 -0
  636. nautobot/project-static/materialdesignicons-7.4.47/fonts/materialdesignicons-webfont.woff2 +0 -0
  637. nautobot/tenancy/__init__.py +0 -1
  638. nautobot/tenancy/apps.py +1 -0
  639. nautobot/tenancy/factory.py +3 -2
  640. nautobot/tenancy/filters/__init__.py +1 -0
  641. nautobot/tenancy/forms.py +1 -1
  642. nautobot/tenancy/templates/tenancy/tenant.html +24 -20
  643. nautobot/tenancy/views.py +11 -10
  644. nautobot/users/__init__.py +0 -1
  645. nautobot/users/api/serializers.py +1 -1
  646. nautobot/users/api/views.py +4 -2
  647. nautobot/users/apps.py +3 -2
  648. nautobot/users/factory.py +3 -3
  649. nautobot/users/migrations/0010_user_default_saved_views.py +20 -0
  650. nautobot/users/models.py +12 -0
  651. nautobot/users/tests/test_filters.py +6 -3
  652. nautobot/users/urls.py +8 -0
  653. nautobot/virtualization/__init__.py +0 -1
  654. nautobot/virtualization/apps.py +1 -0
  655. nautobot/virtualization/filters.py +6 -1
  656. nautobot/virtualization/forms.py +11 -3
  657. nautobot/virtualization/graphql/types.py +2 -2
  658. nautobot/virtualization/migrations/0029_add_role_field_to_interface_models.py +27 -0
  659. nautobot/virtualization/migrations/0030_alter_virtualmachine_local_config_context_data_owner_content_type_and_more.py +67 -0
  660. nautobot/virtualization/models.py +0 -2
  661. nautobot/virtualization/tables.py +10 -3
  662. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
  663. nautobot/virtualization/templates/virtualization/vminterface.html +7 -1
  664. nautobot/virtualization/templates/virtualization/vminterface_edit.html +1 -0
  665. nautobot/virtualization/tests/test_api.py +9 -4
  666. nautobot/virtualization/tests/test_filters.py +22 -0
  667. nautobot/virtualization/tests/test_models.py +7 -3
  668. nautobot/virtualization/tests/test_views.py +19 -3
  669. nautobot/virtualization/urls.py +2 -2
  670. nautobot/virtualization/views.py +10 -32
  671. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/METADATA +20 -18
  672. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/RECORD +677 -557
  673. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css +0 -1
  674. nautobot/project-static/docs/assets/stylesheets/main.76a95c52.min.css.map +0 -1
  675. nautobot/project-static/materialdesignicons-6.5.95/.github/ISSUE_TEMPLATE.md +0 -3
  676. nautobot/project-static/materialdesignicons-6.5.95/README.md +0 -25
  677. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css +0 -26654
  678. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.css.map +0 -16
  679. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css +0 -3
  680. nautobot/project-static/materialdesignicons-6.5.95/css/materialdesignicons.min.css.map +0 -16
  681. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff +0 -0
  682. nautobot/project-static/materialdesignicons-6.5.95/fonts/materialdesignicons-webfont.woff2 +0 -0
  683. nautobot/project-static/materialdesignicons-6.5.95/package.json +0 -28
  684. nautobot/project-static/materialdesignicons-6.5.95/preview.html +0 -717
  685. nautobot/project-static/materialdesignicons-6.5.95/scss/_animated.scss +0 -27
  686. nautobot/project-static/materialdesignicons-6.5.95/scss/_core.scss +0 -10
  687. nautobot/project-static/materialdesignicons-6.5.95/scss/_extras.scss +0 -65
  688. nautobot/project-static/materialdesignicons-6.5.95/scss/_functions.scss +0 -20
  689. nautobot/project-static/materialdesignicons-6.5.95/scss/_icons.scss +0 -10
  690. nautobot/project-static/materialdesignicons-6.5.95/scss/_path.scss +0 -10
  691. nautobot/project-static/materialdesignicons-6.5.95/scss/_variables.scss +0 -6606
  692. nautobot/project-static/materialdesignicons-6.5.95/scss/materialdesignicons.scss +0 -8
  693. /nautobot/project-static/{materialdesignicons-6.5.95 → materialdesignicons-7.4.47}/LICENSE +0 -0
  694. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/LICENSE.txt +0 -0
  695. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/NOTICE +0 -0
  696. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/WHEEL +0 -0
  697. {nautobot-2.2.9.dist-info → nautobot-2.3.0.dist-info}/entry_points.txt +0 -0
@@ -27,12 +27,21 @@ from nautobot.dcim.choices import (
27
27
  RackTypeChoices,
28
28
  RackWidthChoices,
29
29
  )
30
- from nautobot.dcim.constants import NONCONNECTABLE_IFACE_TYPES, VIRTUAL_IFACE_TYPES, WIRELESS_IFACE_TYPES
30
+ from nautobot.dcim.constants import (
31
+ MODULE_RECURSION_DEPTH_LIMIT,
32
+ NONCONNECTABLE_IFACE_TYPES,
33
+ VIRTUAL_IFACE_TYPES,
34
+ WIRELESS_IFACE_TYPES,
35
+ )
31
36
  from nautobot.dcim.filters.mixins import (
32
37
  CableTerminationModelFilterSetMixin,
33
38
  DeviceComponentModelFilterSetMixin,
34
39
  DeviceComponentTemplateModelFilterSetMixin,
40
+ DeviceModuleCommonFiltersMixin,
41
+ DeviceTypeModuleTypeCommonFiltersMixin,
35
42
  LocatableModelFilterSetMixin,
43
+ ModularDeviceComponentModelFilterSetMixin,
44
+ ModularDeviceComponentTemplateModelFilterSetMixin,
36
45
  PathEndpointModelFilterSetMixin,
37
46
  )
38
47
  from nautobot.dcim.models import (
@@ -60,6 +69,10 @@ from nautobot.dcim.models import (
60
69
  Location,
61
70
  LocationType,
62
71
  Manufacturer,
72
+ Module,
73
+ ModuleBay,
74
+ ModuleBayTemplate,
75
+ ModuleType,
63
76
  Platform,
64
77
  PowerFeed,
65
78
  PowerOutlet,
@@ -118,6 +131,10 @@ __all__ = (
118
131
  "LocationFilterSet",
119
132
  "LocationTypeFilterSet",
120
133
  "ManufacturerFilterSet",
134
+ "ModuleBayFilterSet",
135
+ "ModuleBayTemplateFilterSet",
136
+ "ModuleFilterSet",
137
+ "ModuleTypeFilterSet",
121
138
  "PathEndpointFilterSet",
122
139
  "PathEndpointModelFilterSetMixin",
123
140
  "PlatformFilterSet",
@@ -178,6 +195,7 @@ class LocationFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyMod
178
195
  label="Location type (name or ID)",
179
196
  )
180
197
  parent = NaturalKeyOrPKMultipleChoiceFilter(
198
+ prefers_id=True,
181
199
  queryset=Location.objects.all(),
182
200
  to_field_name="name",
183
201
  label="Parent location (name or ID)",
@@ -204,6 +222,7 @@ class LocationFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyMod
204
222
  label="Has circuit terminations",
205
223
  )
206
224
  devices = NaturalKeyOrPKMultipleChoiceFilter(
225
+ prefers_id=True,
207
226
  queryset=Device.objects.all(),
208
227
  to_field_name="name",
209
228
  label="Devices (name or ID)",
@@ -222,6 +241,7 @@ class LocationFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyMod
222
241
  label="Has power panels",
223
242
  )
224
243
  rack_groups = NaturalKeyOrPKMultipleChoiceFilter(
244
+ prefers_id=True,
225
245
  queryset=RackGroup.objects.all(),
226
246
  to_field_name="name",
227
247
  label="Rack groups (name or ID)",
@@ -256,8 +276,8 @@ class LocationFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyMod
256
276
  field_name="vlans",
257
277
  label="Has VLANs",
258
278
  )
259
- # FIXME (timizuo): LocationFilterSet vlans field currently only filters with vid and not pk(throws an error when pk is provided)
260
279
  vlans = NaturalKeyOrPKMultipleChoiceFilter(
280
+ prefers_id=True,
261
281
  to_field_name="vid",
262
282
  queryset=VLAN.objects.all(),
263
283
  label="Tagged VLANs (VID or ID)",
@@ -326,11 +346,13 @@ class LocationFilterSet(NautobotFilterSet, StatusModelFilterSetMixin, TenancyMod
326
346
  @extend_schema_field({"type": "string"})
327
347
  def _subtree(self, queryset, name, value):
328
348
  """FilterSet method for getting Locations that are or are descended from a given Location(s)."""
329
- params = self.generate_query__subtree(value)
330
- return queryset.filter(params)
349
+ if value:
350
+ params = self.generate_query__subtree(value)
351
+ return queryset.with_tree_fields().filter(params)
352
+ return queryset
331
353
 
332
354
 
333
- class RackGroupFilterSet(NautobotFilterSet, LocatableModelFilterSetMixin, NameSearchFilterSet):
355
+ class RackGroupFilterSet(LocatableModelFilterSetMixin, NautobotFilterSet, NameSearchFilterSet):
334
356
  parent = NaturalKeyOrPKMultipleChoiceFilter(
335
357
  queryset=RackGroup.objects.all(),
336
358
  to_field_name="name",
@@ -347,6 +369,7 @@ class RackGroupFilterSet(NautobotFilterSet, LocatableModelFilterSetMixin, NameSe
347
369
  )
348
370
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
349
371
  power_panels = NaturalKeyOrPKMultipleChoiceFilter(
372
+ prefers_id=True,
350
373
  field_name="power_panels",
351
374
  to_field_name="name",
352
375
  queryset=PowerPanel.objects.all(),
@@ -389,6 +412,7 @@ class RackFilterSet(
389
412
  },
390
413
  )
391
414
  rack_group = TreeNodeMultipleChoiceFilter(
415
+ prefers_id=True,
392
416
  queryset=RackGroup.objects.all(),
393
417
  field_name="rack_group",
394
418
  to_field_name="name",
@@ -403,6 +427,7 @@ class RackFilterSet(
403
427
  )
404
428
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
405
429
  power_feeds = NaturalKeyOrPKMultipleChoiceFilter(
430
+ prefers_id=True,
406
431
  field_name="power_feeds",
407
432
  to_field_name="name",
408
433
  queryset=PowerFeed.objects.all(),
@@ -436,7 +461,7 @@ class RackFilterSet(
436
461
  ]
437
462
 
438
463
 
439
- class RackReservationFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
464
+ class RackReservationFilterSet(TenancyModelFilterSetMixin, NautobotFilterSet):
440
465
  q = SearchFilter(
441
466
  filter_predicates={
442
467
  "rack__name": "icontains",
@@ -446,6 +471,7 @@ class RackReservationFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
446
471
  },
447
472
  )
448
473
  rack_group = TreeNodeMultipleChoiceFilter(
474
+ prefers_id=True,
449
475
  queryset=RackGroup.objects.all(),
450
476
  field_name="rack__rack_group",
451
477
  to_field_name="name",
@@ -458,6 +484,7 @@ class RackReservationFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
458
484
  )
459
485
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
460
486
  rack = NaturalKeyOrPKMultipleChoiceFilter(
487
+ prefers_id=True,
461
488
  queryset=Rack.objects.all(),
462
489
  to_field_name="name",
463
490
  label="Rack (name or ID)",
@@ -471,6 +498,7 @@ class RackReservationFilterSet(NautobotFilterSet, TenancyModelFilterSetMixin):
471
498
  class ManufacturerFilterSet(NautobotFilterSet, NameSearchFilterSet):
472
499
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
473
500
  inventory_items = NaturalKeyOrPKMultipleChoiceFilter(
501
+ prefers_id=True,
474
502
  queryset=InventoryItem.objects.all(),
475
503
  to_field_name="name",
476
504
  label="Inventory items (name or ID)",
@@ -519,7 +547,7 @@ class DeviceFamilyFilterSet(NautobotFilterSet, NameSearchFilterSet):
519
547
  fields = ["id", "name", "description", "tags"]
520
548
 
521
549
 
522
- class DeviceTypeFilterSet(NautobotFilterSet):
550
+ class DeviceTypeFilterSet(DeviceTypeModuleTypeCommonFiltersMixin, NautobotFilterSet):
523
551
  q = SearchFilter(
524
552
  filter_predicates={
525
553
  "manufacturer__name": "icontains",
@@ -529,9 +557,6 @@ class DeviceTypeFilterSet(NautobotFilterSet):
529
557
  "comments": "icontains",
530
558
  },
531
559
  )
532
- manufacturer = NaturalKeyOrPKMultipleChoiceFilter(
533
- queryset=Manufacturer.objects.all(), to_field_name="name", label="Manufacturer (name or ID)"
534
- )
535
560
  device_family = NaturalKeyOrPKMultipleChoiceFilter(
536
561
  queryset=DeviceFamily.objects.all(), to_field_name="name", label="Device family (name or ID)"
537
562
  )
@@ -555,8 +580,8 @@ class DeviceTypeFilterSet(NautobotFilterSet):
555
580
  method="_interfaces",
556
581
  label="Has interfaces",
557
582
  )
558
- pass_through_ports = django_filters.BooleanFilter(
559
- method="_pass_through_ports",
583
+ pass_through_ports = RelatedMembershipBooleanFilter(
584
+ field_name="front_port_templates",
560
585
  label="Has pass-through ports",
561
586
  )
562
587
  device_bays = django_filters.BooleanFilter(
@@ -568,77 +593,8 @@ class DeviceTypeFilterSet(NautobotFilterSet):
568
593
  label="Has device instances",
569
594
  )
570
595
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
571
- console_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
572
- to_field_name="name",
573
- queryset=ConsolePortTemplate.objects.all(),
574
- label="Console port templates (name or ID)",
575
- )
576
- has_console_port_templates = RelatedMembershipBooleanFilter(
577
- field_name="console_port_templates",
578
- label="Has console port templates",
579
- )
580
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
581
- console_server_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
582
- to_field_name="name",
583
- queryset=ConsoleServerPortTemplate.objects.all(),
584
- label="Console server port templates (name or ID)",
585
- )
586
- has_console_server_port_templates = RelatedMembershipBooleanFilter(
587
- field_name="console_server_port_templates",
588
- label="Has console server port templates",
589
- )
590
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
591
- power_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
592
- to_field_name="name",
593
- queryset=PowerPortTemplate.objects.all(),
594
- label="Power port templates (name or ID)",
595
- )
596
- has_power_port_templates = RelatedMembershipBooleanFilter(
597
- field_name="power_port_templates",
598
- label="Has power port templates",
599
- )
600
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
601
- power_outlet_templates = NaturalKeyOrPKMultipleChoiceFilter(
602
- to_field_name="name",
603
- queryset=PowerOutletTemplate.objects.all(),
604
- label="Power outlet templates (name or ID)",
605
- )
606
- has_power_outlet_templates = RelatedMembershipBooleanFilter(
607
- field_name="power_outlet_templates",
608
- label="Has power outlet templates",
609
- )
610
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
611
- interface_templates = NaturalKeyOrPKMultipleChoiceFilter(
612
- to_field_name="name",
613
- queryset=InterfaceTemplate.objects.all(),
614
- label="Interface templates (name or ID)",
615
- )
616
- has_interface_templates = RelatedMembershipBooleanFilter(
617
- field_name="interface_templates",
618
- label="Has interface templates",
619
- )
620
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
621
- front_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
622
- to_field_name="name",
623
- queryset=FrontPortTemplate.objects.all(),
624
- label="Front port templates (name or ID)",
625
- )
626
- has_front_port_templates = RelatedMembershipBooleanFilter(
627
- field_name="front_port_templates",
628
- label="Has front port templates",
629
- )
630
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
631
- rear_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
632
- to_field_name="name",
633
- queryset=RearPortTemplate.objects.all(),
634
- label="Rear port templates (name or ID)",
635
- )
636
- has_rear_port_templates = RelatedMembershipBooleanFilter(
637
- field_name="rear_port_templates",
638
- label="Has rear port templates",
639
- )
640
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
641
596
  device_bay_templates = NaturalKeyOrPKMultipleChoiceFilter(
597
+ prefers_id=True,
642
598
  to_field_name="name",
643
599
  queryset=DeviceBayTemplate.objects.all(),
644
600
  label="Device bay templates (name or ID)",
@@ -688,9 +644,6 @@ class DeviceTypeFilterSet(NautobotFilterSet):
688
644
  def _interfaces(self, queryset, name, value):
689
645
  return queryset.exclude(interface_templates__isnull=value)
690
646
 
691
- def _pass_through_ports(self, queryset, name, value):
692
- return queryset.exclude(front_port_templates__isnull=value, rear_port_templates__isnull=value)
693
-
694
647
  def _device_bays(self, queryset, name, value):
695
648
  return queryset.exclude(device_bay_templates__isnull=value)
696
649
 
@@ -701,21 +654,22 @@ class DeviceTypeComponentFilterSet(DeviceComponentTemplateModelFilterSetMixin):
701
654
  pass
702
655
 
703
656
 
704
- class ConsolePortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
657
+ class ConsolePortTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
705
658
  class Meta:
706
659
  model = ConsolePortTemplate
707
660
  fields = ["type"]
708
661
 
709
662
 
710
- class ConsoleServerPortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
663
+ class ConsoleServerPortTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
711
664
  class Meta:
712
665
  model = ConsoleServerPortTemplate
713
666
  fields = ["type"]
714
667
 
715
668
 
716
- class PowerPortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
669
+ class PowerPortTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
717
670
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
718
671
  power_outlet_templates = NaturalKeyOrPKMultipleChoiceFilter(
672
+ prefers_id=True,
719
673
  to_field_name="name",
720
674
  queryset=PowerOutletTemplate.objects.all(),
721
675
  label="Power outlet templates (name or ID)",
@@ -734,9 +688,10 @@ class PowerPortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilt
734
688
  ]
735
689
 
736
690
 
737
- class PowerOutletTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
691
+ class PowerOutletTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
738
692
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
739
693
  power_port_template = NaturalKeyOrPKMultipleChoiceFilter(
694
+ prefers_id=True,
740
695
  to_field_name="name",
741
696
  queryset=PowerPortTemplate.objects.all(),
742
697
  label="Power port template (name or ID)",
@@ -747,13 +702,13 @@ class PowerOutletTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFi
747
702
  fields = ["type", "feed_leg"]
748
703
 
749
704
 
750
- class InterfaceTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
705
+ class InterfaceTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
751
706
  class Meta:
752
707
  model = InterfaceTemplate
753
708
  fields = ["type", "mgmt_only"]
754
709
 
755
710
 
756
- class FrontPortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
711
+ class FrontPortTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
757
712
  rear_port_template = django_filters.ModelMultipleChoiceFilter(
758
713
  queryset=RearPortTemplate.objects.all(),
759
714
  label="Rear port template",
@@ -764,7 +719,7 @@ class FrontPortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilt
764
719
  fields = ["type", "rear_port_position"]
765
720
 
766
721
 
767
- class RearPortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
722
+ class RearPortTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
768
723
  front_port_templates = django_filters.ModelMultipleChoiceFilter(
769
724
  queryset=FrontPortTemplate.objects.all(),
770
725
  label="Front port templates",
@@ -779,7 +734,7 @@ class RearPortTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilte
779
734
  fields = ["type", "positions"]
780
735
 
781
736
 
782
- class DeviceBayTemplateFilterSet(BaseFilterSet, DeviceComponentTemplateModelFilterSetMixin):
737
+ class DeviceBayTemplateFilterSet(DeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
783
738
  class Meta:
784
739
  model = DeviceBayTemplate
785
740
  fields = []
@@ -814,6 +769,7 @@ class PlatformFilterSet(NautobotFilterSet, NameSearchFilterSet):
814
769
 
815
770
  class DeviceFilterSet(
816
771
  NautobotFilterSet,
772
+ DeviceModuleCommonFiltersMixin,
817
773
  LocatableModelFilterSetMixin,
818
774
  TenancyModelFilterSetMixin,
819
775
  LocalContextModelFilterSetMixin,
@@ -867,6 +823,7 @@ class DeviceFilterSet(
867
823
  queryset=Platform.objects.all(), to_field_name="name", label="Platform (name or ID)"
868
824
  )
869
825
  rack_group = TreeNodeMultipleChoiceFilter(
826
+ prefers_id=True,
870
827
  queryset=RackGroup.objects.all(),
871
828
  field_name="rack__rack_group",
872
829
  to_field_name="name",
@@ -874,11 +831,11 @@ class DeviceFilterSet(
874
831
  )
875
832
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
876
833
  rack = NaturalKeyOrPKMultipleChoiceFilter(
834
+ prefers_id=True,
877
835
  queryset=Rack.objects.all(),
878
836
  to_field_name="name",
879
837
  label="Rack (name or ID)",
880
838
  )
881
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
882
839
  cluster = NaturalKeyOrPKMultipleChoiceFilter(
883
840
  queryset=Cluster.objects.all(),
884
841
  to_field_name="name",
@@ -888,10 +845,6 @@ class DeviceFilterSet(
888
845
  field_name="device_type__is_full_depth",
889
846
  label="Is full depth",
890
847
  )
891
- mac_address = MultiValueMACAddressFilter(
892
- field_name="interfaces__mac_address",
893
- label="MAC address",
894
- )
895
848
  serial = MultiValueCharFilter(lookup_expr="iexact")
896
849
  has_primary_ip = django_filters.BooleanFilter(
897
850
  method="_has_primary_ip",
@@ -902,7 +855,6 @@ class DeviceFilterSet(
902
855
  to_field_name="name",
903
856
  label="Secrets group (name or ID)",
904
857
  )
905
- # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
906
858
  virtual_chassis = NaturalKeyOrPKMultipleChoiceFilter(
907
859
  queryset=VirtualChassis.objects.all(),
908
860
  to_field_name="name",
@@ -925,58 +877,6 @@ class DeviceFilterSet(
925
877
  label="Controller Managed Device Groups (name or ID)",
926
878
  )
927
879
  virtual_chassis_member = is_virtual_chassis_member
928
- has_console_ports = RelatedMembershipBooleanFilter(
929
- field_name="console_ports",
930
- label="Has console ports",
931
- )
932
- console_ports = django_filters.ModelMultipleChoiceFilter(
933
- queryset=ConsolePort.objects.all(),
934
- label="Console Ports",
935
- )
936
- has_console_server_ports = RelatedMembershipBooleanFilter(
937
- field_name="console_server_ports",
938
- label="Has console server ports",
939
- )
940
- console_server_ports = django_filters.ModelMultipleChoiceFilter(
941
- queryset=ConsoleServerPort.objects.all(),
942
- label="Console Server Ports",
943
- )
944
- has_power_ports = RelatedMembershipBooleanFilter(
945
- field_name="power_ports",
946
- label="Has power ports",
947
- )
948
- power_ports = django_filters.ModelMultipleChoiceFilter(
949
- queryset=PowerPort.objects.all(),
950
- label="Power Ports",
951
- )
952
- has_power_outlets = RelatedMembershipBooleanFilter(
953
- field_name="power_outlets",
954
- label="Has power outlets",
955
- )
956
- power_outlets = django_filters.ModelMultipleChoiceFilter(
957
- queryset=PowerOutlet.objects.all(),
958
- label="Power Outlets",
959
- )
960
- has_interfaces = RelatedMembershipBooleanFilter(
961
- field_name="interfaces",
962
- label="Has interfaces",
963
- )
964
- has_front_ports = RelatedMembershipBooleanFilter(
965
- field_name="front_ports",
966
- label="Has front ports",
967
- )
968
- front_ports = django_filters.ModelMultipleChoiceFilter(
969
- queryset=FrontPort.objects.all(),
970
- label="Front Port",
971
- )
972
- has_rear_ports = RelatedMembershipBooleanFilter(
973
- field_name="rear_ports",
974
- label="Has rear ports",
975
- )
976
- rear_ports = django_filters.ModelMultipleChoiceFilter(
977
- queryset=RearPort.objects.all(),
978
- label="Rear Port",
979
- )
980
880
  has_device_bays = RelatedMembershipBooleanFilter(
981
881
  field_name="device_bays",
982
882
  label="Has device bays",
@@ -1053,10 +953,10 @@ class PathEndpointFilterSet(PathEndpointModelFilterSetMixin):
1053
953
 
1054
954
 
1055
955
  class ConsolePortFilterSet(
1056
- BaseFilterSet,
1057
- DeviceComponentModelFilterSetMixin,
956
+ ModularDeviceComponentModelFilterSetMixin,
1058
957
  CableTerminationModelFilterSetMixin,
1059
958
  PathEndpointModelFilterSetMixin,
959
+ BaseFilterSet,
1060
960
  ):
1061
961
  type = django_filters.MultipleChoiceFilter(choices=ConsolePortTypeChoices, null_value=None)
1062
962
 
@@ -1066,10 +966,10 @@ class ConsolePortFilterSet(
1066
966
 
1067
967
 
1068
968
  class ConsoleServerPortFilterSet(
1069
- BaseFilterSet,
1070
- DeviceComponentModelFilterSetMixin,
969
+ ModularDeviceComponentModelFilterSetMixin,
1071
970
  CableTerminationModelFilterSetMixin,
1072
971
  PathEndpointModelFilterSetMixin,
972
+ BaseFilterSet,
1073
973
  ):
1074
974
  type = django_filters.MultipleChoiceFilter(choices=ConsolePortTypeChoices, null_value=None)
1075
975
 
@@ -1079,14 +979,15 @@ class ConsoleServerPortFilterSet(
1079
979
 
1080
980
 
1081
981
  class PowerPortFilterSet(
1082
- BaseFilterSet,
1083
- DeviceComponentModelFilterSetMixin,
982
+ ModularDeviceComponentModelFilterSetMixin,
1084
983
  CableTerminationModelFilterSetMixin,
1085
984
  PathEndpointModelFilterSetMixin,
985
+ BaseFilterSet,
1086
986
  ):
1087
987
  type = django_filters.MultipleChoiceFilter(choices=PowerPortTypeChoices, null_value=None)
1088
988
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1089
989
  power_outlets = NaturalKeyOrPKMultipleChoiceFilter(
990
+ prefers_id=True,
1090
991
  field_name="power_outlets",
1091
992
  to_field_name="name",
1092
993
  queryset=PowerOutlet.objects.all(),
@@ -1103,10 +1004,10 @@ class PowerPortFilterSet(
1103
1004
 
1104
1005
 
1105
1006
  class PowerOutletFilterSet(
1106
- BaseFilterSet,
1107
- DeviceComponentModelFilterSetMixin,
1007
+ ModularDeviceComponentModelFilterSetMixin,
1108
1008
  CableTerminationModelFilterSetMixin,
1109
1009
  PathEndpointModelFilterSetMixin,
1010
+ BaseFilterSet,
1110
1011
  ):
1111
1012
  type = django_filters.MultipleChoiceFilter(choices=PowerOutletTypeChoices, null_value=None)
1112
1013
  power_port = django_filters.ModelMultipleChoiceFilter(
@@ -1121,22 +1022,26 @@ class PowerOutletFilterSet(
1121
1022
 
1122
1023
  class InterfaceFilterSet(
1123
1024
  BaseFilterSet,
1124
- DeviceComponentModelFilterSetMixin,
1025
+ ModularDeviceComponentModelFilterSetMixin,
1125
1026
  CableTerminationModelFilterSetMixin,
1126
1027
  PathEndpointModelFilterSetMixin,
1127
1028
  StatusModelFilterSetMixin,
1029
+ RoleModelFilterSetMixin,
1128
1030
  ):
1129
- # Override device and device_id filters from DeviceComponentModelFilterSetMixin to
1031
+ # Override device and device_id filters from ModularDeviceComponentModelFilterSetMixin to
1130
1032
  # match against any peer virtual chassis members
1131
- device = MultiValueCharFilter(
1033
+ device = NaturalKeyOrPKMultipleChoiceFilter(
1034
+ queryset=Device.objects.all(),
1035
+ to_field_name="name",
1036
+ label="Device (name or ID)",
1132
1037
  method="filter_device",
1133
- field_name="name",
1134
- label="Device (name)",
1135
1038
  )
1136
- device_id = MultiValueUUIDFilter(
1039
+ # TODO 3.0: Remove this filter. Deprecated in favor of above NaturalKeyOrPKMultipleChoiceFilter `device`
1040
+ device_id = django_filters.ModelMultipleChoiceFilter(
1041
+ queryset=Device.objects.all(),
1137
1042
  method="filter_device_id",
1138
- field_name="pk",
1139
- label="Device (ID)",
1043
+ field_name="device",
1044
+ label='Device (ID) (deprecated, use "device" filter instead)',
1140
1045
  )
1141
1046
  device_with_common_vc = django_filters.UUIDFilter(
1142
1047
  method="filter_device_common_vc_id",
@@ -1149,28 +1054,33 @@ class InterfaceFilterSet(
1149
1054
  )
1150
1055
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1151
1056
  parent_interface = NaturalKeyOrPKMultipleChoiceFilter(
1057
+ prefers_id=True,
1152
1058
  queryset=Interface.objects.all(),
1153
1059
  to_field_name="name",
1154
1060
  label="Parent interface (name or ID)",
1155
1061
  )
1156
1062
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1157
1063
  bridge = NaturalKeyOrPKMultipleChoiceFilter(
1064
+ prefers_id=True,
1158
1065
  queryset=Interface.objects.all(),
1159
1066
  to_field_name="name",
1160
1067
  label="Bridge interface (name or ID)",
1161
1068
  )
1162
1069
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1163
1070
  lag = NaturalKeyOrPKMultipleChoiceFilter(
1071
+ prefers_id=True,
1164
1072
  to_field_name="name",
1165
1073
  queryset=Interface.objects.filter(type=InterfaceTypeChoices.TYPE_LAG),
1166
1074
  label="LAG interface (name or ID)",
1167
1075
  )
1168
1076
  untagged_vlan = NaturalKeyOrPKMultipleChoiceFilter(
1077
+ prefers_id=True,
1169
1078
  to_field_name="vid",
1170
1079
  queryset=VLAN.objects.all(),
1171
1080
  label="Untagged VLAN (VID or ID)",
1172
1081
  )
1173
1082
  tagged_vlans = NaturalKeyOrPKMultipleChoiceFilter(
1083
+ prefers_id=True,
1174
1084
  to_field_name="vid",
1175
1085
  queryset=VLAN.objects.all(),
1176
1086
  label="Tagged VLANs (VID or ID)",
@@ -1181,6 +1091,7 @@ class InterfaceFilterSet(
1181
1091
  )
1182
1092
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1183
1093
  child_interfaces = NaturalKeyOrPKMultipleChoiceFilter(
1094
+ prefers_id=True,
1184
1095
  queryset=Interface.objects.all(),
1185
1096
  to_field_name="name",
1186
1097
  label="Child interfaces (name or ID)",
@@ -1191,6 +1102,7 @@ class InterfaceFilterSet(
1191
1102
  )
1192
1103
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1193
1104
  bridged_interfaces = NaturalKeyOrPKMultipleChoiceFilter(
1105
+ prefers_id=True,
1194
1106
  to_field_name="name",
1195
1107
  queryset=Interface.objects.all(),
1196
1108
  label="Bridged interfaces (name or ID)",
@@ -1201,6 +1113,7 @@ class InterfaceFilterSet(
1201
1113
  )
1202
1114
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1203
1115
  member_interfaces = NaturalKeyOrPKMultipleChoiceFilter(
1116
+ prefers_id=True,
1204
1117
  to_field_name="name",
1205
1118
  queryset=Interface.objects.all(),
1206
1119
  label="Member interfaces (name or ID)",
@@ -1234,26 +1147,38 @@ class InterfaceFilterSet(
1234
1147
  "interface_redundancy_groups",
1235
1148
  ]
1236
1149
 
1150
+ def generate_query_filter_device(self, value):
1151
+ if not hasattr(value, "__iter__") or isinstance(value, str):
1152
+ value = [value]
1153
+
1154
+ device_ids = set(str(item) for item in value if is_uuid(item))
1155
+ device_names = set(str(item) for item in value if not is_uuid(item))
1156
+ devices = Device.objects.filter(Q(name__in=device_names) | Q(pk__in=device_ids))
1157
+ all_interface_ids = []
1158
+ for device in devices:
1159
+ all_interface_ids.extend(device.vc_interfaces.values_list("id", flat=True))
1160
+ return Q(pk__in=all_interface_ids)
1161
+
1237
1162
  def filter_device(self, queryset, name, value):
1238
- try:
1239
- devices = Device.objects.filter(**{f"{name}__in": value})
1240
- vc_interface_ids = []
1241
- for device in devices:
1242
- vc_interface_ids.extend(device.vc_interfaces.values_list("id", flat=True))
1243
- return queryset.filter(pk__in=vc_interface_ids)
1244
- except Device.DoesNotExist:
1245
- return queryset.none()
1163
+ if not value:
1164
+ return queryset
1165
+ params = self.generate_query_filter_device(value)
1166
+ return queryset.filter(params)
1246
1167
 
1247
- def filter_device_id(self, queryset, name, id_list):
1248
- # Include interfaces belonging to peer virtual chassis members
1249
- vc_interface_ids = []
1250
- try:
1251
- devices = Device.objects.filter(pk__in=id_list)
1252
- for device in devices:
1253
- vc_interface_ids += device.vc_interfaces.values_list("id", flat=True)
1254
- return queryset.filter(pk__in=vc_interface_ids)
1255
- except Device.DoesNotExist:
1256
- return queryset.none()
1168
+ def generate_query_filter_device_id(self, value):
1169
+ if not hasattr(value, "__iter__") or isinstance(value, str):
1170
+ value = [value]
1171
+
1172
+ all_interface_ids = []
1173
+ for device in value:
1174
+ all_interface_ids.extend(device.vc_interfaces.values_list("id", flat=True))
1175
+ return Q(pk__in=all_interface_ids)
1176
+
1177
+ def filter_device_id(self, queryset, name, value):
1178
+ if not value:
1179
+ return queryset
1180
+ params = self.generate_query_filter_device_id(value)
1181
+ return queryset.filter(params)
1257
1182
 
1258
1183
  def filter_device_common_vc_id(self, queryset, name, value):
1259
1184
  # Include interfaces that share common virtual chassis
@@ -1284,9 +1209,10 @@ class InterfaceFilterSet(
1284
1209
  }.get(value, queryset.none())
1285
1210
 
1286
1211
 
1287
- class FrontPortFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin, CableTerminationModelFilterSetMixin):
1212
+ class FrontPortFilterSet(ModularDeviceComponentModelFilterSetMixin, CableTerminationModelFilterSetMixin, BaseFilterSet):
1288
1213
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1289
1214
  rear_port = NaturalKeyOrPKMultipleChoiceFilter(
1215
+ prefers_id=True,
1290
1216
  to_field_name="name",
1291
1217
  queryset=RearPort.objects.all(),
1292
1218
  label="Rear port (name or ID)",
@@ -1297,7 +1223,7 @@ class FrontPortFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin, Cabl
1297
1223
  fields = ["id", "name", "type", "description", "label", "rear_port_position", "tags"]
1298
1224
 
1299
1225
 
1300
- class RearPortFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin, CableTerminationModelFilterSetMixin):
1226
+ class RearPortFilterSet(ModularDeviceComponentModelFilterSetMixin, CableTerminationModelFilterSetMixin, BaseFilterSet):
1301
1227
  front_ports = NaturalKeyOrPKMultipleChoiceFilter(
1302
1228
  to_field_name="name",
1303
1229
  queryset=FrontPort.objects.all(),
@@ -1313,9 +1239,10 @@ class RearPortFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin, Cable
1313
1239
  fields = ["id", "name", "type", "positions", "description", "label", "tags"]
1314
1240
 
1315
1241
 
1316
- class DeviceBayFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin):
1242
+ class DeviceBayFilterSet(DeviceComponentModelFilterSetMixin, BaseFilterSet):
1317
1243
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1318
1244
  installed_device = NaturalKeyOrPKMultipleChoiceFilter(
1245
+ prefers_id=True,
1319
1246
  field_name="installed_device",
1320
1247
  to_field_name="name",
1321
1248
  queryset=Device.objects.all(),
@@ -1327,7 +1254,7 @@ class DeviceBayFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin):
1327
1254
  fields = ["id", "name", "description", "label", "tags"]
1328
1255
 
1329
1256
 
1330
- class InventoryItemFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin):
1257
+ class InventoryItemFilterSet(DeviceComponentModelFilterSetMixin, BaseFilterSet):
1331
1258
  q = SearchFilter(
1332
1259
  filter_predicates={
1333
1260
  "name": "icontains",
@@ -1351,12 +1278,14 @@ class InventoryItemFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin):
1351
1278
  )
1352
1279
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1353
1280
  device = NaturalKeyOrPKMultipleChoiceFilter(
1281
+ prefers_id=True,
1354
1282
  queryset=Device.objects.all(),
1355
1283
  to_field_name="name",
1356
1284
  label="Device (name or ID)",
1357
1285
  )
1358
1286
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1359
1287
  parent = NaturalKeyOrPKMultipleChoiceFilter(
1288
+ prefers_id=True,
1360
1289
  queryset=InventoryItem.objects.all(),
1361
1290
  to_field_name="name",
1362
1291
  label="Parent items (name or ID)",
@@ -1368,6 +1297,7 @@ class InventoryItemFilterSet(BaseFilterSet, DeviceComponentModelFilterSetMixin):
1368
1297
  )
1369
1298
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1370
1299
  children = NaturalKeyOrPKMultipleChoiceFilter(
1300
+ prefers_id=True,
1371
1301
  queryset=InventoryItem.objects.all(),
1372
1302
  to_field_name="name",
1373
1303
  label="Child items (name or ID)",
@@ -1424,11 +1354,14 @@ class VirtualChassisFilterSet(NautobotFilterSet):
1424
1354
  )
1425
1355
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1426
1356
  master = NaturalKeyOrPKMultipleChoiceFilter(
1357
+ prefers_id=True,
1427
1358
  queryset=Device.objects.all(),
1428
1359
  to_field_name="name",
1429
1360
  label="Master (name or ID)",
1430
1361
  )
1362
+ # TODO Check this filter as it is not using TreeNode...
1431
1363
  location = NaturalKeyOrPKMultipleChoiceFilter(
1364
+ prefers_id=True,
1432
1365
  field_name="master__location",
1433
1366
  queryset=Location.objects.all(),
1434
1367
  to_field_name="name",
@@ -1442,6 +1375,7 @@ class VirtualChassisFilterSet(NautobotFilterSet):
1442
1375
  )
1443
1376
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1444
1377
  members = NaturalKeyOrPKMultipleChoiceFilter(
1378
+ prefers_id=True,
1445
1379
  to_field_name="name",
1446
1380
  queryset=Device.objects.all(),
1447
1381
  label="Device members (name or ID)",
@@ -1460,7 +1394,12 @@ class CableFilterSet(NautobotFilterSet, StatusModelFilterSetMixin):
1460
1394
  q = SearchFilter(filter_predicates={"label": "icontains"})
1461
1395
  type = django_filters.MultipleChoiceFilter(choices=CableTypeChoices)
1462
1396
  color = MultiValueCharFilter()
1463
- device_id = MultiValueUUIDFilter(method="filter_device", label="Device (ID)")
1397
+ device_id = django_filters.ModelMultipleChoiceFilter(
1398
+ queryset=Device.objects.all(),
1399
+ method="filter_device_id",
1400
+ field_name="_termination_a_device_id",
1401
+ label="Device (ID)",
1402
+ )
1464
1403
  device = MultiValueCharFilter(method="filter_device", field_name="device__name", label="Device (name)")
1465
1404
  rack_id = MultiValueUUIDFilter(method="filter_device", field_name="device__rack_id", label="Rack (ID)")
1466
1405
  rack = MultiValueCharFilter(method="filter_device", field_name="device__rack__name", label="Rack (name)")
@@ -1505,6 +1444,17 @@ class CableFilterSet(NautobotFilterSet, StatusModelFilterSetMixin):
1505
1444
  )
1506
1445
  return queryset
1507
1446
 
1447
+ def generate_query_filter_device_id(self, value):
1448
+ if not hasattr(value, "__iter__") or isinstance(value, str):
1449
+ value = [value]
1450
+ return Q(_termination_a_device_id__in=value) | Q(_termination_b_device_id__in=value)
1451
+
1452
+ def filter_device_id(self, queryset, name, value):
1453
+ if not value:
1454
+ return queryset
1455
+ params = self.generate_query_filter_device_id(value)
1456
+ return queryset.filter(params)
1457
+
1508
1458
  def generate_query__termination_type(self, value):
1509
1459
  a_type_q = Q()
1510
1460
  b_type_q = Q()
@@ -1576,15 +1526,17 @@ class InterfaceConnectionFilterSet(ConnectionFilterSetMixin, BaseFilterSet):
1576
1526
  fields = []
1577
1527
 
1578
1528
 
1579
- class PowerPanelFilterSet(NautobotFilterSet, LocatableModelFilterSetMixin):
1529
+ class PowerPanelFilterSet(LocatableModelFilterSetMixin, NautobotFilterSet):
1580
1530
  q = SearchFilter(filter_predicates={"name": "icontains"})
1581
1531
  rack_group = TreeNodeMultipleChoiceFilter(
1532
+ prefers_id=True,
1582
1533
  queryset=RackGroup.objects.all(),
1583
1534
  to_field_name="name",
1584
1535
  label="Rack group (name or ID)",
1585
1536
  )
1586
1537
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1587
1538
  power_feeds = NaturalKeyOrPKMultipleChoiceFilter(
1539
+ prefers_id=True,
1588
1540
  to_field_name="name",
1589
1541
  queryset=PowerFeed.objects.all(),
1590
1542
  label="Power feeds (name or ID)",
@@ -1600,10 +1552,15 @@ class PowerPanelFilterSet(NautobotFilterSet, LocatableModelFilterSetMixin):
1600
1552
 
1601
1553
 
1602
1554
  class PowerFeedFilterSet(
1603
- NautobotFilterSet, CableTerminationModelFilterSetMixin, PathEndpointModelFilterSetMixin, StatusModelFilterSetMixin
1555
+ NautobotFilterSet,
1556
+ CableTerminationModelFilterSetMixin,
1557
+ PathEndpointModelFilterSetMixin,
1558
+ StatusModelFilterSetMixin,
1604
1559
  ):
1605
1560
  q = SearchFilter(filter_predicates={"name": "icontains", "comments": "icontains"})
1561
+ # TODO: Why is this not using TreeNodeMultiple...
1606
1562
  location = NaturalKeyOrPKMultipleChoiceFilter(
1563
+ prefers_id=True,
1607
1564
  field_name="power_panel__location",
1608
1565
  queryset=Location.objects.all(),
1609
1566
  to_field_name="name",
@@ -1611,12 +1568,14 @@ class PowerFeedFilterSet(
1611
1568
  )
1612
1569
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1613
1570
  power_panel = NaturalKeyOrPKMultipleChoiceFilter(
1571
+ prefers_id=True,
1614
1572
  queryset=PowerPanel.objects.all(),
1615
1573
  to_field_name="name",
1616
1574
  label="Power panel (name or ID)",
1617
1575
  )
1618
1576
  # TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
1619
1577
  rack = NaturalKeyOrPKMultipleChoiceFilter(
1578
+ prefers_id=True,
1620
1579
  queryset=Rack.objects.all(),
1621
1580
  to_field_name="name",
1622
1581
  label="Rack (name or ID)",
@@ -1653,7 +1612,7 @@ class DeviceRedundancyGroupFilterSet(NautobotFilterSet, StatusModelFilterSetMixi
1653
1612
  fields = ["id", "name", "failover_strategy", "tags"]
1654
1613
 
1655
1614
 
1656
- class InterfaceRedundancyGroupFilterSet(BaseFilterSet, NameSearchFilterSet):
1615
+ class InterfaceRedundancyGroupFilterSet(NameSearchFilterSet, BaseFilterSet):
1657
1616
  """Filter for InterfaceRedundancyGroup."""
1658
1617
 
1659
1618
  q = SearchFilter(filter_predicates={"name": "icontains"})
@@ -1924,3 +1883,224 @@ class ControllerManagedDeviceGroupFilterSet(NautobotFilterSet):
1924
1883
  """FilterSet method for getting Groups that are or are descended from a given ControllerManagedDeviceGroup(s)."""
1925
1884
  params = self.generate_query__subtree(value)
1926
1885
  return queryset.filter(params)
1886
+
1887
+
1888
+ class ModuleFilterSet(
1889
+ NautobotFilterSet,
1890
+ DeviceModuleCommonFiltersMixin,
1891
+ LocatableModelFilterSetMixin,
1892
+ RoleModelFilterSetMixin,
1893
+ StatusModelFilterSetMixin,
1894
+ TenancyModelFilterSetMixin,
1895
+ ):
1896
+ q = SearchFilter(
1897
+ filter_predicates={
1898
+ "asset_tag": {
1899
+ "lookup_expr": "icontains",
1900
+ "preprocessor": str.strip,
1901
+ },
1902
+ "serial": {
1903
+ "lookup_expr": "icontains",
1904
+ "preprocessor": str.strip,
1905
+ },
1906
+ "module_type__manufacturer__name": {
1907
+ "lookup_expr": "icontains",
1908
+ "preprocessor": str.strip,
1909
+ },
1910
+ "module_type__model": {
1911
+ "lookup_expr": "icontains",
1912
+ "preprocessor": str.strip,
1913
+ },
1914
+ "parent_module_bay__parent_device__name": {
1915
+ "lookup_expr": "icontains",
1916
+ "preprocessor": str.strip,
1917
+ },
1918
+ "parent_module_bay__name": {
1919
+ "lookup_expr": "icontains",
1920
+ "preprocessor": str.strip,
1921
+ },
1922
+ "parent_module_bay__position": {
1923
+ "lookup_expr": "icontains",
1924
+ "preprocessor": str.strip,
1925
+ },
1926
+ "parent_module_bay__parent_module__module_type__manufacturer__name": {
1927
+ "lookup_expr": "icontains",
1928
+ "preprocessor": str.strip,
1929
+ },
1930
+ }
1931
+ )
1932
+ is_installed = RelatedMembershipBooleanFilter(
1933
+ field_name="parent_module_bay",
1934
+ label="Is installed in a module bay",
1935
+ )
1936
+ manufacturer = NaturalKeyOrPKMultipleChoiceFilter(
1937
+ field_name="module_type__manufacturer",
1938
+ queryset=Manufacturer.objects.all(),
1939
+ to_field_name="name",
1940
+ label="Manufacturer (name or ID)",
1941
+ )
1942
+ module_type = NaturalKeyOrPKMultipleChoiceFilter(
1943
+ queryset=ModuleType.objects.all(),
1944
+ to_field_name="model",
1945
+ label="Module type (model or ID)",
1946
+ )
1947
+ parent_module_bay = django_filters.ModelMultipleChoiceFilter(
1948
+ queryset=ModuleBay.objects.all(),
1949
+ label="Parent Module Bay",
1950
+ )
1951
+ device = NaturalKeyOrPKMultipleChoiceFilter(
1952
+ queryset=Device.objects.all(),
1953
+ to_field_name="name",
1954
+ label="Device (name or ID)",
1955
+ method="filter_device",
1956
+ )
1957
+
1958
+ def _construct_device_filter_recursively(self, field_name, value):
1959
+ recursion_depth = MODULE_RECURSION_DEPTH_LIMIT
1960
+ query = Q()
1961
+ for level in range(recursion_depth):
1962
+ recursive_query = "parent_module_bay__parent_module__" * level
1963
+ query = query | Q(**{f"{recursive_query}parent_module_bay__parent_device__{field_name}__in": value})
1964
+ return query
1965
+
1966
+ def generate_query_filter_device(self, value):
1967
+ if not hasattr(value, "__iter__") or isinstance(value, str):
1968
+ value = [value]
1969
+
1970
+ device_ids = set(str(item) for item in value if is_uuid(item))
1971
+ device_names = set(str(item) for item in value if not is_uuid(item))
1972
+ query = self._construct_device_filter_recursively("name", device_names)
1973
+ query |= self._construct_device_filter_recursively("id", device_ids)
1974
+ return query
1975
+
1976
+ def filter_device(self, queryset, name, value):
1977
+ if not value:
1978
+ return queryset
1979
+ params = self.generate_query_filter_device(value)
1980
+ return queryset.filter(params)
1981
+
1982
+ class Meta:
1983
+ model = Module
1984
+ fields = "__all__"
1985
+
1986
+
1987
+ class ModuleTypeFilterSet(DeviceTypeModuleTypeCommonFiltersMixin, NautobotFilterSet):
1988
+ q = SearchFilter(
1989
+ filter_predicates={
1990
+ "manufacturer__name": {
1991
+ "lookup_expr": "icontains",
1992
+ "preprocessor": str.strip,
1993
+ },
1994
+ "model": {
1995
+ "lookup_expr": "icontains",
1996
+ "preprocessor": str.strip,
1997
+ },
1998
+ "part_number": {
1999
+ "lookup_expr": "icontains",
2000
+ "preprocessor": str.strip,
2001
+ },
2002
+ "comments": {
2003
+ "lookup_expr": "icontains",
2004
+ "preprocessor": str.strip,
2005
+ },
2006
+ },
2007
+ )
2008
+ has_modules = RelatedMembershipBooleanFilter(
2009
+ field_name="modules",
2010
+ label="Has module instances",
2011
+ )
2012
+
2013
+ class Meta:
2014
+ model = ModuleType
2015
+ fields = "__all__"
2016
+
2017
+
2018
+ class ModuleBayTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, NautobotFilterSet):
2019
+ q = SearchFilter(
2020
+ filter_predicates={
2021
+ "device_type__manufacturer__name": {
2022
+ "lookup_expr": "icontains",
2023
+ "preprocessor": str.strip,
2024
+ },
2025
+ "device_type__model": {
2026
+ "lookup_expr": "icontains",
2027
+ "preprocessor": str.strip,
2028
+ },
2029
+ "module_type__manufacturer__name": {
2030
+ "lookup_expr": "icontains",
2031
+ "preprocessor": str.strip,
2032
+ },
2033
+ "module_type__model": {
2034
+ "lookup_expr": "icontains",
2035
+ "preprocessor": str.strip,
2036
+ },
2037
+ "name": {
2038
+ "lookup_expr": "icontains",
2039
+ "preprocessor": str.strip,
2040
+ },
2041
+ "position": {
2042
+ "lookup_expr": "icontains",
2043
+ "preprocessor": str.strip,
2044
+ },
2045
+ }
2046
+ )
2047
+
2048
+ class Meta:
2049
+ model = ModuleBayTemplate
2050
+ fields = "__all__"
2051
+
2052
+
2053
+ class ModuleBayFilterSet(NautobotFilterSet):
2054
+ q = SearchFilter(
2055
+ filter_predicates={
2056
+ "device__name": {
2057
+ "lookup_expr": "icontains",
2058
+ "preprocessor": str.strip,
2059
+ },
2060
+ "parent_module__module_type__manufacturer__name": {
2061
+ "lookup_expr": "icontains",
2062
+ "preprocessor": str.strip,
2063
+ },
2064
+ "parent_module__module_type__model": {
2065
+ "lookup_expr": "icontains",
2066
+ "preprocessor": str.strip,
2067
+ },
2068
+ "name": {
2069
+ "lookup_expr": "icontains",
2070
+ "preprocessor": str.strip,
2071
+ },
2072
+ "position": {
2073
+ "lookup_expr": "icontains",
2074
+ "preprocessor": str.strip,
2075
+ },
2076
+ }
2077
+ )
2078
+ parent_device = NaturalKeyOrPKMultipleChoiceFilter(
2079
+ queryset=Device.objects.all(),
2080
+ to_field_name="name",
2081
+ label="Parent device (name or ID)",
2082
+ )
2083
+ has_parent_device = RelatedMembershipBooleanFilter(
2084
+ field_name="parent_device",
2085
+ label="Has parent device",
2086
+ )
2087
+ parent_module = django_filters.ModelMultipleChoiceFilter(
2088
+ queryset=Module.objects.all(),
2089
+ label="Parent module (ID)",
2090
+ )
2091
+ has_parent_module = RelatedMembershipBooleanFilter(
2092
+ field_name="parent_module",
2093
+ label="Has parent module",
2094
+ )
2095
+ installed_module = django_filters.ModelMultipleChoiceFilter(
2096
+ queryset=Module.objects.all(),
2097
+ label="Installed module (ID)",
2098
+ )
2099
+ has_installed_module = RelatedMembershipBooleanFilter(
2100
+ field_name="installed_module",
2101
+ label="Has installed module",
2102
+ )
2103
+
2104
+ class Meta:
2105
+ model = ModuleBay
2106
+ fields = "__all__"