nautobot 2.0.0a2__py3-none-any.whl → 2.0.0b1__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.
Files changed (1029) hide show
  1. nautobot/__init__.py +1 -5
  2. nautobot/apps/api.py +6 -8
  3. nautobot/apps/forms.py +0 -2
  4. nautobot/apps/ui.py +0 -8
  5. nautobot/circuits/api/serializers.py +9 -119
  6. nautobot/circuits/api/urls.py +1 -1
  7. nautobot/circuits/api/views.py +0 -1
  8. nautobot/circuits/choices.py +0 -2
  9. nautobot/circuits/filters.py +7 -6
  10. nautobot/circuits/forms.py +3 -73
  11. nautobot/circuits/migrations/0001_initial_part_1.py +0 -1
  12. nautobot/circuits/migrations/0002_initial_part_2.py +0 -1
  13. nautobot/circuits/migrations/0003_auto_slug.py +0 -1
  14. nautobot/circuits/migrations/0004_increase_provider_account_length.py +0 -1
  15. nautobot/circuits/migrations/0005_providernetwork.py +0 -1
  16. nautobot/circuits/migrations/0006_cache_circuit_terminations.py +0 -1
  17. nautobot/circuits/migrations/0007_circuitterminations_primary_model.py +0 -1
  18. nautobot/circuits/migrations/0008_add_natural_indexing.py +0 -1
  19. nautobot/circuits/migrations/0009_circuittermination_location.py +0 -1
  20. nautobot/circuits/migrations/0010_rename_foreign_keys_and_related_names.py +0 -1
  21. nautobot/circuits/migrations/0011_remove_site_foreign_key_from_circuit_termination_class.py +0 -1
  22. nautobot/circuits/migrations/0012_created_datetime.py +0 -1
  23. nautobot/circuits/migrations/0013_alter_circuittermination__path.py +0 -1
  24. nautobot/circuits/migrations/0014_related_name_changes.py +1 -2
  25. nautobot/circuits/migrations/0015_remove_circuittype_provider_slug.py +20 -0
  26. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  27. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  28. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  29. nautobot/circuits/models.py +3 -93
  30. nautobot/circuits/navigation.py +14 -69
  31. nautobot/circuits/signals.py +0 -2
  32. nautobot/circuits/tables.py +42 -5
  33. nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -1
  34. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -1
  35. nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -1
  36. nautobot/circuits/templates/circuits/provider_create.html +0 -1
  37. nautobot/circuits/templates/circuits/provider_retrieve.html +1 -1
  38. nautobot/circuits/tests/integration/test_relationships.py +13 -16
  39. nautobot/circuits/tests/test_api.py +13 -43
  40. nautobot/circuits/tests/test_filters.py +20 -15
  41. nautobot/circuits/tests/test_models.py +7 -3
  42. nautobot/circuits/tests/test_views.py +57 -67
  43. nautobot/circuits/views.py +18 -9
  44. nautobot/core/api/__init__.py +8 -2
  45. nautobot/core/api/authentication.py +0 -3
  46. nautobot/core/api/fields.py +15 -6
  47. nautobot/core/api/filter_backends.py +3 -2
  48. nautobot/core/api/metadata.py +237 -30
  49. nautobot/core/api/mixins.py +94 -0
  50. nautobot/core/api/pagination.py +3 -3
  51. nautobot/core/api/parsers.py +154 -0
  52. nautobot/core/api/renderers.py +153 -2
  53. nautobot/core/api/schema.py +47 -3
  54. nautobot/core/api/serializers.py +377 -37
  55. nautobot/core/api/urls.py +11 -3
  56. nautobot/core/api/utils.py +174 -2
  57. nautobot/core/api/versioning.py +32 -10
  58. nautobot/core/api/views.py +266 -75
  59. nautobot/core/apps/__init__.py +138 -221
  60. nautobot/core/celery/__init__.py +112 -41
  61. nautobot/core/celery/backends.py +19 -13
  62. nautobot/core/celery/control.py +46 -0
  63. nautobot/core/celery/encoders.py +53 -0
  64. nautobot/core/celery/log.py +38 -0
  65. nautobot/core/celery/schedulers.py +23 -4
  66. nautobot/core/celery/task.py +1 -16
  67. nautobot/core/checks.py +0 -27
  68. nautobot/core/choices.py +21 -113
  69. nautobot/core/{cli.py → cli/__init__.py} +1 -2
  70. nautobot/core/cli/__main__.py +3 -0
  71. nautobot/core/constants.py +25 -43
  72. nautobot/core/context_processors.py +12 -0
  73. nautobot/core/filters.py +2 -2
  74. nautobot/core/forms/__init__.py +0 -4
  75. nautobot/core/forms/fields.py +39 -68
  76. nautobot/core/forms/forms.py +27 -27
  77. nautobot/core/forms/utils.py +7 -59
  78. nautobot/core/forms/widgets.py +0 -1
  79. nautobot/core/graphql/__init__.py +2 -2
  80. nautobot/core/graphql/schema.py +4 -27
  81. nautobot/core/jobs/__init__.py +75 -0
  82. nautobot/core/management/commands/build_ui.py +255 -0
  83. nautobot/core/management/commands/celery.py +0 -1
  84. nautobot/core/management/commands/generate_test_data.py +18 -13
  85. nautobot/core/management/commands/post_upgrade.py +24 -24
  86. nautobot/core/management/commands/validate_models.py +0 -1
  87. nautobot/core/middleware.py +0 -1
  88. nautobot/core/models/__init__.py +26 -1
  89. nautobot/core/models/fields.py +24 -5
  90. nautobot/core/models/generics.py +2 -46
  91. nautobot/core/models/managers.py +5 -0
  92. nautobot/core/models/name_color_content_types.py +1 -19
  93. nautobot/core/models/tree_queries.py +14 -4
  94. nautobot/core/models/utils.py +9 -10
  95. nautobot/core/models/validators.py +17 -8
  96. nautobot/core/releases.py +8 -10
  97. nautobot/core/settings.py +81 -53
  98. nautobot/core/tables.py +5 -5
  99. nautobot/core/tasks.py +4 -7
  100. nautobot/core/templates/base.html +1 -49
  101. nautobot/core/templates/base_django.html +49 -0
  102. nautobot/core/templates/base_react.html +55 -0
  103. nautobot/core/templates/buttons/export.html +6 -4
  104. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  105. nautobot/core/templates/generic/object_list.html +4 -1
  106. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  107. nautobot/core/templates/inc/footer.html +1 -0
  108. nautobot/core/templates/inc/javascript.html +0 -14
  109. nautobot/core/templates/inc/nav_menu.html +28 -33
  110. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  111. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  112. nautobot/core/templates/nautobot_config.py.j2 +8 -25
  113. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  114. nautobot/core/templates/rest_framework/api.html +8 -0
  115. nautobot/core/templatetags/buttons.py +32 -29
  116. nautobot/core/templatetags/helpers.py +1 -1
  117. nautobot/core/testing/__init__.py +47 -44
  118. nautobot/core/testing/api.py +365 -47
  119. nautobot/core/testing/filters.py +12 -7
  120. nautobot/core/testing/integration.py +1 -1
  121. nautobot/core/testing/migrations.py +2 -0
  122. nautobot/core/testing/mixins.py +22 -12
  123. nautobot/core/testing/schema.py +2 -1
  124. nautobot/core/testing/views.py +28 -51
  125. nautobot/core/tests/integration/test_filters.py +17 -8
  126. nautobot/core/tests/integration/test_navbar.py +11 -34
  127. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  128. nautobot/core/tests/nautobot_config.py +2 -3
  129. nautobot/core/tests/runner.py +0 -1
  130. nautobot/core/tests/test_api.py +290 -24
  131. nautobot/core/tests/test_authentication.py +57 -14
  132. nautobot/core/tests/test_checks.py +0 -7
  133. nautobot/core/tests/test_choices.py +0 -1
  134. nautobot/core/tests/test_filters.py +117 -110
  135. nautobot/core/tests/test_forms.py +47 -110
  136. nautobot/core/tests/test_graphql.py +158 -135
  137. nautobot/core/tests/test_logging.py +4 -1
  138. nautobot/core/tests/test_managers.py +3 -5
  139. nautobot/core/tests/test_models.py +2 -0
  140. nautobot/core/tests/test_ordering.py +0 -2
  141. nautobot/core/tests/test_paginator.py +3 -1
  142. nautobot/core/tests/test_releases.py +12 -12
  143. nautobot/core/tests/test_templatetags_helpers.py +7 -4
  144. nautobot/core/tests/test_utils.py +112 -78
  145. nautobot/core/tests/test_views.py +12 -17
  146. nautobot/core/tests/test_views_utils.py +6 -9
  147. nautobot/core/utils/data.py +17 -0
  148. nautobot/core/utils/deprecation.py +13 -20
  149. nautobot/core/utils/filtering.py +53 -9
  150. nautobot/core/utils/git.py +12 -4
  151. nautobot/core/utils/lookup.py +3 -1
  152. nautobot/core/utils/requests.py +23 -116
  153. nautobot/core/views/__init__.py +1 -2
  154. nautobot/core/views/generic.py +131 -119
  155. nautobot/core/views/mixins.py +53 -62
  156. nautobot/core/views/paginator.py +0 -1
  157. nautobot/core/views/renderers.py +14 -12
  158. nautobot/core/views/utils.py +87 -4
  159. nautobot/dcim/api/serializers.py +160 -672
  160. nautobot/dcim/api/urls.py +1 -1
  161. nautobot/dcim/api/views.py +7 -46
  162. nautobot/dcim/choices.py +2 -25
  163. nautobot/dcim/elevations.py +0 -1
  164. nautobot/dcim/factory.py +15 -4
  165. nautobot/dcim/filters/__init__.py +42 -13
  166. nautobot/dcim/form_mixins.py +1 -27
  167. nautobot/dcim/forms.py +58 -797
  168. nautobot/dcim/management/commands/trace_paths.py +0 -1
  169. nautobot/dcim/migrations/0001_initial_part_1.py +0 -1
  170. nautobot/dcim/migrations/0002_initial_part_2.py +0 -1
  171. nautobot/dcim/migrations/0003_initial_part_3.py +0 -1
  172. nautobot/dcim/migrations/0004_initial_part_4.py +0 -1
  173. nautobot/dcim/migrations/0005_device_local_context_schema.py +0 -1
  174. nautobot/dcim/migrations/0006_auto_slug.py +0 -1
  175. nautobot/dcim/migrations/0007_device_secrets_group.py +0 -1
  176. nautobot/dcim/migrations/0008_increase_all_serial_lengths.py +0 -1
  177. nautobot/dcim/migrations/0009_add_natural_indexing.py +0 -1
  178. nautobot/dcim/migrations/0010_interface_status.py +0 -1
  179. nautobot/dcim/migrations/0011_interface_status_data_migration.py +0 -1
  180. nautobot/dcim/migrations/0012_interface_parent_bridge.py +0 -1
  181. nautobot/dcim/migrations/0013_location_location_type.py +0 -1
  182. nautobot/dcim/migrations/0014_location_status_data_migration.py +0 -1
  183. nautobot/dcim/migrations/0015_device_components__changeloggedmodel.py +0 -1
  184. nautobot/dcim/migrations/0016_device_components__timestamp_data_migration.py +0 -1
  185. nautobot/dcim/migrations/0017_locationtype_nestable.py +0 -1
  186. nautobot/dcim/migrations/0018_device_redundancy_group.py +0 -1
  187. nautobot/dcim/migrations/0019_device_redundancy_group_data_migration.py +0 -1
  188. nautobot/dcim/migrations/0020_move_site_fields_to_location_model.py +0 -1
  189. nautobot/dcim/migrations/0021_mptt_to_tree_queries.py +0 -1
  190. nautobot/dcim/migrations/0022_interface_mac_address_data_migration.py +0 -1
  191. nautobot/dcim/migrations/0023_alter_interface_mac_address.py +0 -1
  192. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -2
  193. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -14
  194. nautobot/dcim/migrations/0026_rename_device_and_rack_role.py +0 -1
  195. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -2
  196. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -2
  197. nautobot/dcim/migrations/0029_add_tree_managers_and_foreign_keys_pre_data_migration.py +0 -1
  198. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  199. nautobot/dcim/migrations/0031_rename_path_end_point_related_name.py +0 -1
  200. nautobot/dcim/migrations/0032_remove_site_foreign_key_from_dcim_models.py +0 -1
  201. nautobot/dcim/migrations/0033_created_datetime.py +0 -1
  202. nautobot/dcim/migrations/0034_fixup_fks_and_related_names.py +0 -1
  203. nautobot/dcim/migrations/0035_related_name_changes.py +1 -2
  204. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -2
  205. nautobot/dcim/migrations/0037_interface_ip_addresses_m2m.py +0 -1
  206. nautobot/dcim/migrations/0038_alter_location_managers.py +0 -1
  207. nautobot/dcim/migrations/0039_remove_slug.py +24 -0
  208. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  209. nautobot/dcim/migrations/0041_ipam__namespaces.py +25 -0
  210. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  211. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  212. nautobot/dcim/models/cables.py +4 -35
  213. nautobot/dcim/models/device_component_templates.py +7 -2
  214. nautobot/dcim/models/device_components.py +26 -203
  215. nautobot/dcim/models/devices.py +30 -152
  216. nautobot/dcim/models/locations.py +3 -64
  217. nautobot/dcim/models/power.py +3 -51
  218. nautobot/dcim/models/racks.py +7 -86
  219. nautobot/dcim/navigation.py +141 -467
  220. nautobot/dcim/signals.py +0 -2
  221. nautobot/dcim/tables/devices.py +8 -5
  222. nautobot/dcim/tables/devicetypes.py +1 -1
  223. nautobot/dcim/tables/locations.py +2 -2
  224. nautobot/dcim/tables/power.py +2 -2
  225. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  226. nautobot/dcim/templates/dcim/device.html +15 -4
  227. nautobot/dcim/templates/dcim/device_edit.html +6 -0
  228. nautobot/dcim/templates/dcim/deviceredundancygroup_create.html +0 -1
  229. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  230. nautobot/dcim/templates/dcim/interface.html +4 -0
  231. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  232. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  233. nautobot/dcim/templates/dcim/location.html +16 -1
  234. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  235. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  236. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  237. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  238. nautobot/dcim/tests/test_api.py +202 -130
  239. nautobot/dcim/tests/test_cablepaths.py +47 -42
  240. nautobot/dcim/tests/test_filters.py +156 -134
  241. nautobot/dcim/tests/test_forms.py +12 -213
  242. nautobot/dcim/tests/test_graphql.py +8 -3
  243. nautobot/dcim/tests/test_migrations.py +6 -11
  244. nautobot/dcim/tests/test_models.py +208 -158
  245. nautobot/dcim/tests/test_natural_ordering.py +12 -14
  246. nautobot/dcim/tests/test_signals.py +7 -4
  247. nautobot/dcim/tests/test_views.py +270 -264
  248. nautobot/dcim/urls.py +21 -26
  249. nautobot/dcim/views.py +14 -156
  250. nautobot/docs/additional-features/caching.md +6 -87
  251. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  252. nautobot/docs/additional-features/jobs.md +179 -197
  253. nautobot/docs/administration/nautobot-server.md +9 -24
  254. nautobot/docs/administration/nautobot-shell.md +6 -6
  255. nautobot/docs/administration/replicating-nautobot.md +0 -10
  256. nautobot/docs/configuration/index.md +9 -9
  257. nautobot/docs/configuration/optional-settings.md +32 -61
  258. nautobot/docs/configuration/required-settings.md +11 -52
  259. nautobot/docs/development/application-registry.md +2 -13
  260. nautobot/docs/development/best-practices.md +2 -1
  261. nautobot/docs/development/docker-compose-advanced-use-cases.md +1 -1
  262. nautobot/docs/development/extending-models.md +15 -17
  263. nautobot/docs/development/generic-views.md +0 -2
  264. nautobot/docs/development/getting-started.md +56 -6
  265. nautobot/docs/development/navigation-menu.md +22 -93
  266. nautobot/docs/development/react-ui.md +105 -0
  267. nautobot/docs/development/release-checklist.md +3 -3
  268. nautobot/docs/development/role-internals.md +1 -3
  269. nautobot/docs/development/style-guide.md +6 -4
  270. nautobot/docs/development/templates.md +2 -1
  271. nautobot/docs/docker/index.md +16 -14
  272. nautobot/docs/index.md +7 -3
  273. nautobot/docs/installation/index.md +4 -1
  274. nautobot/docs/installation/migrating-from-netbox.md +12 -43
  275. nautobot/docs/installation/migrating-from-postgresql.md +1 -1
  276. nautobot/docs/installation/nautobot.md +1 -1
  277. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  278. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  279. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  280. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  281. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  282. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  283. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  284. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  285. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  286. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  287. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  288. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  289. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  290. nautobot/docs/installation/upgrading-from-nautobot-v1.md +190 -636
  291. nautobot/docs/installation/upgrading.md +5 -2
  292. nautobot/docs/models/dcim/device.md +3 -0
  293. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  294. nautobot/docs/models/extras/computedfield.md +4 -4
  295. nautobot/docs/models/extras/dynamicgroup.md +9 -9
  296. nautobot/docs/models/extras/gitrepository.md +3 -0
  297. nautobot/docs/models/extras/job.md +1 -0
  298. nautobot/docs/models/extras/jobbutton.md +18 -13
  299. nautobot/docs/models/extras/jobhook.md +7 -4
  300. nautobot/docs/models/extras/jobresult.md +6 -2
  301. nautobot/docs/models/extras/relationship.md +2 -2
  302. nautobot/docs/models/extras/status.md +6 -19
  303. nautobot/docs/models/ipam/ipaddress.md +3 -0
  304. nautobot/docs/models/ipam/vrf.md +0 -3
  305. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  306. nautobot/docs/plugins/development.md +92 -24
  307. nautobot/docs/release-notes/version-1.5.md +96 -0
  308. nautobot/docs/release-notes/version-2.0.md +216 -0
  309. nautobot/docs/requirements.txt +5 -4
  310. nautobot/docs/rest-api/overview.md +384 -215
  311. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  312. nautobot/extras/admin.py +3 -5
  313. nautobot/extras/api/customfields.py +15 -39
  314. nautobot/extras/api/fields.py +0 -11
  315. nautobot/extras/api/mixins.py +45 -0
  316. nautobot/extras/api/relationships.py +63 -159
  317. nautobot/extras/api/serializers.py +165 -706
  318. nautobot/extras/api/urls.py +1 -1
  319. nautobot/extras/api/views.py +295 -282
  320. nautobot/extras/apps.py +4 -7
  321. nautobot/extras/choices.py +11 -22
  322. nautobot/extras/constants.py +9 -3
  323. nautobot/extras/datasources/__init__.py +2 -0
  324. nautobot/extras/datasources/git.py +135 -186
  325. nautobot/extras/datasources/registry.py +25 -35
  326. nautobot/extras/factory.py +1 -3
  327. nautobot/extras/filters/__init__.py +49 -47
  328. nautobot/extras/filters/mixins.py +10 -8
  329. nautobot/extras/forms/forms.py +72 -148
  330. nautobot/extras/forms/mixins.py +34 -57
  331. nautobot/extras/health_checks.py +0 -33
  332. nautobot/extras/jobs.py +387 -566
  333. nautobot/extras/management/__init__.py +55 -48
  334. nautobot/extras/management/commands/renaturalize.py +0 -1
  335. nautobot/extras/management/commands/runjob.py +24 -62
  336. nautobot/extras/management/commands/webhook_receiver.py +0 -1
  337. nautobot/extras/managers.py +30 -7
  338. nautobot/extras/migrations/0001_initial_part_1.py +0 -1
  339. nautobot/extras/migrations/0002_initial_part_2.py +0 -1
  340. nautobot/extras/migrations/0003_initial_part_3.py +0 -1
  341. nautobot/extras/migrations/0004_populate_default_status_records.py +0 -1
  342. nautobot/extras/migrations/0005_configcontext_device_types.py +0 -1
  343. nautobot/extras/migrations/0006_graphqlquery.py +0 -1
  344. nautobot/extras/migrations/0007_configcontextschema.py +0 -1
  345. nautobot/extras/migrations/0008_jobresult__custom_field_data.py +0 -1
  346. nautobot/extras/migrations/0009_computedfield.py +0 -1
  347. nautobot/extras/migrations/0010_change_cf_validation_max_min_field_to_bigint.py +0 -1
  348. nautobot/extras/migrations/0011_fileattachment_fileproxy.py +0 -1
  349. nautobot/extras/migrations/0012_healthchecktestmodel.py +0 -1
  350. nautobot/extras/migrations/0013_default_fallback_value_computedfield.py +0 -1
  351. nautobot/extras/migrations/0014_auto_slug.py +0 -1
  352. nautobot/extras/migrations/0015_scheduled_job.py +0 -1
  353. nautobot/extras/migrations/0016_secret.py +0 -1
  354. nautobot/extras/migrations/0017_joblogentry.py +0 -1
  355. nautobot/extras/migrations/0018_joblog_data_migration.py +0 -2
  356. nautobot/extras/migrations/0019_joblogentry__meta_options__related_name.py +0 -1
  357. nautobot/extras/migrations/0020_customfield_changelog.py +0 -1
  358. nautobot/extras/migrations/0021_customfield_changelog_data.py +0 -1
  359. nautobot/extras/migrations/0022_objectchange_object_datav2.py +0 -1
  360. nautobot/extras/migrations/0023_job_model.py +0 -1
  361. nautobot/extras/migrations/0024_job_data_migration.py +0 -1
  362. nautobot/extras/migrations/0025_add_advanced_ui_boolean_to_customfield_conputedfield_and_relationship.py +0 -1
  363. nautobot/extras/migrations/0026_job_add_gitrepository_fk.py +0 -1
  364. nautobot/extras/migrations/0027_job_gitrepository_data_migration.py +0 -1
  365. nautobot/extras/migrations/0028_job_reduce_source.py +0 -1
  366. nautobot/extras/migrations/0029_dynamicgroup.py +0 -1
  367. nautobot/extras/migrations/0030_webhook_alter_unique_together.py +0 -1
  368. nautobot/extras/migrations/0031_tag_content_types.py +0 -1
  369. nautobot/extras/migrations/0032_tag_content_types_data_migration.py +0 -1
  370. nautobot/extras/migrations/0033_add__optimized_indexing.py +0 -1
  371. nautobot/extras/migrations/0034_alter_fileattachment_mimetype.py +0 -1
  372. nautobot/extras/migrations/0035_scheduledjob_crontab.py +0 -1
  373. nautobot/extras/migrations/0036_job_add_has_sensitive_variables.py +0 -1
  374. nautobot/extras/migrations/0037_configcontextschema__remove_name_unique__create_constraint_unique_name_owner.py +0 -1
  375. nautobot/extras/migrations/0038_configcontext_locations.py +0 -1
  376. nautobot/extras/migrations/0039_objectchange__add_change_context.py +0 -1
  377. nautobot/extras/migrations/0040_dynamicgroup__dynamicgroupmembership.py +0 -1
  378. nautobot/extras/migrations/0041_jobresult_job_kwargs.py +0 -1
  379. nautobot/extras/migrations/0042_job__add_is_job_hook_receiver.py +0 -1
  380. nautobot/extras/migrations/0043_note.py +0 -1
  381. nautobot/extras/migrations/0044_add_job_hook.py +0 -1
  382. nautobot/extras/migrations/0045_add_custom_field_slug.py +0 -1
  383. nautobot/extras/migrations/0046_populate_custom_field_slug_label.py +0 -1
  384. nautobot/extras/migrations/0047_enforce_custom_field_slug.py +0 -1
  385. nautobot/extras/migrations/0048_alter_objectchange_change_context_detail.py +0 -1
  386. nautobot/extras/migrations/0049_alter_tag_slug.py +0 -1
  387. nautobot/extras/migrations/0050_customfield_grouping.py +0 -1
  388. nautobot/extras/migrations/0051_add_job_task_queues.py +0 -1
  389. nautobot/extras/migrations/0052_configcontext_device_redundancy_groups.py +0 -1
  390. nautobot/extras/migrations/0053_relationship_required_on.py +0 -1
  391. nautobot/extras/migrations/0054_scheduledjob_kwargs_request_user_change.py +0 -1
  392. nautobot/extras/migrations/0055_configcontext_dynamic_groups.py +0 -1
  393. nautobot/extras/migrations/0056_objectchange_add_reverse_time_idx.py +0 -1
  394. nautobot/extras/migrations/0057_jobbutton.py +0 -1
  395. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  396. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -2
  397. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -2
  398. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -8
  399. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -33
  400. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -2
  401. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -2
  402. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  403. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -2
  404. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -3
  405. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -2
  406. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -2
  407. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  408. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -2
  409. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  410. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -10
  411. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -2
  412. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  413. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  414. nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
  415. nautobot/extras/migrations/0078_remove_slug.py +45 -0
  416. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  417. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  418. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  419. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  420. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  421. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  422. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  423. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  424. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  425. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  426. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  427. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  428. nautobot/extras/models/__init__.py +2 -3
  429. nautobot/extras/models/change_logging.py +0 -36
  430. nautobot/extras/models/customfields.py +39 -33
  431. nautobot/extras/models/datasources.py +48 -50
  432. nautobot/extras/models/groups.py +5 -12
  433. nautobot/extras/models/jobs.py +190 -323
  434. nautobot/extras/models/mixins.py +0 -71
  435. nautobot/extras/models/models.py +1 -22
  436. nautobot/extras/models/relationships.py +20 -21
  437. nautobot/extras/models/roles.py +0 -23
  438. nautobot/extras/models/secrets.py +2 -31
  439. nautobot/extras/models/statuses.py +6 -5
  440. nautobot/extras/models/tags.py +2 -17
  441. nautobot/extras/navigation.py +89 -307
  442. nautobot/extras/plugins/__init__.py +3 -121
  443. nautobot/extras/plugins/utils.py +0 -3
  444. nautobot/extras/plugins/validators.py +5 -4
  445. nautobot/extras/plugins/views.py +16 -4
  446. nautobot/extras/querysets.py +1 -7
  447. nautobot/extras/registry.py +3 -0
  448. nautobot/extras/signals.py +26 -60
  449. nautobot/extras/tables.py +42 -49
  450. nautobot/extras/tasks.py +0 -12
  451. nautobot/extras/templates/extras/configcontext.html +1 -1
  452. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  453. nautobot/extras/templates/extras/customfield.html +0 -13
  454. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -1
  455. nautobot/extras/templates/extras/gitrepository.html +3 -3
  456. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  457. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  458. nautobot/extras/templates/extras/job.html +35 -25
  459. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  460. nautobot/extras/templates/extras/job_detail.html +13 -31
  461. nautobot/extras/templates/extras/job_edit.html +14 -17
  462. nautobot/extras/templates/extras/jobresult.html +24 -6
  463. nautobot/extras/templates/extras/objectchange_list.html +1 -1
  464. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  465. nautobot/extras/templates/extras/secret.html +28 -0
  466. nautobot/extras/templates/extras/secret_edit.html +0 -1
  467. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -1
  468. nautobot/extras/templatetags/custom_links.py +0 -2
  469. nautobot/extras/templatetags/job_buttons.py +1 -0
  470. nautobot/extras/templatetags/plugins.py +0 -1
  471. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  472. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  473. nautobot/extras/test_jobs/dry_run.py +29 -0
  474. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  475. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  476. nautobot/extras/test_jobs/fail.py +23 -0
  477. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  478. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  479. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  480. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  481. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  482. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  483. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  484. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  485. nautobot/extras/test_jobs/job_variables.py +88 -0
  486. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  487. nautobot/extras/test_jobs/log_redaction.py +20 -0
  488. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  489. nautobot/extras/test_jobs/modify_db.py +25 -0
  490. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  491. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  492. nautobot/extras/test_jobs/object_var_required.py +21 -0
  493. nautobot/extras/test_jobs/object_vars.py +26 -0
  494. nautobot/extras/test_jobs/pass.py +25 -0
  495. nautobot/extras/test_jobs/profiling.py +32 -0
  496. nautobot/extras/test_jobs/read_only_job.py +15 -0
  497. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  498. nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
  499. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  500. nautobot/extras/tests/integration/__init__.py +3 -3
  501. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  502. nautobot/extras/tests/integration/test_configcontextschema.py +7 -5
  503. nautobot/extras/tests/integration/test_customfields.py +4 -2
  504. nautobot/extras/tests/integration/test_dynamicgroups.py +2 -2
  505. nautobot/extras/tests/integration/test_jobs.py +25 -27
  506. nautobot/extras/tests/integration/test_notes.py +8 -4
  507. nautobot/extras/tests/integration/test_plugins.py +4 -4
  508. nautobot/extras/tests/integration/test_relationships.py +2 -2
  509. nautobot/extras/tests/test_api.py +371 -381
  510. nautobot/extras/tests/test_changelog.py +17 -16
  511. nautobot/extras/tests/test_context_managers.py +5 -6
  512. nautobot/extras/tests/test_customfields.py +112 -73
  513. nautobot/extras/tests/test_datasources.py +191 -117
  514. nautobot/extras/tests/test_dynamicgroups.py +45 -68
  515. nautobot/extras/tests/test_filters.py +170 -130
  516. nautobot/extras/tests/test_forms.py +107 -109
  517. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  518. nautobot/extras/tests/test_jobs.py +271 -273
  519. nautobot/extras/tests/test_management.py +3 -6
  520. nautobot/extras/tests/test_migrations.py +5 -3
  521. nautobot/extras/tests/test_models.py +121 -173
  522. nautobot/extras/tests/test_notes.py +0 -1
  523. nautobot/extras/tests/test_plugins.py +55 -89
  524. nautobot/extras/tests/test_relationships.py +174 -130
  525. nautobot/extras/tests/test_tags.py +6 -12
  526. nautobot/extras/tests/test_utils.py +31 -1
  527. nautobot/extras/tests/test_views.py +223 -184
  528. nautobot/extras/tests/test_webhooks.py +16 -15
  529. nautobot/extras/urls.py +69 -69
  530. nautobot/extras/utils.py +137 -163
  531. nautobot/extras/views.py +81 -153
  532. nautobot/ipam/api/fields.py +17 -0
  533. nautobot/ipam/api/serializers.py +77 -164
  534. nautobot/ipam/api/urls.py +4 -1
  535. nautobot/ipam/api/views.py +28 -19
  536. nautobot/ipam/apps.py +1 -0
  537. nautobot/ipam/choices.py +5 -12
  538. nautobot/ipam/constants.py +1 -0
  539. nautobot/ipam/factory.py +41 -30
  540. nautobot/ipam/filters.py +58 -25
  541. nautobot/ipam/forms.py +82 -211
  542. nautobot/ipam/graphql/types.py +0 -9
  543. nautobot/ipam/lookups.py +13 -8
  544. nautobot/ipam/management/commands/__init__.py +0 -0
  545. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  546. nautobot/ipam/migrations/0001_initial_part_1.py +0 -1
  547. nautobot/ipam/migrations/0002_initial_part_2.py +0 -1
  548. nautobot/ipam/migrations/0003_remove_max_length.py +0 -1
  549. nautobot/ipam/migrations/0004_fixup_p2p_broadcast.py +0 -1
  550. nautobot/ipam/migrations/0005_auto_slug.py +0 -1
  551. nautobot/ipam/migrations/0006_ipaddress_nat_outside_list.py +0 -1
  552. nautobot/ipam/migrations/0007_add_natural_indexing.py +0 -1
  553. nautobot/ipam/migrations/0008_prefix_vlan_vlangroup_location.py +0 -1
  554. nautobot/ipam/migrations/0009_alter_vlan_name.py +0 -1
  555. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -2
  556. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -39
  557. nautobot/ipam/migrations/0012_rename_ipam_roles.py +0 -1
  558. nautobot/ipam/migrations/0013_delete_role.py +0 -1
  559. nautobot/ipam/migrations/0014_rename_foreign_keys_and_related_names.py +0 -1
  560. nautobot/ipam/migrations/0015_prefix_add_type.py +0 -1
  561. nautobot/ipam/migrations/0016_prefix_type_data_migration.py +0 -3
  562. nautobot/ipam/migrations/0017_prefix_remove_is_pool.py +0 -1
  563. nautobot/ipam/migrations/0018_remove_site_foreign_key_from_ipam_models.py +0 -1
  564. nautobot/ipam/migrations/0019_created_datetime.py +0 -1
  565. nautobot/ipam/migrations/0020_related_name_changes.py +1 -2
  566. nautobot/ipam/migrations/0021_prefix_add_rir_and_date_allocated.py +0 -1
  567. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +3 -5
  568. nautobot/ipam/migrations/0023_delete_aggregate.py +0 -1
  569. nautobot/ipam/migrations/0024_interface_to_ipaddress_m2m.py +0 -1
  570. nautobot/ipam/migrations/0025_interface_ipaddress_m2m_data_migration.py +0 -1
  571. nautobot/ipam/migrations/0026_ipaddress_remove_assigned_object.py +0 -1
  572. nautobot/ipam/migrations/0027_remove_rir_slug.py +16 -0
  573. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  574. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  575. nautobot/ipam/migrations/0030_ipam__namespaces.py +231 -0
  576. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  577. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  578. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  579. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  580. nautobot/ipam/models.py +579 -368
  581. nautobot/ipam/navigation.py +36 -159
  582. nautobot/ipam/querysets.py +117 -90
  583. nautobot/ipam/signals.py +89 -0
  584. nautobot/ipam/tables.py +86 -28
  585. nautobot/ipam/templates/ipam/ipaddress.html +14 -30
  586. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -0
  587. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  588. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  589. nautobot/ipam/templates/ipam/namespace_retrieve.html +42 -0
  590. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  591. nautobot/ipam/templates/ipam/prefix.html +27 -33
  592. nautobot/ipam/templates/ipam/prefix_edit.html +7 -1
  593. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  594. nautobot/ipam/templates/ipam/vrf.html +6 -4
  595. nautobot/ipam/templates/ipam/vrf_edit.html +20 -2
  596. nautobot/ipam/tests/integration/test_prefixes.py +4 -27
  597. nautobot/ipam/tests/test_api.py +60 -61
  598. nautobot/ipam/tests/test_filters.py +187 -126
  599. nautobot/ipam/tests/test_forms.py +12 -6
  600. nautobot/ipam/tests/test_graphql.py +8 -6
  601. nautobot/ipam/tests/test_migrations.py +8 -13
  602. nautobot/ipam/tests/test_models.py +426 -274
  603. nautobot/ipam/tests/test_ordering.py +6 -3
  604. nautobot/ipam/tests/test_querysets.py +340 -96
  605. nautobot/ipam/tests/test_views.py +100 -55
  606. nautobot/ipam/urls.py +28 -5
  607. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  608. nautobot/ipam/utils/migrations.py +713 -0
  609. nautobot/ipam/views.py +237 -122
  610. nautobot/project-static/docs/404.html +1399 -166
  611. nautobot/project-static/docs/additional-features/caching.html +1416 -320
  612. nautobot/project-static/docs/additional-features/change-logging.html +1389 -190
  613. nautobot/project-static/docs/additional-features/config-contexts.html +1389 -190
  614. nautobot/project-static/docs/additional-features/graphql.html +1389 -190
  615. nautobot/project-static/docs/additional-features/healthcheck.html +1389 -190
  616. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1393 -190
  617. nautobot/project-static/docs/additional-features/jobs.html +1677 -460
  618. nautobot/project-static/docs/additional-features/napalm.html +1389 -190
  619. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1389 -190
  620. nautobot/project-static/docs/additional-features/template-filters.html +1389 -190
  621. nautobot/project-static/docs/administration/celery-queues.html +1389 -190
  622. nautobot/project-static/docs/administration/nautobot-server.html +1553 -375
  623. nautobot/project-static/docs/administration/nautobot-shell.html +1395 -196
  624. nautobot/project-static/docs/administration/permissions.html +1389 -190
  625. nautobot/project-static/docs/administration/replicating-nautobot.html +1387 -207
  626. nautobot/project-static/docs/apps/index.html +1389 -190
  627. nautobot/project-static/docs/apps/nautobot-apps.html +1387 -175
  628. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js +29 -0
  629. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js.map +8 -0
  630. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js → search.208ed371.min.js} +9 -15
  631. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js.map → search.208ed371.min.js.map} +4 -4
  632. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css +1 -0
  633. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css.map +1 -0
  634. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css +1 -0
  635. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css.map +1 -0
  636. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1775 -590
  637. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1389 -190
  638. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3588 -1922
  639. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1461 -262
  640. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1401 -170
  641. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1396 -191
  642. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +2095 -894
  643. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2357 -1194
  644. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2258 -940
  645. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1389 -190
  646. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1400 -201
  647. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11068 -7861
  648. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2867 -2224
  649. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1389 -190
  650. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2641 -1573
  651. nautobot/project-static/docs/configuration/authentication/ldap.html +1389 -190
  652. nautobot/project-static/docs/configuration/authentication/remote.html +1389 -190
  653. nautobot/project-static/docs/configuration/authentication/sso.html +1389 -190
  654. nautobot/project-static/docs/configuration/index.html +1398 -199
  655. nautobot/project-static/docs/configuration/optional-settings.html +1418 -274
  656. nautobot/project-static/docs/configuration/required-settings.html +1419 -287
  657. nautobot/project-static/docs/core-functionality/circuits.html +1446 -247
  658. nautobot/project-static/docs/core-functionality/device-types.html +1448 -249
  659. nautobot/project-static/docs/core-functionality/devices.html +1452 -249
  660. nautobot/project-static/docs/core-functionality/ipam.html +1452 -253
  661. nautobot/project-static/docs/core-functionality/power.html +1448 -249
  662. nautobot/project-static/docs/core-functionality/secrets.html +1448 -249
  663. nautobot/project-static/docs/core-functionality/services.html +1448 -249
  664. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1448 -249
  665. nautobot/project-static/docs/core-functionality/tenancy.html +1448 -249
  666. nautobot/project-static/docs/core-functionality/virtualization.html +1452 -249
  667. nautobot/project-static/docs/core-functionality/vlans.html +1448 -249
  668. nautobot/project-static/docs/development/application-registry.html +1393 -214
  669. nautobot/project-static/docs/development/best-practices.html +1392 -192
  670. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1390 -191
  671. nautobot/project-static/docs/development/extending-models.html +1443 -257
  672. nautobot/project-static/docs/development/generic-views.html +1403 -174
  673. nautobot/project-static/docs/development/getting-started.html +1568 -262
  674. nautobot/project-static/docs/development/homepage.html +1389 -190
  675. nautobot/project-static/docs/development/index.html +1389 -190
  676. nautobot/project-static/docs/development/model-features.html +1389 -190
  677. nautobot/project-static/docs/development/natural-keys.html +1389 -190
  678. nautobot/project-static/docs/development/navigation-menu.html +1451 -330
  679. nautobot/project-static/docs/development/react-ui.html +4199 -0
  680. nautobot/project-static/docs/development/release-checklist.html +1392 -193
  681. nautobot/project-static/docs/development/role-internals.html +1402 -172
  682. nautobot/project-static/docs/development/style-guide.html +1399 -199
  683. nautobot/project-static/docs/development/templates.html +1391 -191
  684. nautobot/project-static/docs/development/testing.html +1389 -190
  685. nautobot/project-static/docs/development/user-preferences.html +1389 -190
  686. nautobot/project-static/docs/docker/index.html +1408 -206
  687. nautobot/project-static/docs/index.html +1397 -180
  688. nautobot/project-static/docs/installation/centos.html +1401 -170
  689. nautobot/project-static/docs/installation/external-authentication.html +1389 -190
  690. nautobot/project-static/docs/installation/http-server.html +1389 -190
  691. nautobot/project-static/docs/installation/index.html +1394 -191
  692. nautobot/project-static/docs/installation/migrating-from-netbox.html +1452 -305
  693. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1390 -191
  694. nautobot/project-static/docs/installation/nautobot.html +1390 -191
  695. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1389 -190
  696. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1401 -170
  697. nautobot/project-static/docs/installation/services.html +1389 -190
  698. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  699. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  700. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  701. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  702. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  703. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  704. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  705. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  706. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  707. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  708. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  709. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  710. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  711. nautobot/project-static/docs/installation/ubuntu.html +1401 -170
  712. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +4254 -1923
  713. nautobot/project-static/docs/installation/upgrading.html +1395 -192
  714. nautobot/project-static/docs/models/circuits/circuit.html +1427 -174
  715. nautobot/project-static/docs/models/circuits/circuittermination.html +1427 -174
  716. nautobot/project-static/docs/models/circuits/circuittype.html +1427 -174
  717. nautobot/project-static/docs/models/circuits/provider.html +1427 -174
  718. nautobot/project-static/docs/models/circuits/providernetwork.html +1427 -174
  719. nautobot/project-static/docs/models/dcim/cable.html +1458 -174
  720. nautobot/project-static/docs/models/dcim/consoleport.html +1427 -174
  721. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1427 -174
  722. nautobot/project-static/docs/models/dcim/consoleserverport.html +1427 -174
  723. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1427 -174
  724. nautobot/project-static/docs/models/dcim/device.html +1431 -174
  725. nautobot/project-static/docs/models/dcim/devicebay.html +1427 -174
  726. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1427 -174
  727. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1522 -177
  728. nautobot/project-static/docs/models/dcim/devicetype.html +1427 -174
  729. nautobot/project-static/docs/models/dcim/frontport.html +1427 -174
  730. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1427 -174
  731. nautobot/project-static/docs/models/dcim/interface.html +1427 -174
  732. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1427 -174
  733. nautobot/project-static/docs/models/dcim/inventoryitem.html +1427 -174
  734. nautobot/project-static/docs/models/dcim/location.html +1427 -174
  735. nautobot/project-static/docs/models/dcim/locationtype.html +1427 -174
  736. nautobot/project-static/docs/models/dcim/manufacturer.html +1427 -174
  737. nautobot/project-static/docs/models/dcim/platform.html +1427 -174
  738. nautobot/project-static/docs/models/dcim/powerfeed.html +1425 -172
  739. nautobot/project-static/docs/models/dcim/poweroutlet.html +1427 -174
  740. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1427 -174
  741. nautobot/project-static/docs/models/dcim/powerpanel.html +1425 -172
  742. nautobot/project-static/docs/models/dcim/powerport.html +1427 -174
  743. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1427 -174
  744. nautobot/project-static/docs/models/dcim/rack.html +1427 -174
  745. nautobot/project-static/docs/models/dcim/rackgroup.html +1427 -174
  746. nautobot/project-static/docs/models/dcim/rackreservation.html +1427 -174
  747. nautobot/project-static/docs/models/dcim/rearport.html +1427 -174
  748. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1427 -174
  749. nautobot/project-static/docs/models/dcim/region.html +1401 -170
  750. nautobot/project-static/docs/models/dcim/site.html +1401 -170
  751. nautobot/project-static/docs/models/dcim/virtualchassis.html +1425 -172
  752. nautobot/project-static/docs/models/extras/computedfield.html +1393 -194
  753. nautobot/project-static/docs/models/extras/configcontext.html +1465 -174
  754. nautobot/project-static/docs/models/extras/configcontextschema.html +1421 -168
  755. nautobot/project-static/docs/models/extras/customfield.html +1389 -190
  756. nautobot/project-static/docs/models/extras/customlink.html +1389 -190
  757. nautobot/project-static/docs/models/extras/dynamicgroup.html +1398 -199
  758. nautobot/project-static/docs/models/extras/exporttemplate.html +1389 -190
  759. nautobot/project-static/docs/models/extras/gitrepository.html +1393 -190
  760. nautobot/project-static/docs/models/extras/graphqlquery.html +1469 -171
  761. nautobot/project-static/docs/models/extras/imageattachment.html +1434 -181
  762. nautobot/project-static/docs/models/extras/job.html +1411 -157
  763. nautobot/project-static/docs/models/extras/jobbutton.html +1410 -207
  764. nautobot/project-static/docs/models/extras/jobhook.html +1397 -194
  765. nautobot/project-static/docs/models/extras/joblogentry.html +1408 -155
  766. nautobot/project-static/docs/models/extras/jobresult.html +1417 -159
  767. nautobot/project-static/docs/models/extras/note.html +1389 -190
  768. nautobot/project-static/docs/models/extras/relationship.html +1391 -192
  769. nautobot/project-static/docs/models/extras/role.html +1495 -198
  770. nautobot/project-static/docs/models/extras/secret.html +1492 -201
  771. nautobot/project-static/docs/models/extras/secretsgroup.html +1410 -157
  772. nautobot/project-static/docs/models/extras/status.html +1381 -221
  773. nautobot/project-static/docs/models/extras/tag.html +1389 -190
  774. nautobot/project-static/docs/models/extras/webhook.html +1389 -190
  775. nautobot/project-static/docs/models/ipam/ipaddress.html +1488 -200
  776. nautobot/project-static/docs/models/ipam/prefix.html +1410 -157
  777. nautobot/project-static/docs/models/ipam/rir.html +1410 -157
  778. nautobot/project-static/docs/models/ipam/routetarget.html +1410 -157
  779. nautobot/project-static/docs/models/ipam/service.html +1410 -157
  780. nautobot/project-static/docs/models/ipam/vlan.html +1410 -157
  781. nautobot/project-static/docs/models/ipam/vlangroup.html +1410 -157
  782. nautobot/project-static/docs/models/ipam/vrf.html +1410 -161
  783. nautobot/project-static/docs/models/tenancy/tenant.html +1412 -159
  784. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1412 -159
  785. nautobot/project-static/docs/models/users/objectpermission.html +1462 -171
  786. nautobot/project-static/docs/models/users/token.html +1410 -157
  787. nautobot/project-static/docs/models/virtualization/cluster.html +1410 -157
  788. nautobot/project-static/docs/models/virtualization/clustergroup.html +1410 -157
  789. nautobot/project-static/docs/models/virtualization/clustertype.html +1410 -157
  790. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1414 -157
  791. nautobot/project-static/docs/models/virtualization/vminterface.html +1410 -157
  792. nautobot/project-static/docs/objects.inv +0 -0
  793. nautobot/project-static/docs/plugins/development.html +1916 -646
  794. nautobot/project-static/docs/plugins/index.html +1389 -190
  795. nautobot/project-static/docs/plugins/porting-from-netbox.html +1389 -190
  796. nautobot/project-static/docs/release-notes/index.html +1389 -190
  797. nautobot/project-static/docs/release-notes/version-1.0.html +1389 -190
  798. nautobot/project-static/docs/release-notes/version-1.1.html +1389 -190
  799. nautobot/project-static/docs/release-notes/version-1.2.html +1389 -190
  800. nautobot/project-static/docs/release-notes/version-1.3.html +1389 -190
  801. nautobot/project-static/docs/release-notes/version-1.4.html +1389 -190
  802. nautobot/project-static/docs/release-notes/version-1.5.html +2016 -397
  803. nautobot/project-static/docs/release-notes/version-2.0.html +1935 -287
  804. nautobot/project-static/docs/requirements.txt +5 -4
  805. nautobot/project-static/docs/rest-api/authentication.html +1389 -190
  806. nautobot/project-static/docs/rest-api/filtering.html +1389 -190
  807. nautobot/project-static/docs/rest-api/overview.html +2002 -576
  808. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  809. nautobot/project-static/docs/search/search_index.json +1 -1
  810. nautobot/project-static/docs/sitemap.xml +197 -187
  811. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  812. nautobot/project-static/docs/user-guides/custom-fields.html +1390 -191
  813. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1392 -193
  814. nautobot/project-static/docs/user-guides/getting-started/index.html +1388 -189
  815. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1388 -189
  816. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1386 -187
  817. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1448 -249
  818. nautobot/project-static/docs/user-guides/getting-started/regions.html +1411 -212
  819. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1395 -196
  820. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1448 -249
  821. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1448 -249
  822. nautobot/project-static/docs/user-guides/git-data-source.html +1405 -206
  823. nautobot/project-static/docs/user-guides/graphql.html +1402 -203
  824. nautobot/project-static/docs/user-guides/relationships.html +1448 -249
  825. nautobot/project-static/docs/user-guides/s3-django-storage.html +1448 -249
  826. nautobot/project-static/js/forms.js +16 -9
  827. nautobot/project-static/js/theme.js +5 -0
  828. nautobot/tenancy/api/serializers.py +4 -34
  829. nautobot/tenancy/api/urls.py +1 -1
  830. nautobot/tenancy/filters/__init__.py +9 -7
  831. nautobot/tenancy/filters/mixins.py +3 -2
  832. nautobot/tenancy/forms.py +3 -36
  833. nautobot/tenancy/migrations/0001_initial.py +0 -1
  834. nautobot/tenancy/migrations/0002_auto_slug.py +0 -1
  835. nautobot/tenancy/migrations/0003_mptt_to_tree_queries.py +0 -1
  836. nautobot/tenancy/migrations/0004_change_tree_manager_on_tree_models.py +0 -1
  837. nautobot/tenancy/migrations/0005_rename_foreign_keys_and_related_names.py +0 -1
  838. nautobot/tenancy/migrations/0006_created_datetime.py +0 -1
  839. nautobot/tenancy/migrations/0007_remove_tenant_tenantgroup_slug.py +20 -0
  840. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  841. nautobot/tenancy/models.py +0 -30
  842. nautobot/tenancy/navigation.py +6 -39
  843. nautobot/tenancy/tables.py +4 -4
  844. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  845. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -1
  846. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  847. nautobot/tenancy/tests/test_api.py +1 -12
  848. nautobot/tenancy/tests/test_filters.py +20 -12
  849. nautobot/tenancy/tests/test_views.py +11 -29
  850. nautobot/tenancy/urls.py +10 -10
  851. nautobot/tenancy/views.py +0 -3
  852. nautobot/ui/.eslintignore +6 -0
  853. nautobot/ui/.gitignore +10 -0
  854. nautobot/ui/.prettierignore +9 -0
  855. nautobot/ui/.prettierrc +4 -0
  856. nautobot/ui/README.md +33 -0
  857. nautobot/ui/app_imports.js.j2 +7 -0
  858. nautobot/ui/craco.config.js +46 -0
  859. nautobot/ui/jsconfig-base.json +11 -0
  860. nautobot/ui/jsconfig.json +5 -0
  861. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  862. nautobot/ui/package-lock.json +21451 -0
  863. nautobot/ui/package.json +70 -0
  864. nautobot/ui/public/index.html +47 -0
  865. nautobot/ui/public/logo192.png +0 -0
  866. nautobot/ui/public/logo512.png +0 -0
  867. nautobot/ui/public/manifest.json +25 -0
  868. nautobot/ui/public/nautobot_logo.svg +131 -0
  869. nautobot/ui/public/robots.txt +3 -0
  870. nautobot/ui/src/App.js +71 -0
  871. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  872. nautobot/ui/src/components/AppTab.js +40 -0
  873. nautobot/ui/src/components/Apps.js +60 -0
  874. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  875. nautobot/ui/src/components/HomePanel.js +58 -0
  876. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  877. nautobot/ui/src/components/Layout.js +53 -0
  878. nautobot/ui/src/components/LoadingWidget.js +25 -0
  879. nautobot/ui/src/components/Navbar.js +116 -0
  880. nautobot/ui/src/components/NotificationPopover.js +27 -0
  881. nautobot/ui/src/components/ObjectListTable.js +209 -0
  882. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  883. nautobot/ui/src/components/RouterButton.js +10 -0
  884. nautobot/ui/src/components/RouterLink.js +10 -0
  885. nautobot/ui/src/components/SidebarNav.js +147 -0
  886. nautobot/ui/src/components/Table.js +48 -0
  887. nautobot/ui/src/components/TableItem.js +71 -0
  888. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  889. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  890. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  891. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  892. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  893. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  894. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  895. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  896. nautobot/ui/src/components/pagination.js +93 -0
  897. nautobot/ui/src/components/paginator.js +79 -0
  898. nautobot/ui/src/components/paginator_form.js +43 -0
  899. nautobot/ui/src/components/usePagination.js +57 -0
  900. nautobot/ui/src/constants/apiPath.js +10 -0
  901. nautobot/ui/src/constants/icons.js +15 -0
  902. nautobot/ui/src/constants/size.js +15 -0
  903. nautobot/ui/src/index.js +65 -0
  904. nautobot/ui/src/reportWebVitals.js +15 -0
  905. nautobot/ui/src/router.js +77 -0
  906. nautobot/ui/src/utils/api.js +131 -0
  907. nautobot/ui/src/utils/app-import.js +15 -0
  908. nautobot/ui/src/utils/color.js +15 -0
  909. nautobot/ui/src/utils/date.js +14 -0
  910. nautobot/ui/src/utils/index.js +15 -0
  911. nautobot/ui/src/utils/navigation.js +32 -0
  912. nautobot/ui/src/utils/session.js +64 -0
  913. nautobot/ui/src/utils/store.js +242 -0
  914. nautobot/ui/src/utils/string.js +6 -0
  915. nautobot/ui/src/utils/url.js +4 -0
  916. nautobot/ui/src/views/Home.js +138 -0
  917. nautobot/ui/src/views/InstalledApps.js +80 -0
  918. nautobot/ui/src/views/Login.js +48 -0
  919. nautobot/ui/src/views/Logout.js +20 -0
  920. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  921. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  922. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  923. nautobot/ui/src/views/generic/GenericView.js +142 -0
  924. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  925. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  926. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  927. nautobot/users/admin.py +1 -1
  928. nautobot/users/api/serializers.py +51 -61
  929. nautobot/users/api/urls.py +1 -1
  930. nautobot/users/api/views.py +53 -2
  931. nautobot/users/migrations/0001_initial.py +0 -1
  932. nautobot/users/migrations/0002_token_ordering_by_created.py +0 -1
  933. nautobot/users/migrations/0003_alter_user_options.py +0 -1
  934. nautobot/users/migrations/0004_alter_user_managers.py +0 -1
  935. nautobot/users/tests/test_api.py +109 -28
  936. nautobot/users/tests/test_filters.py +0 -4
  937. nautobot/users/tests/test_models.py +0 -1
  938. nautobot/users/views.py +0 -7
  939. nautobot/virtualization/api/serializers.py +18 -132
  940. nautobot/virtualization/api/urls.py +1 -1
  941. nautobot/virtualization/api/views.py +1 -22
  942. nautobot/virtualization/choices.py +0 -2
  943. nautobot/virtualization/filters.py +12 -7
  944. nautobot/virtualization/forms.py +21 -117
  945. nautobot/virtualization/migrations/0001_initial.py +0 -1
  946. nautobot/virtualization/migrations/0002_virtualmachine_local_context_schema.py +0 -1
  947. nautobot/virtualization/migrations/0003_vminterface_verbose_name.py +0 -1
  948. nautobot/virtualization/migrations/0004_auto_slug.py +0 -1
  949. nautobot/virtualization/migrations/0005_add_natural_indexing.py +0 -1
  950. nautobot/virtualization/migrations/0006_vminterface_status.py +0 -1
  951. nautobot/virtualization/migrations/0007_vminterface_status_data_migration.py +0 -1
  952. nautobot/virtualization/migrations/0008_vminterface_parent.py +0 -1
  953. nautobot/virtualization/migrations/0009_cluster_location.py +0 -1
  954. nautobot/virtualization/migrations/0010_vminterface_mac_address_data_migration.py +0 -1
  955. nautobot/virtualization/migrations/0011_alter_vminterface_mac_address.py +0 -1
  956. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -2
  957. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -12
  958. nautobot/virtualization/migrations/0014_rename_virtualmachine_roles.py +0 -1
  959. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -2
  960. nautobot/virtualization/migrations/0016_remove_site_foreign_key_from_cluster_class.py +0 -1
  961. nautobot/virtualization/migrations/0017_created_datetime.py +0 -1
  962. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -2
  963. nautobot/virtualization/migrations/0019_vminterface_ip_addresses_m2m.py +0 -1
  964. nautobot/virtualization/migrations/0020_remove_clustergroup_clustertype_slug.py +20 -0
  965. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  966. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  967. nautobot/virtualization/migrations/0023_ipam__namespaces.py +25 -0
  968. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  969. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  970. nautobot/virtualization/models.py +39 -131
  971. nautobot/virtualization/navigation.py +18 -99
  972. nautobot/virtualization/tables.py +4 -4
  973. nautobot/virtualization/templates/virtualization/virtualmachine.html +13 -2
  974. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  975. nautobot/virtualization/tests/test_api.py +42 -52
  976. nautobot/virtualization/tests/test_filters.py +98 -75
  977. nautobot/virtualization/tests/test_models.py +36 -13
  978. nautobot/virtualization/tests/test_views.py +68 -73
  979. nautobot/virtualization/urls.py +10 -10
  980. nautobot/virtualization/views.py +8 -14
  981. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +15 -22
  982. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +987 -834
  983. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  984. nautobot/circuits/api/nested_serializers.py +0 -69
  985. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  986. nautobot/dcim/api/nested_serializers.py +0 -356
  987. nautobot/dcim/templates/dcim/device_import.html +0 -5
  988. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  989. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  990. nautobot/extras/api/nested_serializers.py +0 -353
  991. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -42
  992. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -47
  993. nautobot/extras/reports.py +0 -60
  994. nautobot/extras/scripts.py +0 -72
  995. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  996. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  997. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  998. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  999. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  1000. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  1001. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  1002. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  1003. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  1004. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -19
  1005. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  1006. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  1007. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  1008. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  1009. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  1010. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  1011. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  1012. nautobot/ipam/api/nested_serializers.py +0 -143
  1013. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js +0 -29
  1014. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js.map +0 -8
  1015. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js +0 -18
  1016. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js.map +0 -8
  1017. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css +0 -1
  1018. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css.map +0 -1
  1019. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css +0 -1
  1020. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css.map +0 -1
  1021. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css +0 -1
  1022. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css.map +0 -1
  1023. nautobot/tenancy/api/nested_serializers.py +0 -31
  1024. nautobot/users/api/nested_serializers.py +0 -67
  1025. nautobot/virtualization/api/nested_serializers.py +0 -65
  1026. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  1027. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  1028. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  1029. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -81,7 +81,7 @@ from nautobot.extras.models import (
81
81
  Status,
82
82
  Tag,
83
83
  )
84
- from nautobot.ipam.models import VLAN, IPAddress
84
+ from nautobot.ipam.models import VLAN, IPAddress, Namespace, Prefix
85
85
  from nautobot.tenancy.models import Tenant
86
86
  from nautobot.users.models import ObjectPermission
87
87
 
@@ -94,15 +94,19 @@ def create_test_device(name):
94
94
  Convenience method for creating a Device (e.g. for component testing).
95
95
  """
96
96
  location_type, _ = LocationType.objects.get_or_create(name="Campus")
97
+ location_status = Status.objects.get_for_model(Location).first()
97
98
  location, _ = Location.objects.get_or_create(
98
- name="Test Location 1", slug="test-location-1", location_type=location_type
99
+ name="Test Location 1", slug="test-location-1", location_type=location_type, status=location_status
99
100
  )
100
- manufacturer, _ = Manufacturer.objects.get_or_create(name="Manufacturer 1", slug="manufacturer-1")
101
+ manufacturer, _ = Manufacturer.objects.get_or_create(name="Manufacturer 1")
101
102
  devicetype, _ = DeviceType.objects.get_or_create(model="Device Type 1", manufacturer=manufacturer)
102
103
  devicerole, _ = Role.objects.get_or_create(name="Device Role")
103
104
  device_ct = ContentType.objects.get_for_model(Device)
104
105
  devicerole.content_types.add(device_ct)
105
- device = Device.objects.create(name=name, location=location, device_type=devicetype, role=devicerole)
106
+ devicestatus = Status.objects.get_for_model(Device).first()
107
+ device = Device.objects.create(
108
+ name=name, location=location, device_type=devicetype, role=devicerole, status=devicestatus
109
+ )
106
110
 
107
111
  return device
108
112
 
@@ -163,13 +167,13 @@ class LocationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
163
167
  for lt in [lt1, lt2, lt3]:
164
168
  lt.validated_save()
165
169
 
166
- active = Status.objects.get(name="Active")
170
+ status = Status.objects.get_for_model(Location).first()
167
171
  tenant = Tenant.objects.first()
168
172
 
169
- loc1 = Location.objects.create(name="Root 1", location_type=lt1, status=active)
170
- loc2 = Location.objects.create(name="Root 2", location_type=lt1, status=active, tenant=tenant)
171
- loc3 = Location.objects.create(name="Intermediate 1", location_type=lt2, parent=loc2, status=active)
172
- loc4 = Location.objects.create(name="Leaf 1", location_type=lt3, parent=loc3, status=active, description="Hi!")
173
+ loc1 = Location.objects.create(name="Root 1", location_type=lt1, status=status)
174
+ loc2 = Location.objects.create(name="Root 2", location_type=lt1, status=status, tenant=tenant)
175
+ loc3 = Location.objects.create(name="Intermediate 1", location_type=lt2, parent=loc2, status=status)
176
+ loc4 = Location.objects.create(name="Leaf 1", location_type=lt3, parent=loc3, status=status, description="Hi!")
173
177
  for loc in [loc1, loc2, loc3, loc4]:
174
178
  loc.validated_save()
175
179
 
@@ -178,7 +182,7 @@ class LocationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
178
182
  "parent": None,
179
183
  "name": "Root 3",
180
184
  "slug": "root-3",
181
- "status": active.pk,
185
+ "status": status.pk,
182
186
  "tenant": tenant.pk,
183
187
  "facility": "Facility X",
184
188
  "asn": 65001,
@@ -197,9 +201,9 @@ class LocationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
197
201
 
198
202
  cls.csv_data = (
199
203
  "name,slug,location_type,parent,status,tenant,description",
200
- f'Root 3,root-3,"{lt1.name}",,active,,',
201
- f'Intermediate 2,intermediate-2,"{lt2.name}","{loc2.name}",active,"{tenant.name}",Hello world!',
202
- f'Leaf 2,leaf-2,"{lt3.name}","{loc3.name}",active,"{tenant.name}",',
204
+ f'Root 3,root-3,"{lt1.name}",,{status.name},,',
205
+ f'Intermediate 2,intermediate-2,"{lt2.name}",{loc2.natural_key_slug},{status.name},"{tenant.name}",Hello world!',
206
+ f'Leaf 2,leaf-2,"{lt3.name}",{loc3.natural_key_slug},{status.name},"{tenant.name}",',
203
207
  )
204
208
 
205
209
  cls.bulk_edit_data = {
@@ -207,7 +211,7 @@ class LocationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
207
211
  # Because we have a mix of root and non-root LocationTypes,
208
212
  # we can't bulk-edit the parent in this generic test
209
213
  "tenant": tenant.pk,
210
- "status": Status.objects.get(name="Planned").pk,
214
+ "status": Status.objects.get_for_model(Location).last().pk,
211
215
  "asn": 65009,
212
216
  "time_zone": pytz.timezone("US/Eastern"),
213
217
  }
@@ -237,10 +241,10 @@ class RackGroupTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
237
241
 
238
242
  cls.csv_data = (
239
243
  "location,name,slug,description",
240
- f"{location.name},Rack Group 4,rack-group-4,Fourth rack group",
241
- f"{location.name},Rack Group 5,rack-group-5,Fifth rack group",
242
- f"{location.name},Rack Group 6,rack-group-6,Sixth rack group",
243
- f"{location.name},Rack Group 7,,Seventh rack group",
244
+ f"{location.natural_key_slug},Rack Group 4,rack-group-4,Fourth rack group",
245
+ f"{location.natural_key_slug},Rack Group 5,rack-group-5,Fifth rack group",
246
+ f"{location.natural_key_slug},Rack Group 6,rack-group-6,Sixth rack group",
247
+ f"{location.natural_key_slug},Rack Group 7,,Seventh rack group",
244
248
  )
245
249
  cls.slug_test_object = "Rack Group 8"
246
250
  cls.slug_source = "name"
@@ -258,7 +262,8 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
258
262
 
259
263
  rack_group = RackGroup.objects.create(name="Rack Group 1", slug="rack-group-1", location=location)
260
264
 
261
- rack = Rack.objects.create(name="Rack 1", location=location, rack_group=rack_group)
265
+ rack_status = Status.objects.get_for_model(Rack).first()
266
+ rack = Rack.objects.create(name="Rack 1", location=location, rack_group=rack_group, status=rack_status)
262
267
 
263
268
  RackReservation.objects.create(rack=rack, user=user2, units=[1, 2, 3], description="Reservation 1")
264
269
  RackReservation.objects.create(rack=rack, user=user2, units=[4, 5, 6], description="Reservation 2")
@@ -274,10 +279,10 @@ class RackReservationTestCase(ViewTestCases.PrimaryObjectViewTestCase):
274
279
  }
275
280
 
276
281
  cls.csv_data = (
277
- "location,rack_group,rack,units,description",
278
- f'{location.name},Rack Group 1,Rack 1,"10,11,12",Reservation 1',
279
- f'{location.name},Rack Group 1,Rack 1,"13,14,15",Reservation 2',
280
- f'{location.name},Rack Group 1,Rack 1,"16,17,18",Reservation 3',
282
+ "rack,units,description",
283
+ f'{rack.natural_key_slug},"10,11,12",Reservation 1',
284
+ f"{rack.natural_key_slug},13,Reservation 2",
285
+ f'{rack.natural_key_slug},"16,17,18",Reservation 3',
281
286
  )
282
287
 
283
288
  cls.bulk_edit_data = {
@@ -309,10 +314,10 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
309
314
  rackroles = Role.objects.get_for_model(Rack)[:2]
310
315
 
311
316
  statuses = Status.objects.get_for_model(Rack)
312
- cls.status_active = statuses.get(slug="active")
317
+ cls.status = statuses[0]
313
318
 
314
319
  cable_statuses = Status.objects.get_for_model(Cable)
315
- cls.cable_connected = cable_statuses.get(slug="connected")
320
+ cls.cable_connected = cable_statuses.get(name="Connected")
316
321
 
317
322
  cls.custom_fields = (
318
323
  CustomField.objects.create(type=CustomFieldTypeChoices.TYPE_MULTISELECT, label="Rack Colors", default=[]),
@@ -328,19 +333,19 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
328
333
  Rack.objects.create(
329
334
  name="Rack 1",
330
335
  location=cls.locations[0],
331
- status=cls.status_active,
336
+ status=cls.status,
332
337
  _custom_field_data={"rack_colors": ["red"]},
333
338
  ),
334
339
  Rack.objects.create(
335
340
  name="Rack 2",
336
341
  location=cls.locations[0],
337
- status=cls.status_active,
342
+ status=cls.status,
338
343
  _custom_field_data={"rack_colors": ["green"]},
339
344
  ),
340
345
  Rack.objects.create(
341
346
  name="Rack 3",
342
347
  location=cls.locations[0],
343
- status=cls.status_active,
348
+ status=cls.status,
344
349
  _custom_field_data={"rack_colors": ["blue"]},
345
350
  ),
346
351
  )
@@ -350,8 +355,8 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
350
355
 
351
356
  cls.relationships = (
352
357
  Relationship(
353
- name="Backup Locations",
354
- slug="backup-locations",
358
+ label="Backup Locations",
359
+ key="backup_locations",
355
360
  type=RelationshipTypeChoices.TYPE_MANY_TO_MANY,
356
361
  source_type=ContentType.objects.get_for_model(Rack),
357
362
  source_label="Backup location(s)",
@@ -373,7 +378,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
373
378
  "location": cls.locations[1].pk,
374
379
  "rack_group": rackgroups[1].pk,
375
380
  "tenant": None,
376
- "status": statuses.get(slug="planned").pk,
381
+ "status": statuses[2].pk,
377
382
  "role": rackroles[1].pk,
378
383
  "serial": "VMWARE-XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX",
379
384
  "asset_tag": "ABCDEF",
@@ -392,16 +397,16 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
392
397
 
393
398
  cls.csv_data = (
394
399
  "location,rack_group,name,width,u_height,status",
395
- f"{cls.locations[0].name},,Rack 4,19,42,planned",
396
- f"{cls.locations[0].name},Rack Group 1,Rack 5,19,42,active",
397
- f"{cls.locations[1].name},Rack Group 2,Rack 6,19,42,reserved",
400
+ f"{cls.locations[0].natural_key_slug},,Rack 4,19,42,{statuses[0].name}",
401
+ f"{cls.locations[0].natural_key_slug},{rackgroups[0].natural_key_slug},Rack 5,19,42,{statuses[1].name}",
402
+ f"{cls.locations[1].natural_key_slug},{rackgroups[1].natural_key_slug},Rack 6,19,42,{statuses[2].name}",
398
403
  )
399
404
 
400
405
  cls.bulk_edit_data = {
401
406
  "location": cls.locations[1].pk,
402
407
  "rack_group": rackgroups[1].pk,
403
408
  "tenant": None,
404
- "status": statuses.get(slug="deprecated").pk,
409
+ "status": statuses[3].pk,
405
410
  "role": rackroles[1].pk,
406
411
  "serial": "654321-XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX",
407
412
  "type": RackTypeChoices.TYPE_4POST,
@@ -425,7 +430,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
425
430
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
426
431
  def test_powerports(self):
427
432
  # Create Devices
428
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
433
+ manufacturer = Manufacturer.objects.first()
429
434
 
430
435
  device_types = (
431
436
  DeviceType.objects.create(model="Device Type 1", slug="device-type-1", manufacturer=manufacturer),
@@ -433,7 +438,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
433
438
 
434
439
  device_roles = Role.objects.get_for_model(Device)[:1]
435
440
 
436
- platforms = (Platform.objects.create(name="Platform 1", slug="platform-1"),)
441
+ platforms = Platform.objects.all()[:1]
437
442
 
438
443
  devices = (
439
444
  Device.objects.create(
@@ -443,7 +448,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
443
448
  device_type=device_types[0],
444
449
  role=device_roles[0],
445
450
  platform=platforms[0],
446
- status=self.status_active,
451
+ status=self.status,
447
452
  ),
448
453
  Device.objects.create(
449
454
  name="Dev 1",
@@ -452,12 +457,13 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
452
457
  device_type=device_types[0],
453
458
  role=device_roles[0],
454
459
  platform=platforms[0],
455
- status=self.status_active,
460
+ status=self.status,
456
461
  ),
457
462
  )
458
463
 
459
464
  # Create Power Port for device
460
465
  powerport1 = PowerPort.objects.create(device=devices[0], name="Power Port 11")
466
+ pf_status = Status.objects.get_for_model(PowerFeed).first()
461
467
  powerfeed1 = PowerFeed.objects.create(
462
468
  power_panel=self.powerpanels[0],
463
469
  name="Power Feed 11",
@@ -465,6 +471,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
465
471
  voltage=240,
466
472
  amperage=20,
467
473
  rack=self.racks[0],
474
+ status=pf_status,
468
475
  )
469
476
  powerfeed2 = PowerFeed.objects.create(
470
477
  power_panel=self.powerpanels[0],
@@ -473,6 +480,7 @@ class RackTestCase(ViewTestCases.PrimaryObjectViewTestCase):
473
480
  voltage=240,
474
481
  amperage=20,
475
482
  rack=self.racks[0],
483
+ status=pf_status,
476
484
  )
477
485
 
478
486
  # Create power outlet to the power port
@@ -534,8 +542,6 @@ class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
534
542
 
535
543
  @classmethod
536
544
  def setUpTestData(cls):
537
- manufacturer = Manufacturer.objects.first()
538
-
539
545
  # FIXME(jathan): This has to be replaced with# `get_deletable_object` and
540
546
  # `get_deletable_object_pks` but this is a workaround just so all of these objects are
541
547
  # deletable for now.
@@ -544,18 +550,15 @@ class ManufacturerTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
544
550
 
545
551
  cls.form_data = {
546
552
  "name": "Manufacturer X",
547
- "slug": "manufacturer-x",
548
553
  "description": "A new manufacturer",
549
554
  }
550
555
  cls.csv_data = (
551
- "name,slug,description",
552
- "Manufacturer 4,manufacturer-4,Fourth manufacturer",
553
- "Manufacturer 5,manufacturer-5,Fifth manufacturer",
554
- "Manufacturer 6,manufacturer-6,Sixth manufacturer",
555
- "Manufacturer 7,,Seventh manufacturer",
556
+ "name,description",
557
+ "Manufacturer 4,Fourth manufacturer",
558
+ "Manufacturer 5,Fifth manufacturer",
559
+ "Manufacturer 6,Sixth manufacturer",
560
+ "Manufacturer 7,Seventh manufacturer",
556
561
  )
557
- cls.slug_test_object = manufacturer.name
558
- cls.slug_source = "name"
559
562
 
560
563
 
561
564
  # TODO: Change base class to PrimaryObjectViewTestCase
@@ -574,10 +577,7 @@ class DeviceTypeTestCase(
574
577
 
575
578
  @classmethod
576
579
  def setUpTestData(cls):
577
- manufacturers = (
578
- Manufacturer.objects.first(),
579
- Manufacturer.objects.last(),
580
- )
580
+ manufacturers = Manufacturer.objects.all()[:2]
581
581
 
582
582
  DeviceType.objects.create(model="Test Device Type 1", slug="device-type-1", manufacturer=manufacturers[0])
583
583
  DeviceType.objects.create(model="Test Device Type 2", slug="device-type-2", manufacturer=manufacturers[0])
@@ -631,8 +631,9 @@ class DeviceTypeTestCase(
631
631
  # TODO: Note use of "power-outlets.power_port" (not "power_port_template") and "front-ports.rear_port"
632
632
  # (not "rear_port_template"). This is intentional as we are testing for backwards compatibility with
633
633
  # the netbox/devicetype-library repository.
634
- IMPORT_DATA = """
635
- manufacturer: Generic
634
+ manufacturer = Manufacturer.objects.first()
635
+ IMPORT_DATA = f"""
636
+ manufacturer: {manufacturer.name}
636
637
  model: TEST-1000
637
638
  slug: test-1000
638
639
  u_height: 2
@@ -704,7 +705,7 @@ device-bays:
704
705
  """
705
706
 
706
707
  # Create the manufacturer
707
- Manufacturer.objects.create(name="Generic", slug="generic")
708
+ Manufacturer.objects.first()
708
709
 
709
710
  # Add all required permissions to the test user
710
711
  self.add_permissions(
@@ -830,7 +831,7 @@ class ConsolePortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestC
830
831
 
831
832
  @classmethod
832
833
  def setUpTestData(cls):
833
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
834
+ manufacturer = Manufacturer.objects.first()
834
835
  devicetypes = (
835
836
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1"),
836
837
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 2", slug="device-type-2"),
@@ -862,7 +863,7 @@ class ConsoleServerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateVie
862
863
 
863
864
  @classmethod
864
865
  def setUpTestData(cls):
865
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
866
+ manufacturer = Manufacturer.objects.first()
866
867
  devicetypes = (
867
868
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1"),
868
869
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 2", slug="device-type-2"),
@@ -894,7 +895,7 @@ class PowerPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas
894
895
 
895
896
  @classmethod
896
897
  def setUpTestData(cls):
897
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
898
+ manufacturer = Manufacturer.objects.first()
898
899
  devicetypes = (
899
900
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1"),
900
901
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 2", slug="device-type-2"),
@@ -932,7 +933,7 @@ class PowerOutletTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestC
932
933
 
933
934
  @classmethod
934
935
  def setUpTestData(cls):
935
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
936
+ manufacturer = Manufacturer.objects.first()
936
937
  devicetype = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1")
937
938
 
938
939
  PowerOutletTemplate.objects.create(device_type=devicetype, name="Power Outlet Template 1")
@@ -968,7 +969,7 @@ class InterfaceTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas
968
969
 
969
970
  @classmethod
970
971
  def setUpTestData(cls):
971
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
972
+ manufacturer = Manufacturer.objects.first()
972
973
  devicetypes = (
973
974
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1"),
974
975
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 2", slug="device-type-2"),
@@ -1005,7 +1006,7 @@ class FrontPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas
1005
1006
 
1006
1007
  @classmethod
1007
1008
  def setUpTestData(cls):
1008
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
1009
+ manufacturer = Manufacturer.objects.first()
1009
1010
  devicetype = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1")
1010
1011
 
1011
1012
  rearports = (
@@ -1061,7 +1062,7 @@ class RearPortTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCase
1061
1062
 
1062
1063
  @classmethod
1063
1064
  def setUpTestData(cls):
1064
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
1065
+ manufacturer = Manufacturer.objects.first()
1065
1066
  devicetypes = (
1066
1067
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1"),
1067
1068
  DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 2", slug="device-type-2"),
@@ -1095,7 +1096,7 @@ class DeviceBayTemplateTestCase(ViewTestCases.DeviceComponentTemplateViewTestCas
1095
1096
 
1096
1097
  @classmethod
1097
1098
  def setUpTestData(cls):
1098
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
1099
+ manufacturer = Manufacturer.objects.first()
1099
1100
  devicetypes = (
1100
1101
  DeviceType.objects.create(
1101
1102
  manufacturer=manufacturer,
@@ -1136,11 +1137,9 @@ class PlatformTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
1136
1137
  @classmethod
1137
1138
  def setUpTestData(cls):
1138
1139
  manufacturer = Manufacturer.objects.first()
1139
- platform = Platform.objects.first()
1140
1140
 
1141
1141
  cls.form_data = {
1142
1142
  "name": "Platform X",
1143
- "slug": "platform-x",
1144
1143
  "manufacturer": manufacturer.pk,
1145
1144
  "napalm_driver": "junos",
1146
1145
  "napalm_args": None,
@@ -1148,16 +1147,13 @@ class PlatformTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
1148
1147
  }
1149
1148
 
1150
1149
  cls.csv_data = (
1151
- "name,slug,description",
1152
- "Platform 4,platform-4,Fourth platform",
1153
- "Platform 5,platform-5,Fifth platform",
1154
- "Platform 6,platform-6,Sixth platform",
1155
- "Platform 7,,Seventh platform",
1150
+ "name,description",
1151
+ "Platform 4,Fourth platform",
1152
+ "Platform 5,Fifth platform",
1153
+ "Platform 6,Sixth platform",
1154
+ "Platform 7,Seventh platform",
1156
1155
  )
1157
1156
 
1158
- cls.slug_test_object = platform.name
1159
- cls.slug_source = "name"
1160
-
1161
1157
 
1162
1158
  class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1163
1159
  model = Device
@@ -1168,12 +1164,13 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1168
1164
 
1169
1165
  rack_group = RackGroup.objects.create(location=locations[0], name="Rack Group 1", slug="rack-group-1")
1170
1166
 
1167
+ rack_status = Status.objects.get_for_model(Rack).first()
1171
1168
  racks = (
1172
- Rack.objects.create(name="Rack 1", location=locations[0], rack_group=rack_group),
1173
- Rack.objects.create(name="Rack 2", location=locations[1]),
1169
+ Rack.objects.create(name="Rack 1", location=locations[0], rack_group=rack_group, status=rack_status),
1170
+ Rack.objects.create(name="Rack 2", location=locations[1], status=rack_status),
1174
1171
  )
1175
1172
 
1176
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
1173
+ manufacturer = Manufacturer.objects.first()
1177
1174
 
1178
1175
  devicetypes = (
1179
1176
  DeviceType.objects.create(model="Device Type 1", slug="device-type-1", manufacturer=manufacturer),
@@ -1182,18 +1179,18 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1182
1179
 
1183
1180
  deviceroles = Role.objects.get_for_model(Device)[:2]
1184
1181
 
1185
- platforms = (
1186
- Platform.objects.create(name="Platform 1", slug="platform-1"),
1187
- Platform.objects.create(name="Platform 2", slug="platform-2"),
1188
- )
1182
+ platforms = Platform.objects.all()[:2]
1183
+ for platform in platforms:
1184
+ platform.manufacturer = manufacturer
1185
+ platform.save()
1189
1186
 
1190
1187
  secrets_groups = (
1191
- SecretsGroup.objects.create(name="Secrets Group 1", slug="secrets-group-1"),
1192
- SecretsGroup.objects.create(name="Secrets Group 2", slug="secrets-group-2"),
1188
+ SecretsGroup.objects.create(name="Secrets Group 1"),
1189
+ SecretsGroup.objects.create(name="Secrets Group 2"),
1193
1190
  )
1194
1191
 
1195
1192
  statuses = Status.objects.get_for_model(Device)
1196
- status_active = statuses.get(slug="active")
1193
+ status_active = statuses[0]
1197
1194
 
1198
1195
  cls.custom_fields = (
1199
1196
  CustomField.objects.create(type=CustomFieldTypeChoices.TYPE_INTEGER, label="Crash Counter", default=0),
@@ -1234,10 +1231,12 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1234
1231
  ),
1235
1232
  )
1236
1233
 
1234
+ device_bay = DeviceBay.objects.create(device=devices[0], name="Device Bay 1")
1235
+
1237
1236
  cls.relationships = (
1238
1237
  Relationship(
1239
- name="BGP Router-ID",
1240
- slug="router-id",
1238
+ label="BGP Router-ID",
1239
+ key="router_id",
1241
1240
  type=RelationshipTypeChoices.TYPE_ONE_TO_ONE,
1242
1241
  source_type=ContentType.objects.get_for_model(Device),
1243
1242
  source_label="BGP Router ID",
@@ -1248,10 +1247,16 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1248
1247
  for relationship in cls.relationships:
1249
1248
  relationship.validated_save()
1250
1249
 
1250
+ cls.ipaddr_status = Status.objects.get_for_model(IPAddress).first()
1251
+ cls.prefix_status = Status.objects.get_for_model(Prefix).first()
1252
+ namespace = Namespace.objects.first()
1253
+ Prefix.objects.create(prefix="1.1.1.1/24", namespace=namespace, status=cls.prefix_status)
1254
+ Prefix.objects.create(prefix="2.2.2.2/24", namespace=namespace, status=cls.prefix_status)
1255
+ Prefix.objects.create(prefix="3.3.3.3/24", namespace=namespace, status=cls.prefix_status)
1251
1256
  ipaddresses = (
1252
- IPAddress.objects.create(address="1.1.1.1/32"),
1253
- IPAddress.objects.create(address="2.2.2.2/32"),
1254
- IPAddress.objects.create(address="3.3.3.3/32"),
1257
+ IPAddress.objects.create(address="1.1.1.1/32", namespace=namespace, status=cls.ipaddr_status),
1258
+ IPAddress.objects.create(address="2.2.2.2/32", namespace=namespace, status=cls.ipaddr_status),
1259
+ IPAddress.objects.create(address="3.3.3.3/32", namespace=namespace, status=cls.ipaddr_status),
1255
1260
  )
1256
1261
 
1257
1262
  for device, ipaddress in zip(devices, ipaddresses):
@@ -1271,7 +1276,7 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1271
1276
  "rack": racks[1].pk,
1272
1277
  "position": 1,
1273
1278
  "face": DeviceFaceChoices.FACE_FRONT,
1274
- "status": statuses.get(slug="planned").pk,
1279
+ "status": statuses[1].pk,
1275
1280
  "primary_ip4": None,
1276
1281
  "primary_ip6": None,
1277
1282
  "cluster": None,
@@ -1287,10 +1292,11 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1287
1292
  }
1288
1293
 
1289
1294
  cls.csv_data = (
1290
- "role,manufacturer,device_type,status,name,location,rack_group,rack,position,face,secrets_group",
1291
- f"{deviceroles[0].name},Manufacturer 1,Device Type 1,active,Device 4,{locations[0].name},Rack Group 1,Rack 1,10,front,",
1292
- f"{deviceroles[0].name},Manufacturer 1,Device Type 1,active,Device 5,{locations[0].name},Rack Group 1,Rack 1,20,front,",
1293
- f"{deviceroles[0].name},Manufacturer 1,Device Type 1,active,Device 6,{locations[0].name},Rack Group 1,Rack 1,30,front,Secrets Group 2",
1295
+ "role,device_type,status,name,location,rack,position,face,secrets_group,parent_bay",
1296
+ f"{deviceroles[0].name},{devicetypes[0].natural_key_slug},{statuses[0].name},Device 4,{locations[0].name},{racks[0].natural_key_slug},10,front,",
1297
+ f"{deviceroles[0].name},{devicetypes[0].natural_key_slug},{statuses[0].name},Device 5,{locations[0].name},{racks[0].natural_key_slug},20,front,",
1298
+ f"{deviceroles[0].name},{devicetypes[0].natural_key_slug},{statuses[0].name},Device 6,{locations[0].name},{racks[0].natural_key_slug},30,front,Secrets Group 2",
1299
+ f"{deviceroles[1].name},{devicetypes[1].natural_key_slug},{statuses[0].name},Child Device,{locations[0].name},,,,,{device_bay.natural_key_slug}",
1294
1300
  )
1295
1301
 
1296
1302
  cls.bulk_edit_data = {
@@ -1299,7 +1305,7 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1299
1305
  "tenant": None,
1300
1306
  "platform": platforms[1].pk,
1301
1307
  "serial": "VMWARE-XX XX XX XX XX XX XX XX-XX XX XX XX XX XX XX XX",
1302
- "status": statuses.get(slug="decommissioning").pk,
1308
+ "status": statuses[2].pk,
1303
1309
  "location": locations[1].pk,
1304
1310
  "rack": racks[1].pk,
1305
1311
  "position": None,
@@ -1355,9 +1361,10 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1355
1361
  def test_device_interfaces(self):
1356
1362
  device = Device.objects.first()
1357
1363
 
1358
- Interface.objects.create(device=device, name="Interface 1")
1359
- Interface.objects.create(device=device, name="Interface 2")
1360
- Interface.objects.create(device=device, name="Interface 3")
1364
+ intf_status = Status.objects.get_for_model(Interface).first()
1365
+ Interface.objects.create(device=device, name="Interface 1", status=intf_status)
1366
+ Interface.objects.create(device=device, name="Interface 2", status=intf_status)
1367
+ Interface.objects.create(device=device, name="Interface 3", status=intf_status)
1361
1368
 
1362
1369
  url = reverse("dcim:device_interfaces", kwargs={"pk": device.pk})
1363
1370
  self.assertHttpStatus(self.client.get(url), 200)
@@ -1408,7 +1415,7 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1408
1415
  def test_device_devicebays(self):
1409
1416
  device = Device.objects.first()
1410
1417
 
1411
- DeviceBay.objects.create(device=device, name="Device Bay 1")
1418
+ # Device Bay 1 was already created in setUpTestData()
1412
1419
  DeviceBay.objects.create(device=device, name="Device Bay 2")
1413
1420
  DeviceBay.objects.create(device=device, name="Device Bay 3")
1414
1421
 
@@ -1433,14 +1440,16 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
1433
1440
 
1434
1441
  # Create an interface and assign an IP to it.
1435
1442
  device = Device.objects.first()
1436
- interface = Interface.objects.create(device=device, name="Interface 1")
1437
- ip_address = IPAddress.objects.create(address="1.2.3.4/32")
1443
+ intf_status = Status.objects.get_for_model(Interface).first()
1444
+ interface = Interface.objects.create(device=device, name="Interface 1", status=intf_status)
1445
+ namespace = Namespace.objects.first()
1446
+ Prefix.objects.create(prefix="1.2.3.0/24", namespace=namespace, status=self.prefix_status)
1447
+ ip_address = IPAddress.objects.create(address="1.2.3.4/32", namespace=namespace, status=self.ipaddr_status)
1438
1448
  interface.ip_addresses.add(ip_address)
1439
1449
 
1440
1450
  # Dupe the form data and populated primary_ip4 w/ ip_address
1441
1451
  form_data = self.form_data.copy()
1442
1452
  form_data["primary_ip4"] = ip_address.pk
1443
-
1444
1453
  # Assert that update succeeds.
1445
1454
  request = {
1446
1455
  "path": self._get_url("edit", device),
@@ -1539,9 +1548,9 @@ class ConsolePortTestCase(ViewTestCases.DeviceComponentViewTestCase):
1539
1548
 
1540
1549
  cls.csv_data = (
1541
1550
  "device,name",
1542
- "Device 1,Console Port 4",
1543
- "Device 1,Console Port 5",
1544
- "Device 1,Console Port 6",
1551
+ f"{device.natural_key_slug},Console Port 4",
1552
+ f"{device.natural_key_slug},Console Port 5",
1553
+ f"{device.natural_key_slug},Console Port 6",
1545
1554
  )
1546
1555
 
1547
1556
 
@@ -1585,9 +1594,9 @@ class ConsoleServerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
1585
1594
 
1586
1595
  cls.csv_data = (
1587
1596
  "device,name",
1588
- "Device 1,Console Server Port 4",
1589
- "Device 1,Console Server Port 5",
1590
- "Device 1,Console Server Port 6",
1597
+ f"{device.natural_key_slug},Console Server Port 4",
1598
+ f"{device.natural_key_slug},Console Server Port 5",
1599
+ f"{device.natural_key_slug},Console Server Port 6",
1591
1600
  )
1592
1601
 
1593
1602
 
@@ -1636,9 +1645,9 @@ class PowerPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
1636
1645
 
1637
1646
  cls.csv_data = (
1638
1647
  "device,name",
1639
- "Device 1,Power Port 4",
1640
- "Device 1,Power Port 5",
1641
- "Device 1,Power Port 6",
1648
+ f"{device.natural_key_slug},Power Port 4",
1649
+ f"{device.natural_key_slug},Power Port 5",
1650
+ f"{device.natural_key_slug},Power Port 6",
1642
1651
  )
1643
1652
 
1644
1653
 
@@ -1701,9 +1710,9 @@ class PowerOutletTestCase(ViewTestCases.DeviceComponentViewTestCase):
1701
1710
 
1702
1711
  cls.csv_data = (
1703
1712
  "device,name",
1704
- "Device 1,Power Outlet 4",
1705
- "Device 1,Power Outlet 5",
1706
- "Device 1,Power Outlet 6",
1713
+ f"{device.natural_key_slug},Power Outlet 4",
1714
+ f"{device.natural_key_slug},Power Outlet 5",
1715
+ f"{device.natural_key_slug},Power Outlet 6",
1707
1716
  )
1708
1717
 
1709
1718
 
@@ -1715,24 +1724,29 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
1715
1724
  device = create_test_device("Device 1")
1716
1725
 
1717
1726
  statuses = Status.objects.get_for_model(Interface)
1718
- status_active = statuses.get(slug="active")
1727
+ status_active = statuses[0]
1719
1728
 
1720
1729
  interfaces = (
1721
- Interface.objects.create(device=device, name="Interface 1"),
1722
- Interface.objects.create(device=device, name="Interface 2"),
1723
- Interface.objects.create(device=device, name="Interface 3"),
1724
- Interface.objects.create(device=device, name="LAG", type=InterfaceTypeChoices.TYPE_LAG),
1725
- Interface.objects.create(device=device, name="BRIDGE", type=InterfaceTypeChoices.TYPE_BRIDGE),
1730
+ Interface.objects.create(device=device, name="Interface 1", status=status_active),
1731
+ Interface.objects.create(device=device, name="Interface 2", status=status_active),
1732
+ Interface.objects.create(device=device, name="Interface 3", status=status_active),
1733
+ Interface.objects.create(
1734
+ device=device, name="LAG", status=status_active, type=InterfaceTypeChoices.TYPE_LAG
1735
+ ),
1736
+ Interface.objects.create(
1737
+ device=device, name="BRIDGE", status=status_active, type=InterfaceTypeChoices.TYPE_BRIDGE
1738
+ ),
1726
1739
  )
1727
1740
  # Required by ViewTestCases.DeviceComponentViewTestCase.test_bulk_rename
1728
1741
  cls.selected_objects = interfaces
1729
1742
  cls.selected_objects_parent_name = device.name
1730
1743
 
1744
+ vlan_status = Status.objects.get_for_model(VLAN).first()
1731
1745
  vlans = (
1732
- VLAN.objects.create(vid=1, name="VLAN1", location=device.location),
1733
- VLAN.objects.create(vid=101, name="VLAN101", location=device.location),
1734
- VLAN.objects.create(vid=102, name="VLAN102", location=device.location),
1735
- VLAN.objects.create(vid=103, name="VLAN103", location=device.location),
1746
+ VLAN.objects.create(vid=1, name="VLAN1", location=device.location, status=vlan_status),
1747
+ VLAN.objects.create(vid=101, name="VLAN101", location=device.location, status=vlan_status),
1748
+ VLAN.objects.create(vid=102, name="VLAN102", location=device.location, status=vlan_status),
1749
+ VLAN.objects.create(vid=103, name="VLAN103", location=device.location, status=vlan_status),
1736
1750
  )
1737
1751
 
1738
1752
  cls.form_data = {
@@ -1801,9 +1815,9 @@ class InterfaceTestCase(ViewTestCases.DeviceComponentViewTestCase):
1801
1815
 
1802
1816
  cls.csv_data = (
1803
1817
  "device,name,type,status",
1804
- "Device 1,Interface 4,1000base-t,active",
1805
- "Device 1,Interface 5,1000base-t,active",
1806
- "Device 1,Interface 6,1000base-t,active",
1818
+ f"{device.natural_key_slug},Interface 4,1000base-t,{statuses[0].name}",
1819
+ f"{device.natural_key_slug},Interface 5,1000base-t,{statuses[0].name}",
1820
+ f"{device.natural_key_slug},Interface 6,1000base-t,{statuses[0].name}",
1807
1821
  )
1808
1822
 
1809
1823
 
@@ -1859,9 +1873,9 @@ class FrontPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
1859
1873
 
1860
1874
  cls.csv_data = (
1861
1875
  "device,name,type,rear_port,rear_port_position",
1862
- "Device 1,Front Port 4,8p8c,Rear Port 4,1",
1863
- "Device 1,Front Port 5,8p8c,Rear Port 5,1",
1864
- "Device 1,Front Port 6,8p8c,Rear Port 6,1",
1876
+ f"{device.natural_key_slug},Front Port 4,8p8c,{rearports[3].natural_key_slug},1",
1877
+ f"{device.natural_key_slug},Front Port 5,8p8c,{rearports[4].natural_key_slug},1",
1878
+ f"{device.natural_key_slug},Front Port 6,8p8c,{rearports[5].natural_key_slug},1",
1865
1879
  )
1866
1880
 
1867
1881
  @unittest.skip("No DeviceBulkAddFrontPortView exists at present")
@@ -1910,9 +1924,9 @@ class RearPortTestCase(ViewTestCases.DeviceComponentViewTestCase):
1910
1924
 
1911
1925
  cls.csv_data = (
1912
1926
  "device,name,type,positions",
1913
- "Device 1,Rear Port 4,8p8c,1",
1914
- "Device 1,Rear Port 5,8p8c,1",
1915
- "Device 1,Rear Port 6,8p8c,1",
1927
+ f"{device.natural_key_slug},Rear Port 4,8p8c,1",
1928
+ f"{device.natural_key_slug},Rear Port 5,8p8c,1",
1929
+ f"{device.natural_key_slug},Rear Port 6,8p8c,1",
1916
1930
  )
1917
1931
 
1918
1932
 
@@ -1955,9 +1969,9 @@ class DeviceBayTestCase(ViewTestCases.DeviceComponentViewTestCase):
1955
1969
 
1956
1970
  cls.csv_data = (
1957
1971
  "device,name",
1958
- "Device 1,Device Bay 4",
1959
- "Device 1,Device Bay 5",
1960
- "Device 1,Device Bay 6",
1972
+ f"{device.natural_key_slug},Device Bay 4",
1973
+ f"{device.natural_key_slug},Device Bay 5",
1974
+ f"{device.natural_key_slug},Device Bay 6",
1961
1975
  )
1962
1976
 
1963
1977
 
@@ -1967,7 +1981,7 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
1967
1981
  @classmethod
1968
1982
  def setUpTestData(cls):
1969
1983
  device = create_test_device("Device 1")
1970
- manufacturer, _ = Manufacturer.objects.get_or_create(name="Manufacturer 1", slug="manufacturer-1")
1984
+ manufacturer, _ = Manufacturer.objects.get_or_create(name="Manufacturer 1")
1971
1985
 
1972
1986
  inventory_items = (
1973
1987
  InventoryItem.objects.create(device=device, name="Inventory Item 1"),
@@ -2010,9 +2024,9 @@ class InventoryItemTestCase(ViewTestCases.DeviceComponentViewTestCase):
2010
2024
 
2011
2025
  cls.csv_data = (
2012
2026
  "device,name",
2013
- "Device 1,Inventory Item 4",
2014
- "Device 1,Inventory Item 5",
2015
- "Device 1,Inventory Item 6",
2027
+ f"{device.natural_key_slug},Inventory Item 4",
2028
+ f"{device.natural_key_slug},Inventory Item 5",
2029
+ f"{device.natural_key_slug},Inventory Item 6",
2016
2030
  )
2017
2031
 
2018
2032
 
@@ -2033,9 +2047,10 @@ class CableTestCase(
2033
2047
  @classmethod
2034
2048
  def setUpTestData(cls):
2035
2049
  location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
2036
- manufacturer = Manufacturer.objects.create(name="Manufacturer 1", slug="manufacturer-1")
2050
+ manufacturer = Manufacturer.objects.first()
2037
2051
  devicetype = DeviceType.objects.create(model="Device Type 1", manufacturer=manufacturer)
2038
2052
  devicerole = Role.objects.get_for_model(Device).first()
2053
+ devicestatus = Status.objects.get_for_model(Device).first()
2039
2054
 
2040
2055
  devices = (
2041
2056
  Device.objects.create(
@@ -2043,108 +2058,128 @@ class CableTestCase(
2043
2058
  location=location,
2044
2059
  device_type=devicetype,
2045
2060
  role=devicerole,
2061
+ status=devicestatus,
2046
2062
  ),
2047
2063
  Device.objects.create(
2048
2064
  name="Device 2",
2049
2065
  location=location,
2050
2066
  device_type=devicetype,
2051
2067
  role=devicerole,
2068
+ status=devicestatus,
2052
2069
  ),
2053
2070
  Device.objects.create(
2054
2071
  name="Device 3",
2055
2072
  location=location,
2056
2073
  device_type=devicetype,
2057
2074
  role=devicerole,
2075
+ status=devicestatus,
2058
2076
  ),
2059
2077
  Device.objects.create(
2060
2078
  name="Device 4",
2061
2079
  location=location,
2062
2080
  device_type=devicetype,
2063
2081
  role=devicerole,
2082
+ status=devicestatus,
2064
2083
  ),
2065
2084
  )
2066
2085
 
2086
+ interface_status = Status.objects.get_for_model(Interface).first()
2067
2087
  interfaces = (
2068
2088
  Interface.objects.create(
2069
2089
  device=devices[0],
2070
2090
  name="Interface 1",
2071
2091
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2092
+ status=interface_status,
2072
2093
  ),
2073
2094
  Interface.objects.create(
2074
2095
  device=devices[0],
2075
2096
  name="Interface 2",
2076
2097
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2098
+ status=interface_status,
2077
2099
  ),
2078
2100
  Interface.objects.create(
2079
2101
  device=devices[0],
2080
2102
  name="Interface 3",
2081
2103
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2104
+ status=interface_status,
2082
2105
  ),
2083
2106
  Interface.objects.create(
2084
2107
  device=devices[1],
2085
2108
  name="Interface 1",
2086
2109
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2110
+ status=interface_status,
2087
2111
  ),
2088
2112
  Interface.objects.create(
2089
2113
  device=devices[1],
2090
2114
  name="Interface 2",
2091
2115
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2116
+ status=interface_status,
2092
2117
  ),
2093
2118
  Interface.objects.create(
2094
2119
  device=devices[1],
2095
2120
  name="Interface 3",
2096
2121
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2122
+ status=interface_status,
2097
2123
  ),
2098
2124
  Interface.objects.create(
2099
2125
  device=devices[2],
2100
2126
  name="Interface 1",
2101
2127
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2128
+ status=interface_status,
2102
2129
  ),
2103
2130
  Interface.objects.create(
2104
2131
  device=devices[2],
2105
2132
  name="Interface 2",
2106
2133
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2134
+ status=interface_status,
2107
2135
  ),
2108
2136
  Interface.objects.create(
2109
2137
  device=devices[2],
2110
2138
  name="Interface 3",
2111
2139
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2140
+ status=interface_status,
2112
2141
  ),
2113
2142
  Interface.objects.create(
2114
2143
  device=devices[3],
2115
2144
  name="Interface 1",
2116
2145
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2146
+ status=interface_status,
2117
2147
  ),
2118
2148
  Interface.objects.create(
2119
2149
  device=devices[3],
2120
2150
  name="Interface 2",
2121
2151
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2152
+ status=interface_status,
2122
2153
  ),
2123
2154
  Interface.objects.create(
2124
2155
  device=devices[3],
2125
2156
  name="Interface 3",
2126
2157
  type=InterfaceTypeChoices.TYPE_1GE_FIXED,
2158
+ status=interface_status,
2127
2159
  ),
2128
2160
  )
2129
2161
 
2162
+ statuses = Status.objects.get_for_model(Cable)
2163
+
2130
2164
  Cable.objects.create(
2131
2165
  termination_a=interfaces[0],
2132
2166
  termination_b=interfaces[3],
2133
2167
  type=CableTypeChoices.TYPE_CAT6,
2168
+ status=statuses[0],
2134
2169
  )
2135
2170
  Cable.objects.create(
2136
2171
  termination_a=interfaces[1],
2137
2172
  termination_b=interfaces[4],
2138
2173
  type=CableTypeChoices.TYPE_CAT6,
2174
+ status=statuses[0],
2139
2175
  )
2140
2176
  Cable.objects.create(
2141
2177
  termination_a=interfaces[2],
2142
2178
  termination_b=interfaces[5],
2143
2179
  type=CableTypeChoices.TYPE_CAT6,
2180
+ status=statuses[0],
2144
2181
  )
2145
2182
 
2146
- statuses = Status.objects.get_for_model(Cable)
2147
-
2148
2183
  # interface_ct = ContentType.objects.get_for_model(Interface)
2149
2184
  cls.form_data = {
2150
2185
  # Changing terminations not supported when editing an existing Cable
@@ -2154,7 +2189,7 @@ class CableTestCase(
2154
2189
  # 'termination_b_type': interface_ct.pk,
2155
2190
  # 'termination_b_id': interfaces[3].pk,
2156
2191
  "type": CableTypeChoices.TYPE_CAT6,
2157
- "status": statuses.get(slug="planned").pk,
2192
+ "status": statuses[1].pk,
2158
2193
  "label": "Label",
2159
2194
  "color": "c0c0c0",
2160
2195
  "length": 100,
@@ -2163,15 +2198,15 @@ class CableTestCase(
2163
2198
  }
2164
2199
 
2165
2200
  cls.csv_data = (
2166
- "side_a_device,side_a_type,side_a_name,side_b_device,side_b_type,side_b_name,status",
2167
- "Device 3,dcim.interface,Interface 1,Device 4,dcim.interface,Interface 1,planned",
2168
- "Device 3,dcim.interface,Interface 2,Device 4,dcim.interface,Interface 2,planned",
2169
- "Device 3,dcim.interface,Interface 3,Device 4,dcim.interface,Interface 3,planned",
2201
+ "termination_a_id,termination_a_type,termination_b_id,termination_b_type,status",
2202
+ f"{interfaces[6].id},dcim.interface,{interfaces[9].id},dcim.interface,{statuses[0].name}",
2203
+ f"{interfaces[7].id},dcim.interface,{interfaces[10].id},dcim.interface,{statuses[0].name}",
2204
+ f"{interfaces[8].id},dcim.interface,{interfaces[11].id},dcim.interface,{statuses[0].name}",
2170
2205
  )
2171
2206
 
2172
2207
  cls.bulk_edit_data = {
2173
2208
  "type": CableTypeChoices.TYPE_CAT5E,
2174
- "status": statuses.get(slug="connected").pk,
2209
+ "status": statuses[0].pk,
2175
2210
  "label": "New label",
2176
2211
  "color": "00ff00",
2177
2212
  "length": 50,
@@ -2185,14 +2220,18 @@ class CableTestCase(
2185
2220
  location = Location.objects.first()
2186
2221
  device = Device.objects.first()
2187
2222
 
2223
+ interface_status = Status.objects.get_for_model(Interface).first()
2188
2224
  interfaces = [
2189
- Interface.objects.create(device=device, name="eth0"),
2190
- Interface.objects.create(device=device, name="eth1"),
2225
+ Interface.objects.create(device=device, name="eth0", status=interface_status),
2226
+ Interface.objects.create(device=device, name="eth1", status=interface_status),
2191
2227
  ]
2192
2228
 
2193
- provider = Provider.objects.create(name="Provider 1", slug="provider-1")
2194
- circuittype = CircuitType.objects.create(name="Circuit Type A", slug="circuit-type-a")
2195
- circuit = Circuit.objects.create(cid="Circuit 1", provider=provider, circuit_type=circuittype)
2229
+ provider = Provider.objects.first()
2230
+ circuittype = CircuitType.objects.first()
2231
+ circuit_status = Status.objects.get_for_model(Circuit).first()
2232
+ circuit = Circuit.objects.create(
2233
+ cid="Circuit 1", provider=provider, circuit_type=circuittype, status=circuit_status
2234
+ )
2196
2235
 
2197
2236
  circuit_terminations = [
2198
2237
  CircuitTermination.objects.create(
@@ -2203,10 +2242,10 @@ class CableTestCase(
2203
2242
  ),
2204
2243
  ]
2205
2244
 
2206
- connected = Status.objects.get(slug="connected")
2245
+ status = Status.objects.get_for_model(Cable).get(name="Connected")
2207
2246
  cables = [
2208
- Cable.objects.create(termination_a=circuit_terminations[0], termination_b=interfaces[0], status=connected),
2209
- Cable.objects.create(termination_a=circuit_terminations[1], termination_b=interfaces[1], status=connected),
2247
+ Cable.objects.create(termination_a=circuit_terminations[0], termination_b=interfaces[0], status=status),
2248
+ Cable.objects.create(termination_a=circuit_terminations[1], termination_b=interfaces[1], status=status),
2210
2249
  ]
2211
2250
 
2212
2251
  request = {
@@ -2277,31 +2316,11 @@ class ConsoleConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
2277
2316
  ConsolePort.objects.create(device=device_1, name="Console Port 2"),
2278
2317
  ConsolePort.objects.create(device=device_1, name="Console Port 3"),
2279
2318
  )
2319
+ status_connected = Status.objects.get(name="Connected")
2280
2320
 
2281
- Cable.objects.create(
2282
- termination_a=consoleports[0], termination_b=serverports[0], status=Status.objects.get(slug="connected")
2283
- )
2284
- Cable.objects.create(
2285
- termination_a=consoleports[1], termination_b=serverports[1], status=Status.objects.get(slug="connected")
2286
- )
2287
- Cable.objects.create(
2288
- termination_a=consoleports[2], termination_b=rearport, status=Status.objects.get(slug="connected")
2289
- )
2290
-
2291
- @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
2292
- def test_queryset_to_csv(self):
2293
- """This view has a custom queryset_to_csv() implementation."""
2294
- response = self.client.get(f"{self._get_url('list')}?export")
2295
- self.assertHttpStatus(response, 200)
2296
- self.assertEqual(response.get("Content-Type"), "text/csv")
2297
- self.assertEqual(
2298
- """\
2299
- device,console_port,console_server,port,reachable
2300
- Device 1,Console Port 1,Device 2,Console Server Port 1,True
2301
- Device 1,Console Port 2,Device 2,Console Server Port 2,True
2302
- Device 1,Console Port 3,,,False""",
2303
- response.content.decode(response.charset),
2304
- )
2321
+ Cable.objects.create(termination_a=consoleports[0], termination_b=serverports[0], status=status_connected)
2322
+ Cable.objects.create(termination_a=consoleports[1], termination_b=serverports[1], status=status_connected)
2323
+ Cable.objects.create(termination_a=consoleports[2], termination_b=rearport, status=status_connected)
2305
2324
 
2306
2325
 
2307
2326
  class PowerConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
@@ -2340,33 +2359,15 @@ class PowerConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
2340
2359
  )
2341
2360
 
2342
2361
  powerpanel = PowerPanel.objects.create(location=location, name="Power Panel 1")
2343
- powerfeed = PowerFeed.objects.create(power_panel=powerpanel, name="Power Feed 1")
2362
+ pf_status = Status.objects.get_for_model(PowerFeed).first()
2363
+ powerfeed = PowerFeed.objects.create(power_panel=powerpanel, name="Power Feed 1", status=pf_status)
2344
2364
 
2345
- Cable.objects.create(
2346
- termination_a=powerports[2], termination_b=powerfeed, status=Status.objects.get(slug="connected")
2347
- )
2348
- # Creating a PowerOutlet with a PowerPort via the ORM does *not* automatically cable the two together. Bug?
2349
- Cable.objects.create(
2350
- termination_a=powerports[0], termination_b=poweroutlets[0], status=Status.objects.get(slug="connected")
2351
- )
2352
- Cable.objects.create(
2353
- termination_a=powerports[1], termination_b=poweroutlets[1], status=Status.objects.get(slug="connected")
2354
- )
2365
+ status_connected = Status.objects.get(name="Connected")
2355
2366
 
2356
- @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
2357
- def test_queryset_to_csv(self):
2358
- """This view has a custom queryset_to_csv() implementation."""
2359
- response = self.client.get(f"{self._get_url('list')}?export")
2360
- self.assertHttpStatus(response, 200)
2361
- self.assertEqual(response.get("Content-Type"), "text/csv")
2362
- self.assertEqual(
2363
- """\
2364
- device,power_port,pdu,outlet,reachable
2365
- Device 1,Power Port 1,Device 2,Power Outlet 1,True
2366
- Device 1,Power Port 2,Device 2,Power Outlet 2,True
2367
- Device 1,Power Port 3,,Power Feed 1,True""",
2368
- response.content.decode(response.charset),
2369
- )
2367
+ Cable.objects.create(termination_a=powerports[2], termination_b=powerfeed, status=status_connected)
2368
+ # Creating a PowerOutlet with a PowerPort via the ORM does *not* automatically cable the two together. Bug?
2369
+ Cable.objects.create(termination_a=powerports[0], termination_b=poweroutlets[0], status=status_connected)
2370
+ Cable.objects.create(termination_a=powerports[1], termination_b=poweroutlets[1], status=status_connected)
2370
2371
 
2371
2372
 
2372
2373
  class InterfaceConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
@@ -2393,45 +2394,40 @@ class InterfaceConnectionsTestCase(ViewTestCases.ListObjectsViewTestCase):
2393
2394
  device_1 = create_test_device("Device 1")
2394
2395
  device_2 = create_test_device("Device 2")
2395
2396
 
2397
+ interface_status = Status.objects.get_for_model(Interface).first()
2396
2398
  cls.interfaces = (
2397
- Interface.objects.create(device=device_1, name="Interface 1", type=InterfaceTypeChoices.TYPE_1GE_SFP),
2398
- Interface.objects.create(device=device_1, name="Interface 2", type=InterfaceTypeChoices.TYPE_1GE_SFP),
2399
- Interface.objects.create(device=device_1, name="Interface 3", type=InterfaceTypeChoices.TYPE_1GE_SFP),
2399
+ Interface.objects.create(
2400
+ device=device_1, name="Interface 1", type=InterfaceTypeChoices.TYPE_1GE_SFP, status=interface_status
2401
+ ),
2402
+ Interface.objects.create(
2403
+ device=device_1, name="Interface 2", type=InterfaceTypeChoices.TYPE_1GE_SFP, status=interface_status
2404
+ ),
2405
+ Interface.objects.create(
2406
+ device=device_1, name="Interface 3", type=InterfaceTypeChoices.TYPE_1GE_SFP, status=interface_status
2407
+ ),
2400
2408
  )
2401
2409
 
2402
2410
  cls.device_2_interface = Interface.objects.create(
2403
- device=device_2, name="Interface 1", type=InterfaceTypeChoices.TYPE_1GE_SFP
2411
+ device=device_2, name="Interface 1", type=InterfaceTypeChoices.TYPE_1GE_SFP, status=interface_status
2404
2412
  )
2405
2413
  rearport = RearPort.objects.create(device=device_2, type=PortTypeChoices.TYPE_8P8C)
2406
2414
 
2407
- provider = Provider.objects.create(name="Provider 1", slug="provider-1")
2408
- circuittype = CircuitType.objects.create(name="Circuit Type A", slug="circuit-type-a")
2409
- circuit = Circuit.objects.create(cid="Circuit 1", provider=provider, circuit_type=circuittype)
2415
+ provider = Provider.objects.first()
2416
+ circuittype = CircuitType.objects.first()
2417
+ circuit_status = Status.objects.get_for_model(Circuit).first()
2418
+ circuit = Circuit.objects.create(
2419
+ cid="Circuit 1", provider=provider, circuit_type=circuittype, status=circuit_status
2420
+ )
2410
2421
  circuittermination = CircuitTermination.objects.create(
2411
2422
  circuit=circuit, term_side=CircuitTerminationSideChoices.SIDE_A, location=location
2412
2423
  )
2413
2424
 
2414
- connected = Status.objects.get(slug="connected")
2425
+ connected = Status.objects.get(name="Connected")
2415
2426
 
2416
2427
  Cable.objects.create(termination_a=cls.interfaces[0], termination_b=cls.device_2_interface, status=connected)
2417
2428
  Cable.objects.create(termination_a=cls.interfaces[1], termination_b=circuittermination, status=connected)
2418
2429
  Cable.objects.create(termination_a=cls.interfaces[2], termination_b=rearport, status=connected)
2419
2430
 
2420
- @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
2421
- def test_queryset_to_csv(self):
2422
- """This view has a custom queryset_to_csv() implementation."""
2423
- response = self.client.get(f"{self._get_url('list')}?export")
2424
- self.assertHttpStatus(response, 200)
2425
- self.assertEqual(response.get("Content-Type"), "text/csv")
2426
- self.assertEqual(
2427
- """\
2428
- device_a,interface_a,device_b,interface_b,reachable
2429
- Device 1,Interface 1,Device 2,Interface 1,True
2430
- Device 1,Interface 2,,,True
2431
- Device 1,Interface 3,,,False""",
2432
- response.content.decode(response.charset),
2433
- )
2434
-
2435
2431
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
2436
2432
  def test_list_objects_filtered(self):
2437
2433
  """Extend base ListObjectsViewTestCase to filter based on *both ends* of a connection."""
@@ -2477,14 +2473,16 @@ class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2477
2473
  @classmethod
2478
2474
  def setUpTestData(cls):
2479
2475
  location = Location.objects.filter(location_type=LocationType.objects.get(name="Campus")).first()
2480
- manufacturer = Manufacturer.objects.create(name="Manufacturer", slug="manufacturer-1")
2476
+ manufacturer = Manufacturer.objects.first()
2481
2477
  device_type = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1")
2482
2478
  device_role = Role.objects.get_for_model(Device).first()
2479
+ device_status = Status.objects.get_for_model(Device).first()
2483
2480
 
2484
2481
  cls.devices = [
2485
2482
  Device.objects.create(
2486
2483
  device_type=device_type,
2487
2484
  role=device_role,
2485
+ status=device_status,
2488
2486
  name=f"Device {num}",
2489
2487
  location=location,
2490
2488
  )
@@ -2517,9 +2515,9 @@ class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2517
2515
 
2518
2516
  cls.csv_data = (
2519
2517
  "name,domain,master",
2520
- "VC4,Domain 4,Device 10",
2521
- "VC5,Domain 5,Device 11",
2522
- "VC6,Domain 6,Device 12",
2518
+ f"VC4,Domain 4,{cls.devices[9].natural_key_slug}",
2519
+ f"VC5,Domain 5,{cls.devices[10].natural_key_slug}",
2520
+ f"VC6,Domain 6,{cls.devices[11].natural_key_slug}",
2523
2521
  )
2524
2522
 
2525
2523
  cls.bulk_edit_data = {
@@ -2533,8 +2531,9 @@ class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2533
2531
  """
2534
2532
  self.user.is_superuser = True
2535
2533
  self.user.save()
2536
- Interface.objects.create(device=self.devices[0], name="eth0")
2537
- Interface.objects.create(device=self.devices[0], name="eth1")
2534
+ interface_status = Status.objects.get_for_model(Interface).first()
2535
+ Interface.objects.create(device=self.devices[0], name="eth0", status=interface_status)
2536
+ Interface.objects.create(device=self.devices[0], name="eth1", status=interface_status)
2538
2537
  response = self.client.get(reverse("dcim:device_interfaces", kwargs={"pk": self.devices[0].pk}))
2539
2538
  self.assertIn("<th >Device</th>", str(response.content))
2540
2539
 
@@ -2545,8 +2544,9 @@ class VirtualChassisTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2545
2544
  """
2546
2545
  self.user.is_superuser = True
2547
2546
  self.user.save()
2548
- Interface.objects.create(device=self.devices[1], name="eth2")
2549
- Interface.objects.create(device=self.devices[1], name="eth3")
2547
+ interface_status = Status.objects.get_for_model(Interface).first()
2548
+ Interface.objects.create(device=self.devices[1], name="eth2", status=interface_status)
2549
+ Interface.objects.create(device=self.devices[1], name="eth3", status=interface_status)
2550
2550
  response = self.client.get(reverse("dcim:device_interfaces", kwargs={"pk": self.devices[1].pk}))
2551
2551
  self.assertNotIn("<th >Device</th>", str(response.content))
2552
2552
  # Sanity check:
@@ -2577,9 +2577,9 @@ class PowerPanelTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2577
2577
 
2578
2578
  cls.csv_data = (
2579
2579
  "location,rack_group,name",
2580
- f"{locations[0].name},Rack Group 1,Power Panel 4",
2581
- f"{locations[0].name},Rack Group 1,Power Panel 5",
2582
- f"{locations[0].name},Rack Group 1,Power Panel 6",
2580
+ f"{locations[0].natural_key_slug},{rackgroups[0].natural_key_slug},Power Panel 4",
2581
+ f"{locations[0].natural_key_slug},{rackgroups[0].natural_key_slug},Power Panel 5",
2582
+ f"{locations[0].natural_key_slug},{rackgroups[0].natural_key_slug},Power Panel 6",
2583
2583
  )
2584
2584
 
2585
2585
  cls.bulk_edit_data = {
@@ -2606,22 +2606,27 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2606
2606
  # Assign power panels generated to the class object for use later.
2607
2607
  cls.powerpanels = powerpanels
2608
2608
 
2609
+ rack_status = Status.objects.get_for_model(Rack).first()
2609
2610
  racks = (
2610
- Rack.objects.create(location=location, name="Rack 1"),
2611
- Rack.objects.create(location=location, name="Rack 2"),
2611
+ Rack.objects.create(location=location, name="Rack 1", status=rack_status),
2612
+ Rack.objects.create(location=location, name="Rack 2", status=rack_status),
2612
2613
  )
2613
2614
 
2614
- powerfeed_1 = PowerFeed.objects.create(name="Power Feed 1", power_panel=powerpanels[0], rack=racks[0])
2615
- powerfeed_2 = PowerFeed.objects.create(name="Power Feed 2", power_panel=powerpanels[0], rack=racks[0])
2616
- PowerFeed.objects.create(name="Power Feed 3", power_panel=powerpanels[0], rack=racks[0])
2615
+ statuses = Status.objects.get_for_model(PowerFeed)
2616
+ cls.status = statuses
2617
+ status_planned = statuses[0]
2618
+
2619
+ powerfeed_1 = PowerFeed.objects.create(
2620
+ name="Power Feed 1", power_panel=powerpanels[0], rack=racks[0], status=status_planned
2621
+ )
2622
+ powerfeed_2 = PowerFeed.objects.create(
2623
+ name="Power Feed 2", power_panel=powerpanels[0], rack=racks[0], status=status_planned
2624
+ )
2625
+ PowerFeed.objects.create(name="Power Feed 3", power_panel=powerpanels[0], rack=racks[0], status=status_planned)
2617
2626
 
2618
2627
  # Assign power feeds for the tests later
2619
2628
  cls.powerfeeds = (powerfeed_1, powerfeed_2)
2620
2629
 
2621
- statuses = Status.objects.get_for_model(PowerFeed)
2622
- cls.statuses = statuses
2623
- status_planned = statuses.get(slug="planned")
2624
-
2625
2630
  cls.form_data = {
2626
2631
  "name": "Power Feed X",
2627
2632
  "power_panel": powerpanels[1].pk,
@@ -2638,10 +2643,10 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2638
2643
  }
2639
2644
 
2640
2645
  cls.csv_data = (
2641
- "location,power_panel,name,voltage,amperage,max_utilization,status",
2642
- f"{location.name},Power Panel 1,Power Feed 4,120,20,80,active",
2643
- f"{location.name},Power Panel 1,Power Feed 5,120,20,80,failed",
2644
- f"{location.name},Power Panel 1,Power Feed 6,120,20,80,offline",
2646
+ "power_panel,name,voltage,amperage,max_utilization,status",
2647
+ f"{powerpanels[0].natural_key_slug},Power Feed 4,120,20,80,{statuses[0].name}",
2648
+ f"{powerpanels[0].natural_key_slug},Power Feed 5,120,20,80,{statuses[0].name}",
2649
+ f"{powerpanels[0].natural_key_slug},Power Feed 6,120,20,80,{statuses[1].name}",
2645
2650
  )
2646
2651
 
2647
2652
  cls.bulk_edit_data = {
@@ -2660,12 +2665,14 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2660
2665
  def test_power_feed_detail(self):
2661
2666
  self.add_permissions("dcim.view_powerfeed")
2662
2667
  # Setup base device info
2663
- manufacturer = Manufacturer.objects.create(name="Manufacturer", slug="manufacturer-1")
2668
+ manufacturer = Manufacturer.objects.first()
2664
2669
  device_type = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1")
2665
2670
  device_role = Role.objects.get_for_model(Device).first()
2671
+ device_status = Status.objects.get_for_model(Device).first()
2666
2672
  device = Device.objects.create(
2667
2673
  device_type=device_type,
2668
2674
  role=device_role,
2675
+ status=device_status,
2669
2676
  name="Device1",
2670
2677
  location=self.location,
2671
2678
  )
@@ -2675,10 +2682,10 @@ class PowerFeedTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2675
2682
  powerfeed = self.powerfeeds[0]
2676
2683
 
2677
2684
  Cable.objects.create(
2678
- termination_a=powerport, termination_b=powerfeed, status=Status.objects.get(slug="connected")
2685
+ termination_a=powerport, termination_b=powerfeed, status=Status.objects.get(name="Connected")
2679
2686
  )
2680
2687
 
2681
- url = reverse("dcim:powerfeed", kwargs=dict(pk=powerfeed.pk))
2688
+ url = reverse("dcim:powerfeed", kwargs={"pk": powerfeed.pk})
2682
2689
  self.assertHttpStatus(self.client.get(url), 200)
2683
2690
 
2684
2691
 
@@ -2690,9 +2697,9 @@ class PathTraceViewTestCase(ModelViewTestCase):
2690
2697
  (https://github.com/nautobot/nautobot/issues/1741)
2691
2698
  """
2692
2699
  self.add_permissions("dcim.view_cable", "dcim.view_rearport")
2693
- active = Status.objects.get(slug="active")
2694
- connected = Status.objects.get(slug="connected")
2695
- manufacturer = Manufacturer.objects.create(name="Test Manufacturer 1", slug="test-manufacturer-1")
2700
+ active = Status.objects.get(name="Active")
2701
+ connected = Status.objects.get(name="Connected")
2702
+ manufacturer = Manufacturer.objects.first()
2696
2703
  devicetype = DeviceType.objects.create(manufacturer=manufacturer, model="Device Type 1", slug="device-type-1")
2697
2704
  devicerole = Role.objects.get_for_model(Device).first()
2698
2705
  location_type = LocationType.objects.get(name="Campus")
@@ -2723,7 +2730,6 @@ class DeviceRedundancyGroupTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2723
2730
 
2724
2731
  cls.form_data = {
2725
2732
  "name": "DRG χ",
2726
- "slug": "region-chi",
2727
2733
  "failover_strategy": DeviceRedundancyGroupFailoverStrategyChoices.FAILOVER_ACTIVE_PASSIVE,
2728
2734
  "status": statuses[3].pk,
2729
2735
  "local_config_context_data": None,
@@ -2731,10 +2737,10 @@ class DeviceRedundancyGroupTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2731
2737
 
2732
2738
  cls.csv_data = (
2733
2739
  "name,failover_strategy,status",
2734
- "DRG δ,,active",
2735
- "DRG ε,,planned",
2736
- "DRG ζ,active-active,staging",
2737
- "DRG 7,active-passive,retired",
2740
+ f"DRG δ,,{statuses[0].name}",
2741
+ f"DRG ε,,{statuses[0].name}",
2742
+ f"DRG ζ,active-active,{statuses[1].name}",
2743
+ f"DRG 7,active-passive,{statuses[1].name}",
2738
2744
  )
2739
2745
 
2740
2746
  cls.bulk_edit_data = {