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
@@ -10,8 +10,14 @@
10
10
 
11
11
  <link rel="canonical" href="https://docs.nautobot.com/projects/core/en/stable/plugins/development.html">
12
12
 
13
+
14
+ <link rel="prev" href="index.html">
15
+
16
+
17
+ <link rel="next" href="porting-from-netbox.html">
18
+
13
19
  <link rel="icon" href="../assets/favicon.ico">
14
- <meta name="generator" content="mkdocs-1.4.2, mkdocs-material-8.5.10">
20
+ <meta name="generator" content="mkdocs-1.4.2, mkdocs-material-9.1.6">
15
21
 
16
22
 
17
23
 
@@ -19,11 +25,10 @@
19
25
 
20
26
 
21
27
 
22
- <link rel="stylesheet" href="../assets/stylesheets/main.975780f9.min.css">
28
+ <link rel="stylesheet" href="../assets/stylesheets/main.ded33207.min.css">
23
29
 
24
30
 
25
- <link rel="stylesheet" href="../assets/stylesheets/palette.2505c338.min.css">
26
-
31
+ <link rel="stylesheet" href="../assets/stylesheets/palette.a0c5b2b5.min.css">
27
32
 
28
33
 
29
34
 
@@ -86,7 +91,7 @@
86
91
 
87
92
 
88
93
 
89
- <header class="md-header md-header--lifted" data-md-component="header">
94
+ <header class="md-header md-header--shadow md-header--lifted" data-md-component="header">
90
95
  <nav class="md-header__inner md-grid" aria-label="Header">
91
96
  <a href="../index.html" title="Nautobot Documentation" class="md-header__button md-logo" aria-label="Nautobot Documentation" data-md-component="logo">
92
97
 
@@ -116,8 +121,6 @@
116
121
  <form class="md-header__option" data-md-component="palette">
117
122
 
118
123
 
119
-
120
-
121
124
  <input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
122
125
 
123
126
  <label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
@@ -126,8 +129,6 @@
126
129
 
127
130
 
128
131
 
129
-
130
-
131
132
  <input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_2">
132
133
 
133
134
  <label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
@@ -171,7 +172,7 @@
171
172
  <div class="md-search-result__meta">
172
173
  Initializing search
173
174
  </div>
174
- <ol class="md-search-result__list"></ol>
175
+ <ol class="md-search-result__list" role="presentation"></ol>
175
176
  </div>
176
177
  </div>
177
178
  </div>
@@ -183,7 +184,7 @@
183
184
  <a href="https://github.com/nautobot/nautobot" title="Go to repository" class="md-source" data-md-component="source">
184
185
  <div class="md-source__icon md-icon">
185
186
 
186
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
187
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
187
188
  </div>
188
189
  <div class="md-source__repository">
189
190
  GitHub
@@ -196,7 +197,7 @@
196
197
 
197
198
 
198
199
  <nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
199
- <div class="md-tabs__inner md-grid">
200
+ <div class="md-grid">
200
201
  <ul class="md-tabs__list">
201
202
 
202
203
 
@@ -351,7 +352,7 @@
351
352
  <a href="https://github.com/nautobot/nautobot" title="Go to repository" class="md-source" data-md-component="source">
352
353
  <div class="md-source__icon md-icon">
353
354
 
354
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
355
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
355
356
  </div>
356
357
  <div class="md-source__repository">
357
358
  GitHub
@@ -387,17 +388,18 @@
387
388
  <li class="md-nav__item md-nav__item--nested">
388
389
 
389
390
 
390
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2" type="checkbox" id="__nav_2" >
391
391
 
392
392
 
393
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
394
+
393
395
 
394
396
 
395
- <label class="md-nav__link" for="__nav_2">
397
+ <label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
396
398
  Documentation
397
399
  <span class="md-nav__icon md-icon"></span>
398
400
  </label>
399
401
 
400
- <nav class="md-nav" aria-label="Documentation" data-md-level="1">
402
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
401
403
  <label class="md-nav__title" for="__nav_2">
402
404
  <span class="md-nav__icon md-icon"></span>
403
405
  Documentation
@@ -413,17 +415,18 @@
413
415
  <li class="md-nav__item md-nav__item--nested">
414
416
 
415
417
 
416
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_1" type="checkbox" id="__nav_2_1" >
417
418
 
418
419
 
420
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1" >
419
421
 
420
422
 
421
- <label class="md-nav__link" for="__nav_2_1">
423
+
424
+ <label class="md-nav__link" for="__nav_2_1" id="__nav_2_1_label" tabindex="0">
422
425
  Installation
423
426
  <span class="md-nav__icon md-icon"></span>
424
427
  </label>
425
428
 
426
- <nav class="md-nav" aria-label="Installation" data-md-level="2">
429
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_1_label" aria-expanded="false">
427
430
  <label class="md-nav__title" for="__nav_2_1">
428
431
  <span class="md-nav__icon md-icon"></span>
429
432
  Installation
@@ -530,17 +533,18 @@
530
533
  <li class="md-nav__item md-nav__item--nested">
531
534
 
532
535
 
533
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_2" type="checkbox" id="__nav_2_2" >
534
536
 
535
537
 
538
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_2" >
539
+
536
540
 
537
541
 
538
- <label class="md-nav__link" for="__nav_2_2">
542
+ <label class="md-nav__link" for="__nav_2_2" id="__nav_2_2_label" tabindex="0">
539
543
  Migration
540
544
  <span class="md-nav__icon md-icon"></span>
541
545
  </label>
542
546
 
543
- <nav class="md-nav" aria-label="Migration" data-md-level="2">
547
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_2_label" aria-expanded="false">
544
548
  <label class="md-nav__title" for="__nav_2_2">
545
549
  <span class="md-nav__icon md-icon"></span>
546
550
  Migration
@@ -633,17 +637,18 @@
633
637
  <li class="md-nav__item md-nav__item--nested">
634
638
 
635
639
 
636
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_3" type="checkbox" id="__nav_2_3" >
637
640
 
638
641
 
642
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_3" >
639
643
 
640
644
 
641
- <label class="md-nav__link" for="__nav_2_3">
645
+
646
+ <label class="md-nav__link" for="__nav_2_3" id="__nav_2_3_label" tabindex="0">
642
647
  Configuration
643
648
  <span class="md-nav__icon md-icon"></span>
644
649
  </label>
645
650
 
646
- <nav class="md-nav" aria-label="Configuration" data-md-level="2">
651
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_3_label" aria-expanded="false">
647
652
  <label class="md-nav__title" for="__nav_2_3">
648
653
  <span class="md-nav__icon md-icon"></span>
649
654
  Configuration
@@ -708,17 +713,18 @@
708
713
  <li class="md-nav__item md-nav__item--nested">
709
714
 
710
715
 
711
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_4" type="checkbox" id="__nav_2_4" >
712
716
 
713
717
 
718
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_4" >
719
+
714
720
 
715
721
 
716
- <label class="md-nav__link" for="__nav_2_4">
722
+ <label class="md-nav__link" for="__nav_2_4" id="__nav_2_4_label" tabindex="0">
717
723
  External Authentication
718
724
  <span class="md-nav__icon md-icon"></span>
719
725
  </label>
720
726
 
721
- <nav class="md-nav" aria-label="External Authentication" data-md-level="2">
727
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
722
728
  <label class="md-nav__title" for="__nav_2_4">
723
729
  <span class="md-nav__icon md-icon"></span>
724
730
  External Authentication
@@ -783,17 +789,18 @@
783
789
  <li class="md-nav__item md-nav__item--nested">
784
790
 
785
791
 
786
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_5" type="checkbox" id="__nav_2_5" >
787
792
 
788
793
 
794
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_5" >
789
795
 
790
796
 
791
- <label class="md-nav__link" for="__nav_2_5">
797
+
798
+ <label class="md-nav__link" for="__nav_2_5" id="__nav_2_5_label" tabindex="0">
792
799
  Administration
793
800
  <span class="md-nav__icon md-icon"></span>
794
801
  </label>
795
802
 
796
- <nav class="md-nav" aria-label="Administration" data-md-level="2">
803
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_5_label" aria-expanded="false">
797
804
  <label class="md-nav__title" for="__nav_2_5">
798
805
  <span class="md-nav__icon md-icon"></span>
799
806
  Administration
@@ -886,17 +893,18 @@
886
893
  <li class="md-nav__item md-nav__item--nested">
887
894
 
888
895
 
889
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_6" type="checkbox" id="__nav_2_6" >
890
896
 
891
897
 
898
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_6" >
899
+
892
900
 
893
901
 
894
- <label class="md-nav__link" for="__nav_2_6">
902
+ <label class="md-nav__link" for="__nav_2_6" id="__nav_2_6_label" tabindex="0">
895
903
  User Guides
896
904
  <span class="md-nav__icon md-icon"></span>
897
905
  </label>
898
906
 
899
- <nav class="md-nav" aria-label="User Guides" data-md-level="2">
907
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_6_label" aria-expanded="false">
900
908
  <label class="md-nav__title" for="__nav_2_6">
901
909
  <span class="md-nav__icon md-icon"></span>
902
910
  User Guides
@@ -1143,20 +1151,1128 @@
1143
1151
  <li class="md-nav__item md-nav__item--nested">
1144
1152
 
1145
1153
 
1146
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_7" type="checkbox" id="__nav_2_7" >
1147
1154
 
1148
1155
 
1156
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_7" >
1157
+
1158
+
1159
+
1160
+ <label class="md-nav__link" for="__nav_2_7" id="__nav_2_7_label" tabindex="0">
1161
+ Core Functionality
1162
+ <span class="md-nav__icon md-icon"></span>
1163
+ </label>
1164
+
1165
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_7_label" aria-expanded="false">
1166
+ <label class="md-nav__title" for="__nav_2_7">
1167
+ <span class="md-nav__icon md-icon"></span>
1168
+ Core Functionality
1169
+ </label>
1170
+ <ul class="md-nav__list" data-md-scrollfix>
1171
+
1172
+
1173
+
1174
+
1175
+
1176
+
1177
+ <li class="md-nav__item">
1178
+ <a href="../core-functionality/circuits.html" class="md-nav__link">
1179
+ Circuits
1180
+ </a>
1181
+ </li>
1182
+
1183
+
1184
+
1185
+
1186
+
1187
+
1188
+
1189
+
1190
+
1191
+ <li class="md-nav__item">
1192
+ <a href="../core-functionality/devices.html" class="md-nav__link">
1193
+ Devices and Cabling
1194
+ </a>
1195
+ </li>
1196
+
1197
+
1198
+
1199
+
1200
+
1201
+
1202
+
1203
+
1204
+
1205
+ <li class="md-nav__item">
1206
+ <a href="../core-functionality/device-types.html" class="md-nav__link">
1207
+ Device Types
1208
+ </a>
1209
+ </li>
1210
+
1211
+
1212
+
1213
+
1214
+
1215
+
1216
+
1217
+
1218
+
1219
+ <li class="md-nav__item">
1220
+ <a href="../core-functionality/ipam.html" class="md-nav__link">
1221
+ IP Address Management
1222
+ </a>
1223
+ </li>
1224
+
1225
+
1226
+
1227
+
1228
+
1229
+
1230
+
1231
+
1232
+
1233
+ <li class="md-nav__item">
1234
+ <a href="../core-functionality/power.html" class="md-nav__link">
1235
+ Power Tracking
1236
+ </a>
1237
+ </li>
1238
+
1239
+
1240
+
1241
+
1242
+
1243
+
1244
+
1245
+
1246
+
1247
+ <li class="md-nav__item">
1248
+ <a href="../core-functionality/secrets.html" class="md-nav__link">
1249
+ Secrets
1250
+ </a>
1251
+ </li>
1252
+
1253
+
1254
+
1255
+
1256
+
1257
+
1258
+
1259
+
1260
+
1261
+ <li class="md-nav__item">
1262
+ <a href="../core-functionality/services.html" class="md-nav__link">
1263
+ Service Mapping
1264
+ </a>
1265
+ </li>
1266
+
1267
+
1268
+
1269
+
1270
+
1271
+
1272
+
1273
+
1274
+
1275
+ <li class="md-nav__item">
1276
+ <a href="../core-functionality/sites-and-racks.html" class="md-nav__link">
1277
+ Sites, Locations, and Racks
1278
+ </a>
1279
+ </li>
1280
+
1281
+
1282
+
1283
+
1284
+
1285
+
1286
+
1287
+
1288
+
1289
+ <li class="md-nav__item">
1290
+ <a href="../core-functionality/tenancy.html" class="md-nav__link">
1291
+ Tenancy
1292
+ </a>
1293
+ </li>
1294
+
1295
+
1296
+
1297
+
1298
+
1299
+
1300
+
1301
+
1302
+
1303
+ <li class="md-nav__item">
1304
+ <a href="../core-functionality/virtualization.html" class="md-nav__link">
1305
+ Virtualization
1306
+ </a>
1307
+ </li>
1308
+
1309
+
1310
+
1311
+
1312
+
1313
+
1314
+
1315
+
1316
+
1317
+ <li class="md-nav__item">
1318
+ <a href="../core-functionality/vlans.html" class="md-nav__link">
1319
+ VLAN Management
1320
+ </a>
1321
+ </li>
1322
+
1323
+
1324
+
1325
+
1326
+ </ul>
1327
+ </nav>
1328
+ </li>
1329
+
1330
+
1331
+
1332
+
1333
+
1334
+
1335
+
1336
+
1337
+
1338
+
1339
+ <li class="md-nav__item md-nav__item--nested">
1340
+
1341
+
1342
+
1343
+
1344
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8" >
1345
+
1346
+
1347
+
1348
+ <label class="md-nav__link" for="__nav_2_8" id="__nav_2_8_label" tabindex="0">
1349
+ Model Details
1350
+ <span class="md-nav__icon md-icon"></span>
1351
+ </label>
1352
+
1353
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
1354
+ <label class="md-nav__title" for="__nav_2_8">
1355
+ <span class="md-nav__icon md-icon"></span>
1356
+ Model Details
1357
+ </label>
1358
+ <ul class="md-nav__list" data-md-scrollfix>
1359
+
1360
+
1361
+
1362
+
1363
+
1364
+
1365
+
1366
+ <li class="md-nav__item md-nav__item--nested">
1367
+
1368
+
1369
+
1370
+
1371
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_1" >
1372
+
1373
+
1374
+
1375
+ <label class="md-nav__link" for="__nav_2_8_1" id="__nav_2_8_1_label" tabindex="0">
1376
+ Circuits
1377
+ <span class="md-nav__icon md-icon"></span>
1378
+ </label>
1379
+
1380
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_1_label" aria-expanded="false">
1381
+ <label class="md-nav__title" for="__nav_2_8_1">
1382
+ <span class="md-nav__icon md-icon"></span>
1383
+ Circuits
1384
+ </label>
1385
+ <ul class="md-nav__list" data-md-scrollfix>
1386
+
1387
+
1388
+
1389
+
1390
+
1391
+
1392
+ <li class="md-nav__item">
1393
+ <a href="../models/circuits/circuit.html" class="md-nav__link">
1394
+ Circuit
1395
+ </a>
1396
+ </li>
1397
+
1398
+
1399
+
1400
+
1401
+
1402
+
1403
+
1404
+
1405
+
1406
+ <li class="md-nav__item">
1407
+ <a href="../models/circuits/circuittermination.html" class="md-nav__link">
1408
+ Circuit Termination
1409
+ </a>
1410
+ </li>
1411
+
1412
+
1413
+
1414
+
1415
+
1416
+
1417
+
1418
+
1419
+
1420
+ <li class="md-nav__item">
1421
+ <a href="../models/circuits/circuittype.html" class="md-nav__link">
1422
+ Circuit Type
1423
+ </a>
1424
+ </li>
1425
+
1426
+
1427
+
1428
+
1429
+
1430
+
1431
+
1432
+
1433
+
1434
+ <li class="md-nav__item">
1435
+ <a href="../models/circuits/provider.html" class="md-nav__link">
1436
+ Circuit Provider
1437
+ </a>
1438
+ </li>
1439
+
1440
+
1441
+
1442
+
1443
+
1444
+
1445
+
1446
+
1447
+
1448
+ <li class="md-nav__item">
1449
+ <a href="../models/circuits/providernetwork.html" class="md-nav__link">
1450
+ Circuit Provider Network
1451
+ </a>
1452
+ </li>
1453
+
1454
+
1455
+
1456
+
1457
+ </ul>
1458
+ </nav>
1459
+ </li>
1460
+
1461
+
1462
+
1463
+
1464
+
1465
+
1466
+
1467
+
1468
+
1469
+
1470
+ <li class="md-nav__item md-nav__item--nested">
1471
+
1472
+
1473
+
1474
+
1475
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_2" >
1476
+
1477
+
1478
+
1479
+ <label class="md-nav__link" for="__nav_2_8_2" id="__nav_2_8_2_label" tabindex="0">
1480
+ DCIM
1481
+ <span class="md-nav__icon md-icon"></span>
1482
+ </label>
1483
+
1484
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_2_label" aria-expanded="false">
1485
+ <label class="md-nav__title" for="__nav_2_8_2">
1486
+ <span class="md-nav__icon md-icon"></span>
1487
+ DCIM
1488
+ </label>
1489
+ <ul class="md-nav__list" data-md-scrollfix>
1490
+
1491
+
1492
+
1493
+
1494
+
1495
+
1496
+ <li class="md-nav__item">
1497
+ <a href="../models/dcim/cable.html" class="md-nav__link">
1498
+ Cable
1499
+ </a>
1500
+ </li>
1501
+
1502
+
1503
+
1504
+
1505
+
1506
+
1507
+
1508
+
1509
+
1510
+ <li class="md-nav__item">
1511
+ <a href="../models/dcim/consoleport.html" class="md-nav__link">
1512
+ Console Port
1513
+ </a>
1514
+ </li>
1515
+
1516
+
1517
+
1518
+
1519
+
1520
+
1521
+
1522
+
1523
+
1524
+ <li class="md-nav__item">
1525
+ <a href="../models/dcim/consoleporttemplate.html" class="md-nav__link">
1526
+ Console Port Template
1527
+ </a>
1528
+ </li>
1529
+
1530
+
1531
+
1532
+
1533
+
1534
+
1535
+
1536
+
1537
+
1538
+ <li class="md-nav__item">
1539
+ <a href="../models/dcim/consoleserverport.html" class="md-nav__link">
1540
+ Console Server Port
1541
+ </a>
1542
+ </li>
1543
+
1544
+
1545
+
1546
+
1547
+
1548
+
1549
+
1550
+
1551
+
1552
+ <li class="md-nav__item">
1553
+ <a href="../models/dcim/consoleserverporttemplate.html" class="md-nav__link">
1554
+ Console Server Port Template
1555
+ </a>
1556
+ </li>
1557
+
1558
+
1559
+
1560
+
1561
+
1562
+
1563
+
1564
+
1565
+
1566
+ <li class="md-nav__item">
1567
+ <a href="../models/dcim/device.html" class="md-nav__link">
1568
+ Device
1569
+ </a>
1570
+ </li>
1571
+
1572
+
1573
+
1574
+
1575
+
1576
+
1577
+
1578
+
1579
+
1580
+ <li class="md-nav__item">
1581
+ <a href="../models/dcim/devicebay.html" class="md-nav__link">
1582
+ Device Bay
1583
+ </a>
1584
+ </li>
1585
+
1586
+
1587
+
1588
+
1589
+
1590
+
1591
+
1592
+
1593
+
1594
+ <li class="md-nav__item">
1595
+ <a href="../models/dcim/devicebaytemplate.html" class="md-nav__link">
1596
+ Device Bay Template
1597
+ </a>
1598
+ </li>
1599
+
1600
+
1601
+
1602
+
1603
+
1604
+
1605
+
1606
+
1607
+
1608
+ <li class="md-nav__item">
1609
+ <a href="../models/dcim/deviceredundancygroup.html" class="md-nav__link">
1610
+ Device Redundancy Group
1611
+ </a>
1612
+ </li>
1613
+
1614
+
1615
+
1616
+
1617
+
1618
+
1619
+
1620
+
1621
+
1622
+ <li class="md-nav__item">
1623
+ <a href="../models/dcim/devicetype.html" class="md-nav__link">
1624
+ Device Type
1625
+ </a>
1626
+ </li>
1627
+
1628
+
1629
+
1630
+
1631
+
1632
+
1633
+
1634
+
1635
+
1636
+ <li class="md-nav__item">
1637
+ <a href="../models/dcim/frontport.html" class="md-nav__link">
1638
+ Front Port
1639
+ </a>
1640
+ </li>
1641
+
1642
+
1643
+
1644
+
1645
+
1646
+
1647
+
1648
+
1649
+
1650
+ <li class="md-nav__item">
1651
+ <a href="../models/dcim/frontporttemplate.html" class="md-nav__link">
1652
+ Front Port Template
1653
+ </a>
1654
+ </li>
1655
+
1656
+
1657
+
1658
+
1659
+
1660
+
1661
+
1662
+
1663
+
1664
+ <li class="md-nav__item">
1665
+ <a href="../models/dcim/interface.html" class="md-nav__link">
1666
+ Interface
1667
+ </a>
1668
+ </li>
1669
+
1670
+
1671
+
1672
+
1673
+
1674
+
1675
+
1676
+
1677
+
1678
+ <li class="md-nav__item">
1679
+ <a href="../models/dcim/interfacetemplate.html" class="md-nav__link">
1680
+ Interface Template
1681
+ </a>
1682
+ </li>
1683
+
1684
+
1685
+
1686
+
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+ <li class="md-nav__item">
1693
+ <a href="../models/dcim/inventoryitem.html" class="md-nav__link">
1694
+ Inventory Item
1695
+ </a>
1696
+ </li>
1697
+
1698
+
1699
+
1700
+
1701
+
1702
+
1703
+
1704
+
1705
+
1706
+ <li class="md-nav__item">
1707
+ <a href="../models/dcim/location.html" class="md-nav__link">
1708
+ Location
1709
+ </a>
1710
+ </li>
1711
+
1712
+
1713
+
1714
+
1715
+
1716
+
1717
+
1718
+
1719
+
1720
+ <li class="md-nav__item">
1721
+ <a href="../models/dcim/locationtype.html" class="md-nav__link">
1722
+ Location Type
1723
+ </a>
1724
+ </li>
1725
+
1726
+
1727
+
1728
+
1729
+
1730
+
1731
+
1732
+
1733
+
1734
+ <li class="md-nav__item">
1735
+ <a href="../models/dcim/manufacturer.html" class="md-nav__link">
1736
+ Manufacturer
1737
+ </a>
1738
+ </li>
1739
+
1740
+
1741
+
1742
+
1743
+
1744
+
1745
+
1746
+
1747
+
1748
+ <li class="md-nav__item">
1749
+ <a href="../models/dcim/platform.html" class="md-nav__link">
1750
+ Platform
1751
+ </a>
1752
+ </li>
1753
+
1754
+
1755
+
1756
+
1757
+
1758
+
1759
+
1760
+
1761
+
1762
+ <li class="md-nav__item">
1763
+ <a href="../models/dcim/powerfeed.html" class="md-nav__link">
1764
+ Power Feed
1765
+ </a>
1766
+ </li>
1767
+
1768
+
1769
+
1770
+
1771
+
1772
+
1773
+
1774
+
1775
+
1776
+ <li class="md-nav__item">
1777
+ <a href="../models/dcim/poweroutlet.html" class="md-nav__link">
1778
+ Power Outlet
1779
+ </a>
1780
+ </li>
1781
+
1782
+
1783
+
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+ <li class="md-nav__item">
1791
+ <a href="../models/dcim/poweroutlettemplate.html" class="md-nav__link">
1792
+ Power Outlet Template
1793
+ </a>
1794
+ </li>
1795
+
1796
+
1797
+
1798
+
1799
+
1800
+
1801
+
1802
+
1803
+
1804
+ <li class="md-nav__item">
1805
+ <a href="../models/dcim/powerpanel.html" class="md-nav__link">
1806
+ Power Panel
1807
+ </a>
1808
+ </li>
1809
+
1810
+
1811
+
1812
+
1813
+
1814
+
1815
+
1816
+
1817
+
1818
+ <li class="md-nav__item">
1819
+ <a href="../models/dcim/powerport.html" class="md-nav__link">
1820
+ Power Port
1821
+ </a>
1822
+ </li>
1823
+
1824
+
1825
+
1826
+
1827
+
1828
+
1829
+
1830
+
1831
+
1832
+ <li class="md-nav__item">
1833
+ <a href="../models/dcim/powerporttemplate.html" class="md-nav__link">
1834
+ Power Port Template
1835
+ </a>
1836
+ </li>
1837
+
1838
+
1839
+
1840
+
1841
+
1842
+
1843
+
1844
+
1845
+
1846
+ <li class="md-nav__item">
1847
+ <a href="../models/dcim/rack.html" class="md-nav__link">
1848
+ Rack
1849
+ </a>
1850
+ </li>
1851
+
1852
+
1853
+
1854
+
1855
+
1856
+
1857
+
1858
+
1859
+
1860
+ <li class="md-nav__item">
1861
+ <a href="../models/dcim/rackgroup.html" class="md-nav__link">
1862
+ Rack Group
1863
+ </a>
1864
+ </li>
1865
+
1866
+
1867
+
1868
+
1869
+
1870
+
1871
+
1872
+
1873
+
1874
+ <li class="md-nav__item">
1875
+ <a href="../models/dcim/rackreservation.html" class="md-nav__link">
1876
+ Rack Reservation
1877
+ </a>
1878
+ </li>
1879
+
1880
+
1881
+
1882
+
1883
+
1884
+
1885
+
1886
+
1887
+
1888
+ <li class="md-nav__item">
1889
+ <a href="../models/dcim/rearport.html" class="md-nav__link">
1890
+ Rear Port
1891
+ </a>
1892
+ </li>
1893
+
1894
+
1895
+
1896
+
1897
+
1898
+
1899
+
1900
+
1901
+
1902
+ <li class="md-nav__item">
1903
+ <a href="../models/dcim/rearporttemplate.html" class="md-nav__link">
1904
+ Rear Port Template
1905
+ </a>
1906
+ </li>
1907
+
1908
+
1909
+
1910
+
1911
+
1912
+
1913
+
1914
+
1915
+
1916
+ <li class="md-nav__item">
1917
+ <a href="../models/dcim/virtualchassis.html" class="md-nav__link">
1918
+ Virtual Chassis
1919
+ </a>
1920
+ </li>
1921
+
1922
+
1923
+
1924
+
1925
+ </ul>
1926
+ </nav>
1927
+ </li>
1928
+
1929
+
1930
+
1931
+
1932
+
1933
+
1934
+
1935
+
1936
+
1937
+
1938
+ <li class="md-nav__item md-nav__item--nested">
1939
+
1940
+
1941
+
1942
+
1943
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_3" >
1944
+
1945
+
1946
+
1947
+ <label class="md-nav__link" for="__nav_2_8_3" id="__nav_2_8_3_label" tabindex="0">
1948
+ Extras
1949
+ <span class="md-nav__icon md-icon"></span>
1950
+ </label>
1951
+
1952
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_3_label" aria-expanded="false">
1953
+ <label class="md-nav__title" for="__nav_2_8_3">
1954
+ <span class="md-nav__icon md-icon"></span>
1955
+ Extras
1956
+ </label>
1957
+ <ul class="md-nav__list" data-md-scrollfix>
1958
+
1959
+
1960
+
1961
+
1962
+
1963
+
1964
+ <li class="md-nav__item">
1965
+ <a href="../models/extras/configcontext.html" class="md-nav__link">
1966
+ Config Context
1967
+ </a>
1968
+ </li>
1969
+
1970
+
1971
+
1972
+
1973
+
1974
+
1975
+
1976
+
1977
+
1978
+ <li class="md-nav__item">
1979
+ <a href="../models/extras/configcontextschema.html" class="md-nav__link">
1980
+ Config Context Schema
1981
+ </a>
1982
+ </li>
1983
+
1984
+
1985
+
1986
+
1987
+
1988
+
1989
+
1990
+
1991
+
1992
+ <li class="md-nav__item">
1993
+ <a href="../models/extras/graphqlquery.html" class="md-nav__link">
1994
+ GraphQL Query
1995
+ </a>
1996
+ </li>
1997
+
1998
+
1999
+
2000
+
2001
+
2002
+
2003
+
2004
+
2005
+
2006
+ <li class="md-nav__item">
2007
+ <a href="../models/extras/imageattachment.html" class="md-nav__link">
2008
+ Image Attachment
2009
+ </a>
2010
+ </li>
2011
+
2012
+
2013
+
2014
+
2015
+
2016
+
2017
+
2018
+
2019
+
2020
+ <li class="md-nav__item">
2021
+ <a href="../models/extras/job.html" class="md-nav__link">
2022
+ Job
2023
+ </a>
2024
+ </li>
2025
+
2026
+
2027
+
2028
+
2029
+
2030
+
2031
+
2032
+
2033
+
2034
+ <li class="md-nav__item">
2035
+ <a href="../models/extras/joblogentry.html" class="md-nav__link">
2036
+ Job Log Entry
2037
+ </a>
2038
+ </li>
2039
+
2040
+
2041
+
2042
+
2043
+
2044
+
2045
+
2046
+
2047
+
2048
+ <li class="md-nav__item">
2049
+ <a href="../models/extras/jobresult.html" class="md-nav__link">
2050
+ Job Result
2051
+ </a>
2052
+ </li>
2053
+
2054
+
2055
+
2056
+
2057
+
2058
+
2059
+
2060
+
2061
+
2062
+ <li class="md-nav__item">
2063
+ <a href="../models/extras/role.html" class="md-nav__link">
2064
+ Role
2065
+ </a>
2066
+ </li>
2067
+
2068
+
2069
+
2070
+
2071
+
2072
+
2073
+
2074
+
2075
+
2076
+ <li class="md-nav__item">
2077
+ <a href="../models/extras/secret.html" class="md-nav__link">
2078
+ Secret
2079
+ </a>
2080
+ </li>
2081
+
2082
+
2083
+
2084
+
2085
+
2086
+
2087
+
2088
+
2089
+
2090
+ <li class="md-nav__item">
2091
+ <a href="../models/extras/secretsgroup.html" class="md-nav__link">
2092
+ Secrets group
2093
+ </a>
2094
+ </li>
2095
+
2096
+
2097
+
2098
+
2099
+ </ul>
2100
+ </nav>
2101
+ </li>
2102
+
2103
+
2104
+
2105
+
2106
+
2107
+
2108
+
2109
+
2110
+
2111
+
2112
+ <li class="md-nav__item md-nav__item--nested">
2113
+
2114
+
2115
+
2116
+
2117
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_4" >
2118
+
2119
+
2120
+
2121
+ <label class="md-nav__link" for="__nav_2_8_4" id="__nav_2_8_4_label" tabindex="0">
2122
+ IPAM
2123
+ <span class="md-nav__icon md-icon"></span>
2124
+ </label>
2125
+
2126
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_4_label" aria-expanded="false">
2127
+ <label class="md-nav__title" for="__nav_2_8_4">
2128
+ <span class="md-nav__icon md-icon"></span>
2129
+ IPAM
2130
+ </label>
2131
+ <ul class="md-nav__list" data-md-scrollfix>
2132
+
2133
+
2134
+
2135
+
2136
+
2137
+
2138
+ <li class="md-nav__item">
2139
+ <a href="../models/ipam/ipaddress.html" class="md-nav__link">
2140
+ IP Address
2141
+ </a>
2142
+ </li>
2143
+
2144
+
2145
+
2146
+
2147
+
2148
+
2149
+
2150
+
2151
+
2152
+ <li class="md-nav__item">
2153
+ <a href="../models/ipam/prefix.html" class="md-nav__link">
2154
+ Prefix
2155
+ </a>
2156
+ </li>
2157
+
2158
+
2159
+
2160
+
2161
+
2162
+
2163
+
2164
+
2165
+
2166
+ <li class="md-nav__item">
2167
+ <a href="../models/ipam/rir.html" class="md-nav__link">
2168
+ Rir
2169
+ </a>
2170
+ </li>
2171
+
2172
+
2173
+
2174
+
2175
+
2176
+
2177
+
2178
+
2179
+
2180
+ <li class="md-nav__item">
2181
+ <a href="../models/ipam/routetarget.html" class="md-nav__link">
2182
+ Route Target
2183
+ </a>
2184
+ </li>
2185
+
2186
+
2187
+
2188
+
2189
+
2190
+
2191
+
2192
+
2193
+
2194
+ <li class="md-nav__item">
2195
+ <a href="../models/ipam/service.html" class="md-nav__link">
2196
+ Service
2197
+ </a>
2198
+ </li>
2199
+
2200
+
2201
+
2202
+
2203
+
2204
+
2205
+
2206
+
2207
+
2208
+ <li class="md-nav__item">
2209
+ <a href="../models/ipam/vlan.html" class="md-nav__link">
2210
+ VLAN
2211
+ </a>
2212
+ </li>
2213
+
2214
+
2215
+
2216
+
2217
+
2218
+
2219
+
2220
+
2221
+
2222
+ <li class="md-nav__item">
2223
+ <a href="../models/ipam/vlangroup.html" class="md-nav__link">
2224
+ VLAN Group
2225
+ </a>
2226
+ </li>
2227
+
2228
+
2229
+
2230
+
2231
+
2232
+
2233
+
2234
+
2235
+
2236
+ <li class="md-nav__item">
2237
+ <a href="../models/ipam/vrf.html" class="md-nav__link">
2238
+ VRF
2239
+ </a>
2240
+ </li>
2241
+
2242
+
2243
+
2244
+
2245
+ </ul>
2246
+ </nav>
2247
+ </li>
2248
+
2249
+
2250
+
2251
+
2252
+
2253
+
2254
+
2255
+
2256
+
2257
+
2258
+ <li class="md-nav__item md-nav__item--nested">
2259
+
2260
+
2261
+
2262
+
2263
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_5" >
1149
2264
 
1150
2265
 
1151
- <label class="md-nav__link" for="__nav_2_7">
1152
- Core Functionality
2266
+
2267
+ <label class="md-nav__link" for="__nav_2_8_5" id="__nav_2_8_5_label" tabindex="0">
2268
+ Tenancy
1153
2269
  <span class="md-nav__icon md-icon"></span>
1154
2270
  </label>
1155
2271
 
1156
- <nav class="md-nav" aria-label="Core Functionality" data-md-level="2">
1157
- <label class="md-nav__title" for="__nav_2_7">
2272
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_5_label" aria-expanded="false">
2273
+ <label class="md-nav__title" for="__nav_2_8_5">
1158
2274
  <span class="md-nav__icon md-icon"></span>
1159
- Core Functionality
2275
+ Tenancy
1160
2276
  </label>
1161
2277
  <ul class="md-nav__list" data-md-scrollfix>
1162
2278
 
@@ -1166,8 +2282,8 @@
1166
2282
 
1167
2283
 
1168
2284
  <li class="md-nav__item">
1169
- <a href="../core-functionality/circuits.html" class="md-nav__link">
1170
- Circuits
2285
+ <a href="../models/tenancy/tenant.html" class="md-nav__link">
2286
+ Tenant
1171
2287
  </a>
1172
2288
  </li>
1173
2289
 
@@ -1180,27 +2296,47 @@
1180
2296
 
1181
2297
 
1182
2298
  <li class="md-nav__item">
1183
- <a href="../core-functionality/devices.html" class="md-nav__link">
1184
- Devices and Cabling
2299
+ <a href="../models/tenancy/tenantgroup.html" class="md-nav__link">
2300
+ Tenant Group
1185
2301
  </a>
1186
2302
  </li>
1187
2303
 
1188
2304
 
1189
2305
 
1190
2306
 
2307
+ </ul>
2308
+ </nav>
2309
+ </li>
2310
+
2311
+
2312
+
2313
+
1191
2314
 
1192
2315
 
1193
2316
 
1194
2317
 
1195
2318
 
1196
- <li class="md-nav__item">
1197
- <a href="../core-functionality/device-types.html" class="md-nav__link">
1198
- Device Types
1199
- </a>
1200
- </li>
1201
-
1202
-
1203
-
2319
+
2320
+ <li class="md-nav__item md-nav__item--nested">
2321
+
2322
+
2323
+
2324
+
2325
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_6" >
2326
+
2327
+
2328
+
2329
+ <label class="md-nav__link" for="__nav_2_8_6" id="__nav_2_8_6_label" tabindex="0">
2330
+ Users
2331
+ <span class="md-nav__icon md-icon"></span>
2332
+ </label>
2333
+
2334
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_6_label" aria-expanded="false">
2335
+ <label class="md-nav__title" for="__nav_2_8_6">
2336
+ <span class="md-nav__icon md-icon"></span>
2337
+ Users
2338
+ </label>
2339
+ <ul class="md-nav__list" data-md-scrollfix>
1204
2340
 
1205
2341
 
1206
2342
 
@@ -1208,8 +2344,8 @@
1208
2344
 
1209
2345
 
1210
2346
  <li class="md-nav__item">
1211
- <a href="../core-functionality/ipam.html" class="md-nav__link">
1212
- IP Address Management
2347
+ <a href="../models/users/objectpermission.html" class="md-nav__link">
2348
+ Object Permission
1213
2349
  </a>
1214
2350
  </li>
1215
2351
 
@@ -1222,27 +2358,47 @@
1222
2358
 
1223
2359
 
1224
2360
  <li class="md-nav__item">
1225
- <a href="../core-functionality/power.html" class="md-nav__link">
1226
- Power Tracking
2361
+ <a href="../models/users/token.html" class="md-nav__link">
2362
+ Token
1227
2363
  </a>
1228
2364
  </li>
1229
2365
 
1230
2366
 
1231
2367
 
1232
2368
 
2369
+ </ul>
2370
+ </nav>
2371
+ </li>
2372
+
2373
+
2374
+
2375
+
1233
2376
 
1234
2377
 
1235
2378
 
1236
2379
 
1237
2380
 
1238
- <li class="md-nav__item">
1239
- <a href="../core-functionality/secrets.html" class="md-nav__link">
1240
- Secrets
1241
- </a>
1242
- </li>
1243
-
1244
-
1245
-
2381
+
2382
+ <li class="md-nav__item md-nav__item--nested">
2383
+
2384
+
2385
+
2386
+
2387
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_7" >
2388
+
2389
+
2390
+
2391
+ <label class="md-nav__link" for="__nav_2_8_7" id="__nav_2_8_7_label" tabindex="0">
2392
+ Virtualization
2393
+ <span class="md-nav__icon md-icon"></span>
2394
+ </label>
2395
+
2396
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_7_label" aria-expanded="false">
2397
+ <label class="md-nav__title" for="__nav_2_8_7">
2398
+ <span class="md-nav__icon md-icon"></span>
2399
+ Virtualization
2400
+ </label>
2401
+ <ul class="md-nav__list" data-md-scrollfix>
1246
2402
 
1247
2403
 
1248
2404
 
@@ -1250,8 +2406,8 @@
1250
2406
 
1251
2407
 
1252
2408
  <li class="md-nav__item">
1253
- <a href="../core-functionality/services.html" class="md-nav__link">
1254
- Service Mapping
2409
+ <a href="../models/virtualization/cluster.html" class="md-nav__link">
2410
+ Cluster
1255
2411
  </a>
1256
2412
  </li>
1257
2413
 
@@ -1264,8 +2420,8 @@
1264
2420
 
1265
2421
 
1266
2422
  <li class="md-nav__item">
1267
- <a href="../core-functionality/sites-and-racks.html" class="md-nav__link">
1268
- Sites, Locations, and Racks
2423
+ <a href="../models/virtualization/clustergroup.html" class="md-nav__link">
2424
+ Cluster Group
1269
2425
  </a>
1270
2426
  </li>
1271
2427
 
@@ -1278,8 +2434,8 @@
1278
2434
 
1279
2435
 
1280
2436
  <li class="md-nav__item">
1281
- <a href="../core-functionality/tenancy.html" class="md-nav__link">
1282
- Tenancy
2437
+ <a href="../models/virtualization/clustertype.html" class="md-nav__link">
2438
+ Cluster Type
1283
2439
  </a>
1284
2440
  </li>
1285
2441
 
@@ -1292,8 +2448,8 @@
1292
2448
 
1293
2449
 
1294
2450
  <li class="md-nav__item">
1295
- <a href="../core-functionality/virtualization.html" class="md-nav__link">
1296
- Virtualization
2451
+ <a href="../models/virtualization/virtualmachine.html" class="md-nav__link">
2452
+ Virtual Machine
1297
2453
  </a>
1298
2454
  </li>
1299
2455
 
@@ -1306,8 +2462,8 @@
1306
2462
 
1307
2463
 
1308
2464
  <li class="md-nav__item">
1309
- <a href="../core-functionality/vlans.html" class="md-nav__link">
1310
- VLAN Management
2465
+ <a href="../models/virtualization/vminterface.html" class="md-nav__link">
2466
+ VM Interface
1311
2467
  </a>
1312
2468
  </li>
1313
2469
 
@@ -1321,6 +2477,13 @@
1321
2477
 
1322
2478
 
1323
2479
 
2480
+ </ul>
2481
+ </nav>
2482
+ </li>
2483
+
2484
+
2485
+
2486
+
1324
2487
 
1325
2488
 
1326
2489
 
@@ -1330,18 +2493,19 @@
1330
2493
  <li class="md-nav__item md-nav__item--nested">
1331
2494
 
1332
2495
 
1333
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_8" type="checkbox" id="__nav_2_8" >
1334
2496
 
1335
2497
 
2498
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_9" >
2499
+
1336
2500
 
1337
2501
 
1338
- <label class="md-nav__link" for="__nav_2_8">
2502
+ <label class="md-nav__link" for="__nav_2_9" id="__nav_2_9_label" tabindex="0">
1339
2503
  Additional Features
1340
2504
  <span class="md-nav__icon md-icon"></span>
1341
2505
  </label>
1342
2506
 
1343
- <nav class="md-nav" aria-label="Additional Features" data-md-level="2">
1344
- <label class="md-nav__title" for="__nav_2_8">
2507
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="false">
2508
+ <label class="md-nav__title" for="__nav_2_9">
1345
2509
  <span class="md-nav__icon md-icon"></span>
1346
2510
  Additional Features
1347
2511
  </label>
@@ -1671,18 +2835,19 @@
1671
2835
  <li class="md-nav__item md-nav__item--nested">
1672
2836
 
1673
2837
 
1674
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_9" type="checkbox" id="__nav_2_9" >
1675
2838
 
1676
2839
 
2840
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_10" >
1677
2841
 
1678
2842
 
1679
- <label class="md-nav__link" for="__nav_2_9">
2843
+
2844
+ <label class="md-nav__link" for="__nav_2_10" id="__nav_2_10_label" tabindex="0">
1680
2845
  REST API
1681
2846
  <span class="md-nav__icon md-icon"></span>
1682
2847
  </label>
1683
2848
 
1684
- <nav class="md-nav" aria-label="REST API" data-md-level="2">
1685
- <label class="md-nav__title" for="__nav_2_9">
2849
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
2850
+ <label class="md-nav__title" for="__nav_2_10">
1686
2851
  <span class="md-nav__icon md-icon"></span>
1687
2852
  REST API
1688
2853
  </label>
@@ -1730,6 +2895,20 @@
1730
2895
 
1731
2896
 
1732
2897
 
2898
+
2899
+
2900
+
2901
+
2902
+
2903
+ <li class="md-nav__item">
2904
+ <a href="../rest-api/ui-related-endpoints.html" class="md-nav__link">
2905
+ UI Endpoints
2906
+ </a>
2907
+ </li>
2908
+
2909
+
2910
+
2911
+
1733
2912
  </ul>
1734
2913
  </nav>
1735
2914
  </li>
@@ -1746,18 +2925,19 @@
1746
2925
  <li class="md-nav__item md-nav__item--nested">
1747
2926
 
1748
2927
 
1749
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_10" type="checkbox" id="__nav_2_10" >
1750
2928
 
1751
2929
 
2930
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_11" >
2931
+
1752
2932
 
1753
2933
 
1754
- <label class="md-nav__link" for="__nav_2_10">
2934
+ <label class="md-nav__link" for="__nav_2_11" id="__nav_2_11_label" tabindex="0">
1755
2935
  GraphQL API
1756
2936
  <span class="md-nav__icon md-icon"></span>
1757
2937
  </label>
1758
2938
 
1759
- <nav class="md-nav" aria-label="GraphQL API" data-md-level="2">
1760
- <label class="md-nav__title" for="__nav_2_10">
2939
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_11_label" aria-expanded="false">
2940
+ <label class="md-nav__title" for="__nav_2_11">
1761
2941
  <span class="md-nav__icon md-icon"></span>
1762
2942
  GraphQL API
1763
2943
  </label>
@@ -1817,17 +2997,18 @@
1817
2997
  <li class="md-nav__item md-nav__item--active md-nav__item--nested">
1818
2998
 
1819
2999
 
1820
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3" type="checkbox" id="__nav_3" checked>
1821
3000
 
1822
3001
 
3002
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" checked>
3003
+
1823
3004
 
1824
3005
 
1825
- <label class="md-nav__link" for="__nav_3">
3006
+ <label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
1826
3007
  App Developer Guide
1827
3008
  <span class="md-nav__icon md-icon"></span>
1828
3009
  </label>
1829
3010
 
1830
- <nav class="md-nav" aria-label="App Developer Guide" data-md-level="1">
3011
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="true">
1831
3012
  <label class="md-nav__title" for="__nav_3">
1832
3013
  <span class="md-nav__icon md-icon"></span>
1833
3014
  App Developer Guide
@@ -1843,7 +3024,7 @@
1843
3024
 
1844
3025
  <li class="md-nav__item md-nav__item--active">
1845
3026
 
1846
- <input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
3027
+ <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
1847
3028
 
1848
3029
 
1849
3030
 
@@ -2022,6 +3203,13 @@
2022
3203
  Adding Database Backed Config
2023
3204
  </a>
2024
3205
 
3206
+ </li>
3207
+
3208
+ <li class="md-nav__item">
3209
+ <a href="#overriding-default-model-views-in-nautobot-apps" class="md-nav__link">
3210
+ Overriding Default Model Views in Nautobot Apps
3211
+ </a>
3212
+
2025
3213
  </li>
2026
3214
 
2027
3215
  </ul>
@@ -2362,17 +3550,18 @@
2362
3550
  <li class="md-nav__item md-nav__item--nested">
2363
3551
 
2364
3552
 
2365
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_3" type="checkbox" id="__nav_3_3" >
2366
3553
 
2367
3554
 
3555
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_3" >
3556
+
2368
3557
 
2369
3558
 
2370
- <label class="md-nav__link" for="__nav_3_3">
3559
+ <label class="md-nav__link" for="__nav_3_3" id="__nav_3_3_label" tabindex="0">
2371
3560
  Code Reference
2372
3561
  <span class="md-nav__icon md-icon"></span>
2373
3562
  </label>
2374
3563
 
2375
- <nav class="md-nav" aria-label="Code Reference" data-md-level="2">
3564
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_3_label" aria-expanded="false">
2376
3565
  <label class="md-nav__title" for="__nav_3_3">
2377
3566
  <span class="md-nav__icon md-icon"></span>
2378
3567
  Code Reference
@@ -2599,17 +3788,18 @@
2599
3788
  <li class="md-nav__item md-nav__item--nested">
2600
3789
 
2601
3790
 
2602
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4" type="checkbox" id="__nav_4" >
2603
3791
 
2604
3792
 
3793
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
2605
3794
 
2606
3795
 
2607
- <label class="md-nav__link" for="__nav_4">
3796
+
3797
+ <label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
2608
3798
  Core Developer Guide
2609
3799
  <span class="md-nav__icon md-icon"></span>
2610
3800
  </label>
2611
3801
 
2612
- <nav class="md-nav" aria-label="Core Developer Guide" data-md-level="1">
3802
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
2613
3803
  <label class="md-nav__title" for="__nav_4">
2614
3804
  <span class="md-nav__icon md-icon"></span>
2615
3805
  Core Developer Guide
@@ -2843,17 +4033,18 @@
2843
4033
  <li class="md-nav__item md-nav__item--nested">
2844
4034
 
2845
4035
 
2846
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" type="checkbox" id="__nav_5" >
2847
4036
 
2848
4037
 
4038
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
4039
+
2849
4040
 
2850
4041
 
2851
- <label class="md-nav__link" for="__nav_5">
4042
+ <label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
2852
4043
  Release Notes
2853
4044
  <span class="md-nav__icon md-icon"></span>
2854
4045
  </label>
2855
4046
 
2856
- <nav class="md-nav" aria-label="Release Notes" data-md-level="1">
4047
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
2857
4048
  <label class="md-nav__title" for="__nav_5">
2858
4049
  <span class="md-nav__icon md-icon"></span>
2859
4050
  Release Notes
@@ -2989,17 +4180,18 @@
2989
4180
  <li class="md-nav__item md-nav__item--nested">
2990
4181
 
2991
4182
 
2992
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" type="checkbox" id="__nav_6" >
2993
4183
 
2994
4184
 
4185
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
2995
4186
 
2996
4187
 
2997
- <label class="md-nav__link" for="__nav_6">
4188
+
4189
+ <label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
2998
4190
  Nautobot Apps
2999
4191
  <span class="md-nav__icon md-icon"></span>
3000
4192
  </label>
3001
4193
 
3002
- <nav class="md-nav" aria-label="Nautobot Apps" data-md-level="1">
4194
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
3003
4195
  <label class="md-nav__title" for="__nav_6">
3004
4196
  <span class="md-nav__icon md-icon"></span>
3005
4197
  Nautobot Apps
@@ -3029,17 +4221,18 @@
3029
4221
  <li class="md-nav__item md-nav__item--nested">
3030
4222
 
3031
4223
 
3032
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6_2" type="checkbox" id="__nav_6_2" >
3033
4224
 
3034
4225
 
4226
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_2" >
4227
+
3035
4228
 
3036
4229
 
3037
- <label class="md-nav__link" for="__nav_6_2">
4230
+ <label class="md-nav__link" for="__nav_6_2" id="__nav_6_2_label" tabindex="0">
3038
4231
  Network to Code App Docs
3039
4232
  <span class="md-nav__icon md-icon"></span>
3040
4233
  </label>
3041
4234
 
3042
- <nav class="md-nav" aria-label="Network to Code App Docs" data-md-level="2">
4235
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_6_2_label" aria-expanded="false">
3043
4236
  <label class="md-nav__title" for="__nav_6_2">
3044
4237
  <span class="md-nav__icon md-icon"></span>
3045
4238
  Network to Code App Docs
@@ -3066,8 +4259,8 @@
3066
4259
 
3067
4260
 
3068
4261
  <li class="md-nav__item">
3069
- <a href="https://nautobot-plugin-firewall-models.readthedocs.io/en/latest/" class="md-nav__link">
3070
- Nautobot Firewall Models
4262
+ <a href="https://docs.nautobot.com/projects/circuit-maintenance/en/latest/" class="md-nav__link">
4263
+ Nautobot Circuit Maintenance
3071
4264
  </a>
3072
4265
  </li>
3073
4266
 
@@ -3080,8 +4273,36 @@
3080
4273
 
3081
4274
 
3082
4275
  <li class="md-nav__item">
3083
- <a href="https://docs.nautobot.com/projects/plugin-nornir/en/latest/" class="md-nav__link">
3084
- Nautobot Plugin Nornir
4276
+ <a href="https://docs.nautobot.com/projects/device-lifecycle/en/latest/" class="md-nav__link">
4277
+ Nautobot Device LifeCycle Management
4278
+ </a>
4279
+ </li>
4280
+
4281
+
4282
+
4283
+
4284
+
4285
+
4286
+
4287
+
4288
+
4289
+ <li class="md-nav__item">
4290
+ <a href="https://docs.nautobot.com/projects/device-onboarding/en/latest/" class="md-nav__link">
4291
+ Nautobot Device Onboarding
4292
+ </a>
4293
+ </li>
4294
+
4295
+
4296
+
4297
+
4298
+
4299
+
4300
+
4301
+
4302
+
4303
+ <li class="md-nav__item">
4304
+ <a href="https://nautobot-plugin-firewall-models.readthedocs.io/en/latest/" class="md-nav__link">
4305
+ Nautobot Firewall Models
3085
4306
  </a>
3086
4307
  </li>
3087
4308
 
@@ -3108,7 +4329,21 @@
3108
4329
 
3109
4330
 
3110
4331
  <li class="md-nav__item">
3111
- <a href="https://nautobot-plugin-ssot.readthedocs.io/en/latest/" class="md-nav__link">
4332
+ <a href="https://docs.nautobot.com/projects/plugin-nornir/en/latest/" class="md-nav__link">
4333
+ Nautobot Plugin Nornir
4334
+ </a>
4335
+ </li>
4336
+
4337
+
4338
+
4339
+
4340
+
4341
+
4342
+
4343
+
4344
+
4345
+ <li class="md-nav__item">
4346
+ <a href="https://docs.nautobot.com/projects/ssot/en/latest/" class="md-nav__link">
3112
4347
  Nautobot Single Source of Truth
3113
4348
  </a>
3114
4349
  </li>
@@ -3333,6 +4568,13 @@
3333
4568
  Adding Database Backed Config
3334
4569
  </a>
3335
4570
 
4571
+ </li>
4572
+
4573
+ <li class="md-nav__item">
4574
+ <a href="#overriding-default-model-views-in-nautobot-apps" class="md-nav__link">
4575
+ Overriding Default Model Views in Nautobot Apps
4576
+ </a>
4577
+
3336
4578
  </li>
3337
4579
 
3338
4580
  </ul>
@@ -3655,10 +4897,8 @@
3655
4897
 
3656
4898
 
3657
4899
 
3658
- <a href="https://github.com/nautobot/nautobot/edit/main/nautobot/docs/plugins/development.md" title="Edit this page" class="md-content__button md-icon">
3659
-
3660
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25Z"/></svg>
3661
- </a>
4900
+
4901
+
3662
4902
 
3663
4903
 
3664
4904
  <h1 id="app-development">App Development<a class="headerlink" href="#app-development" title="Permanent link">&para;</a></h1>
@@ -3738,7 +4978,7 @@ Please see the <a href="../administration/nautobot-server.html#startplugin">Naut
3738
4978
  <a id="__codelineno-1-5" name="__codelineno-1-5" href="#__codelineno-1-5"></a>Description []: An example Nautobot app
3739
4979
  <a id="__codelineno-1-6" name="__codelineno-1-6" href="#__codelineno-1-6"></a>Author [, n to skip]: Bob Jones
3740
4980
  <a id="__codelineno-1-7" name="__codelineno-1-7" href="#__codelineno-1-7"></a>License []: Apache 2.0
3741
- <a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a>Compatible Python versions [^3.8]: ^3.7
4981
+ <a id="__codelineno-1-8" name="__codelineno-1-8" href="#__codelineno-1-8"></a>Compatible Python versions [^3.8]: ^3.8
3742
4982
  <a id="__codelineno-1-9" name="__codelineno-1-9" href="#__codelineno-1-9"></a>
3743
4983
  <a id="__codelineno-1-10" name="__codelineno-1-10" href="#__codelineno-1-10"></a>Would you like to define your main dependencies interactively? (yes/no) [yes] no
3744
4984
  <a id="__codelineno-1-11" name="__codelineno-1-11" href="#__codelineno-1-11"></a>Would you like to define your development dependencies interactively? (yes/no) [yes] no
@@ -3752,7 +4992,7 @@ Please see the <a href="../administration/nautobot-server.html#startplugin">Naut
3752
4992
  <a id="__codelineno-1-19" name="__codelineno-1-19" href="#__codelineno-1-19"></a>license = &quot;Apache 2.0&quot;
3753
4993
  <a id="__codelineno-1-20" name="__codelineno-1-20" href="#__codelineno-1-20"></a>
3754
4994
  <a id="__codelineno-1-21" name="__codelineno-1-21" href="#__codelineno-1-21"></a>[tool.poetry.dependencies]
3755
- <a id="__codelineno-1-22" name="__codelineno-1-22" href="#__codelineno-1-22"></a>python = &quot;^3.7&quot;
4995
+ <a id="__codelineno-1-22" name="__codelineno-1-22" href="#__codelineno-1-22"></a>python = &quot;^3.8&quot;
3756
4996
  <a id="__codelineno-1-23" name="__codelineno-1-23" href="#__codelineno-1-23"></a>
3757
4997
  <a id="__codelineno-1-24" name="__codelineno-1-24" href="#__codelineno-1-24"></a>[tool.poetry.dev-dependencies]
3758
4998
  <a id="__codelineno-1-25" name="__codelineno-1-25" href="#__codelineno-1-25"></a>
@@ -3834,11 +5074,6 @@ Please see the <a href="../administration/nautobot-server.html#startplugin">Naut
3834
5074
  <td>Base path to use for app URLs</td>
3835
5075
  </tr>
3836
5076
  <tr>
3837
- <td><code>caching_config</code></td>
3838
- <td><code>{"*":{"ops":"all"}}</code></td>
3839
- <td>App-specific <a href="https://github.com/Suor/django-cacheops#setup">query caching configuration</a></td>
3840
- </tr>
3841
- <tr>
3842
5077
  <td><code>config_view_name</code></td>
3843
5078
  <td><code>None</code></td>
3844
5079
  <td><a href="#adding-links-to-the-installed-apps-view">URL name</a> for a "configuration" view defined by this app</td>
@@ -3899,6 +5134,10 @@ Please see the <a href="../administration/nautobot-server.html#startplugin">Naut
3899
5134
  <p class="admonition-title">Added in version 2.0.0</p>
3900
5135
  <p>Support for the <code>searchable_models</code> and <code>constance_config</code> attributes were added.</p>
3901
5136
  </div>
5137
+ <div class="admonition version-removed">
5138
+ <p class="admonition-title">Removed in version 2.0.0</p>
5139
+ <p>Support for <code>caching_config</code> was removed with the removal of <code>django-cacheops</code>.</p>
5140
+ </div>
3902
5141
  <div class="admonition note">
3903
5142
  <p class="admonition-title">Note</p>
3904
5143
  <p>All <code>required_settings</code> must be configured in <code>PLUGINS_CONFIG</code> in <code>nautobot_config.py</code> before the app can be used.</p>
@@ -4139,7 +5378,11 @@ Please see the <a href="../administration/nautobot-server.html#startplugin">Naut
4139
5378
  </code></pre></div>
4140
5379
  <h3 id="adding-navigation-menu-items">Adding Navigation Menu Items<a class="headerlink" href="#adding-navigation-menu-items" title="Permanent link">&para;</a></h3>
4141
5380
  <p>Apps can extend the existing navigation bar layout. By default, Nautobot looks for a <code>menu_items</code> list inside of <code>navigation.py</code>. (This can be overridden by setting <code>menu_items</code> to a custom value on the app's <code>NautobotAppConfig</code>.)</p>
4142
- <p>Using a key and weight system, a developer can integrate the app's menu additions amongst existing menu tabs, groups, items and buttons, and/or create entirely new menus as desired.</p>
5381
+ <p>Using a key and weight system, a developer can integrate the app's menu additions amongst existing menu tabs, groups, and items.</p>
5382
+ <div class="admonition version-removed">
5383
+ <p class="admonition-title">Removed in version 2.0.0</p>
5384
+ <p>As part of the Nautobot 2.0 UI redesign, the option for apps to add entirely new top-level menu "tabs" has been removed. Additionally, buttons can no longer be added to menu items.</p>
5385
+ </div>
4143
5386
  <p>More documentation and examples can be found in the <a href="../development/navigation-menu.html">Navigation Menu</a> guide.</p>
4144
5387
  <div class="admonition tip">
4145
5388
  <p class="admonition-title">Tip</p>
@@ -4203,6 +5446,44 @@ namedtuple to assist in the configurations.</p>
4203
5446
  <p class="admonition-title">Warning</p>
4204
5447
  <p>Do not store secrets in the constance_config, instead use Nautobot <a href="../models/extras/secret.html">Secrets</a>.</p>
4205
5448
  </div>
5449
+ <h3 id="overriding-default-model-views-in-nautobot-apps">Overriding Default Model Views in Nautobot Apps<a class="headerlink" href="#overriding-default-model-views-in-nautobot-apps" title="Permanent link">&para;</a></h3>
5450
+ <div class="admonition version-added">
5451
+ <p class="admonition-title">Added in version 2.0.0</p>
5452
+ </div>
5453
+ <p>In UI 2.0, Nautobot provides default model views (<code>ObjectListView</code>, <code>ObjectRetrieveView</code> and etc) for every model including App provided models unless they are explicitly overridden. For example, an app called <code>your_example_app</code> wants to override the default <code>ObjectRetrieveView</code> for its model called <code>YourExampleModel</code> with a customized view called <code>YourExampleView</code>. We need to go to the <code>index.js</code> file located in the <code>your_example_app/ui</code> folder and add a key <code>view_overrides</code> to the <code>app_config</code> dictionary variable.</p>
5454
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a>const app_config = {
5455
+ <a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a> ...
5456
+ <a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a> view_overrides: {}
5457
+ <a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a> ...
5458
+ <a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a>}
5459
+ </code></pre></div>
5460
+ <p>In <code>view_overrides</code>'s dictionary, you need to specify the app and the model you want to override the default view for in this format <code>{app_label}: {model_name}</code>. So in our case, it would be <code>"your-example-app": "your-example-model"</code>.</p>
5461
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a>...
5462
+ <a id="__codelineno-14-2" name="__codelineno-14-2" href="#__codelineno-14-2"></a> view_overrides: {
5463
+ <a id="__codelineno-14-3" name="__codelineno-14-3" href="#__codelineno-14-3"></a> &quot;your-example-app&quot;: &quot;your-example-model&quot;: {}
5464
+ <a id="__codelineno-14-4" name="__codelineno-14-4" href="#__codelineno-14-4"></a> }
5465
+ <a id="__codelineno-14-5" name="__codelineno-14-5" href="#__codelineno-14-5"></a>...
5466
+ </code></pre></div>
5467
+ <p>Finally, you need to specify the default view action you want to override and the new view in this format <code>{view_action}: {new_view}</code>. So in our case, it would be <code>"retrieve": "YourExampleView"</code>:</p>
5468
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a>...
5469
+ <a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a> view_overrides: {
5470
+ <a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a> &quot;your-example-app&quot;: &quot;your-example-model&quot;: {
5471
+ <a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a> &quot;retrieve&quot;: &quot;YourExampleView&quot;
5472
+ <a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a> }
5473
+ <a id="__codelineno-15-6" name="__codelineno-15-6" href="#__codelineno-15-6"></a> }
5474
+ <a id="__codelineno-15-7" name="__codelineno-15-7" href="#__codelineno-15-7"></a>...
5475
+ </code></pre></div>
5476
+ <p>Now if you go to <code>YourExampleModel</code>'s retrieve view, instead of the default <code>ObjectRetrieveView</code>, you will see the customized layout of <code>YourExampleView</code>.</p>
5477
+ <p>If you want to override the default <code>ObjectListView</code> as well for <code>YourExampleModel</code> with <code>YourExampleListView</code>, just append <code>"list": "YourExampleListView"</code> to the <code>"your-example-app": "your-example-model"</code> dictionary.</p>
5478
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a>...
5479
+ <a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a> view_overrides: {
5480
+ <a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a> &quot;your-example-app&quot;: &quot;your-example-model&quot;: {
5481
+ <a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a> &quot;retrieve&quot;: &quot;YourExampleView&quot;,
5482
+ <a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a> &quot;list&quot;: &quot;YourExampleListView&quot;,
5483
+ <a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a> }
5484
+ <a id="__codelineno-16-7" name="__codelineno-16-7" href="#__codelineno-16-7"></a> }
5485
+ <a id="__codelineno-16-8" name="__codelineno-16-8" href="#__codelineno-16-8"></a>...
5486
+ </code></pre></div>
4206
5487
  <h2 id="extending-existing-functionality">Extending Existing Functionality<a class="headerlink" href="#extending-existing-functionality" title="Permanent link">&para;</a></h2>
4207
5488
  <h3 id="adding-jinja2-filters">Adding Jinja2 Filters<a class="headerlink" href="#adding-jinja2-filters" title="Permanent link">&para;</a></h3>
4208
5489
  <div class="admonition version-added">
@@ -4210,122 +5491,122 @@ namedtuple to assist in the configurations.</p>
4210
5491
  </div>
4211
5492
  <p>Apps can define custom Jinja2 filters to be used when rendering templates defined in computed fields. Check out the <a href="https://jinja.palletsprojects.com/en/3.0.x/api/#custom-filters">official Jinja2 documentation</a> on how to create filter functions.</p>
4212
5493
  <p>In the file that defines your filters (by default <code>jinja_filters.py</code>, but configurable in the <code>NautobotAppConfig</code> if desired), you must import the <code>library</code> module from the <code>django_jinja</code> library. Filters must then be decorated with <code>@library.filter</code>. See an example below that defines a filter called <code>leet_speak</code>.</p>
4213
- <div class="highlight"><pre><span></span><code><a id="__codelineno-13-1" name="__codelineno-13-1" href="#__codelineno-13-1"></a><span class="kn">from</span> <span class="nn">django_jinja</span> <span class="kn">import</span> <span class="n">library</span>
4214
- <a id="__codelineno-13-2" name="__codelineno-13-2" href="#__codelineno-13-2"></a>
4215
- <a id="__codelineno-13-3" name="__codelineno-13-3" href="#__codelineno-13-3"></a>
4216
- <a id="__codelineno-13-4" name="__codelineno-13-4" href="#__codelineno-13-4"></a><span class="nd">@library</span><span class="o">.</span><span class="n">filter</span>
4217
- <a id="__codelineno-13-5" name="__codelineno-13-5" href="#__codelineno-13-5"></a><span class="k">def</span> <span class="nf">leet_speak</span><span class="p">(</span><span class="n">input_str</span><span class="p">):</span>
4218
- <a id="__codelineno-13-6" name="__codelineno-13-6" href="#__codelineno-13-6"></a> <span class="n">charset</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;a&quot;</span><span class="p">:</span> <span class="s2">&quot;4&quot;</span><span class="p">,</span> <span class="s2">&quot;e&quot;</span><span class="p">:</span> <span class="s2">&quot;3&quot;</span><span class="p">,</span> <span class="s2">&quot;l&quot;</span><span class="p">:</span> <span class="s2">&quot;1&quot;</span><span class="p">,</span> <span class="s2">&quot;o&quot;</span><span class="p">:</span> <span class="s2">&quot;0&quot;</span><span class="p">,</span> <span class="s2">&quot;s&quot;</span><span class="p">:</span> <span class="s2">&quot;5&quot;</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">:</span> <span class="s2">&quot;7&quot;</span><span class="p">}</span>
4219
- <a id="__codelineno-13-7" name="__codelineno-13-7" href="#__codelineno-13-7"></a> <span class="n">output_str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
4220
- <a id="__codelineno-13-8" name="__codelineno-13-8" href="#__codelineno-13-8"></a> <span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">input_str</span><span class="p">:</span>
4221
- <a id="__codelineno-13-9" name="__codelineno-13-9" href="#__codelineno-13-9"></a> <span class="n">output_str</span> <span class="o">+=</span> <span class="n">charset</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">char</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="n">char</span><span class="p">)</span>
4222
- <a id="__codelineno-13-10" name="__codelineno-13-10" href="#__codelineno-13-10"></a> <span class="k">return</span> <span class="n">output_str</span>
5494
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="kn">from</span> <span class="nn">django_jinja</span> <span class="kn">import</span> <span class="n">library</span>
5495
+ <a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a>
5496
+ <a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a>
5497
+ <a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a><span class="nd">@library</span><span class="o">.</span><span class="n">filter</span>
5498
+ <a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a><span class="k">def</span> <span class="nf">leet_speak</span><span class="p">(</span><span class="n">input_str</span><span class="p">):</span>
5499
+ <a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a> <span class="n">charset</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;a&quot;</span><span class="p">:</span> <span class="s2">&quot;4&quot;</span><span class="p">,</span> <span class="s2">&quot;e&quot;</span><span class="p">:</span> <span class="s2">&quot;3&quot;</span><span class="p">,</span> <span class="s2">&quot;l&quot;</span><span class="p">:</span> <span class="s2">&quot;1&quot;</span><span class="p">,</span> <span class="s2">&quot;o&quot;</span><span class="p">:</span> <span class="s2">&quot;0&quot;</span><span class="p">,</span> <span class="s2">&quot;s&quot;</span><span class="p">:</span> <span class="s2">&quot;5&quot;</span><span class="p">,</span> <span class="s2">&quot;t&quot;</span><span class="p">:</span> <span class="s2">&quot;7&quot;</span><span class="p">}</span>
5500
+ <a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a> <span class="n">output_str</span> <span class="o">=</span> <span class="s2">&quot;&quot;</span>
5501
+ <a id="__codelineno-17-8" name="__codelineno-17-8" href="#__codelineno-17-8"></a> <span class="k">for</span> <span class="n">char</span> <span class="ow">in</span> <span class="n">input_str</span><span class="p">:</span>
5502
+ <a id="__codelineno-17-9" name="__codelineno-17-9" href="#__codelineno-17-9"></a> <span class="n">output_str</span> <span class="o">+=</span> <span class="n">charset</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">char</span><span class="o">.</span><span class="n">lower</span><span class="p">(),</span> <span class="n">char</span><span class="p">)</span>
5503
+ <a id="__codelineno-17-10" name="__codelineno-17-10" href="#__codelineno-17-10"></a> <span class="k">return</span> <span class="n">output_str</span>
4223
5504
  </code></pre></div>
4224
5505
  <p>This filter will then be available for use in computed field templates like so:</p>
4225
- <div class="highlight"><pre><span></span><code><a id="__codelineno-14-1" name="__codelineno-14-1" href="#__codelineno-14-1"></a>{{ &quot;HELLO WORLD&quot; | leet_speak }}
5506
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a>{{ &quot;HELLO WORLD&quot; | leet_speak }}
4226
5507
  </code></pre></div>
4227
5508
  <p>The output of this template results in the string <code>"H3110 W0R1D"</code>.</p>
4228
5509
  <h3 id="including-jobs">Including Jobs<a class="headerlink" href="#including-jobs" title="Permanent link">&para;</a></h3>
4229
5510
  <p>Apps can provide <a href="../additional-features/jobs.html">Jobs</a> to take advantage of all the built-in functionality provided by that feature (user input forms, background execution, results logging and reporting, etc.).</p>
4230
5511
  <p>By default, for each app, Nautobot looks for an iterable named <code>jobs</code> within a <code>jobs.py</code> file. (This can be overridden by setting <code>jobs</code> to a custom value on the app's <code>NautobotAppConfig</code>.) A brief example is below; for more details on Job design and implementation, refer to the Jobs feature documentation.</p>
4231
- <div class="highlight"><pre><span></span><code><a id="__codelineno-15-1" name="__codelineno-15-1" href="#__codelineno-15-1"></a><span class="c1"># jobs.py</span>
4232
- <a id="__codelineno-15-2" name="__codelineno-15-2" href="#__codelineno-15-2"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">Job</span>
4233
- <a id="__codelineno-15-3" name="__codelineno-15-3" href="#__codelineno-15-3"></a>
4234
- <a id="__codelineno-15-4" name="__codelineno-15-4" href="#__codelineno-15-4"></a>
4235
- <a id="__codelineno-15-5" name="__codelineno-15-5" href="#__codelineno-15-5"></a><span class="k">class</span> <span class="nc">CreateDevices</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
4236
- <a id="__codelineno-15-6" name="__codelineno-15-6" href="#__codelineno-15-6"></a> <span class="o">...</span>
4237
- <a id="__codelineno-15-7" name="__codelineno-15-7" href="#__codelineno-15-7"></a>
4238
- <a id="__codelineno-15-8" name="__codelineno-15-8" href="#__codelineno-15-8"></a>
4239
- <a id="__codelineno-15-9" name="__codelineno-15-9" href="#__codelineno-15-9"></a><span class="k">class</span> <span class="nc">DeviceConnectionsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
4240
- <a id="__codelineno-15-10" name="__codelineno-15-10" href="#__codelineno-15-10"></a> <span class="o">...</span>
4241
- <a id="__codelineno-15-11" name="__codelineno-15-11" href="#__codelineno-15-11"></a>
4242
- <a id="__codelineno-15-12" name="__codelineno-15-12" href="#__codelineno-15-12"></a>
4243
- <a id="__codelineno-15-13" name="__codelineno-15-13" href="#__codelineno-15-13"></a><span class="k">class</span> <span class="nc">DeviceIPsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
4244
- <a id="__codelineno-15-14" name="__codelineno-15-14" href="#__codelineno-15-14"></a> <span class="o">...</span>
4245
- <a id="__codelineno-15-15" name="__codelineno-15-15" href="#__codelineno-15-15"></a>
4246
- <a id="__codelineno-15-16" name="__codelineno-15-16" href="#__codelineno-15-16"></a>
4247
- <a id="__codelineno-15-17" name="__codelineno-15-17" href="#__codelineno-15-17"></a><span class="n">jobs</span> <span class="o">=</span> <span class="p">[</span><span class="n">CreateDevices</span><span class="p">,</span> <span class="n">DeviceConnectionsReport</span><span class="p">,</span> <span class="n">DeviceIPsReport</span><span class="p">]</span>
5512
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="c1"># jobs.py</span>
5513
+ <a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a><span class="kn">from</span> <span class="nn">nautobot.extras.jobs</span> <span class="kn">import</span> <span class="n">Job</span>
5514
+ <a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a>
5515
+ <a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a>
5516
+ <a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a><span class="k">class</span> <span class="nc">CreateDevices</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
5517
+ <a id="__codelineno-19-6" name="__codelineno-19-6" href="#__codelineno-19-6"></a> <span class="o">...</span>
5518
+ <a id="__codelineno-19-7" name="__codelineno-19-7" href="#__codelineno-19-7"></a>
5519
+ <a id="__codelineno-19-8" name="__codelineno-19-8" href="#__codelineno-19-8"></a>
5520
+ <a id="__codelineno-19-9" name="__codelineno-19-9" href="#__codelineno-19-9"></a><span class="k">class</span> <span class="nc">DeviceConnectionsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
5521
+ <a id="__codelineno-19-10" name="__codelineno-19-10" href="#__codelineno-19-10"></a> <span class="o">...</span>
5522
+ <a id="__codelineno-19-11" name="__codelineno-19-11" href="#__codelineno-19-11"></a>
5523
+ <a id="__codelineno-19-12" name="__codelineno-19-12" href="#__codelineno-19-12"></a>
5524
+ <a id="__codelineno-19-13" name="__codelineno-19-13" href="#__codelineno-19-13"></a><span class="k">class</span> <span class="nc">DeviceIPsReport</span><span class="p">(</span><span class="n">Job</span><span class="p">):</span>
5525
+ <a id="__codelineno-19-14" name="__codelineno-19-14" href="#__codelineno-19-14"></a> <span class="o">...</span>
5526
+ <a id="__codelineno-19-15" name="__codelineno-19-15" href="#__codelineno-19-15"></a>
5527
+ <a id="__codelineno-19-16" name="__codelineno-19-16" href="#__codelineno-19-16"></a>
5528
+ <a id="__codelineno-19-17" name="__codelineno-19-17" href="#__codelineno-19-17"></a><span class="n">jobs</span> <span class="o">=</span> <span class="p">[</span><span class="n">CreateDevices</span><span class="p">,</span> <span class="n">DeviceConnectionsReport</span><span class="p">,</span> <span class="n">DeviceIPsReport</span><span class="p">]</span>
4248
5529
  </code></pre></div>
4249
5530
  <h3 id="implementing-custom-validators">Implementing Custom Validators<a class="headerlink" href="#implementing-custom-validators" title="Permanent link">&para;</a></h3>
4250
5531
  <p>Apps can register custom validator classes which implement model validation logic to be executed during a model's <code>clean()</code> method. Like template extensions, custom validators are registered to a single model and offer a method which app authors override to implement their validation logic. This is accomplished by subclassing <code>CustomValidator</code> and implementing the <code>clean()</code> method.</p>
4251
5532
  <p>App authors must raise <code>django.core.exceptions.ValidationError</code> within the <code>clean()</code> method to trigger validation error messages which are propagated to the user and prevent saving of the model instance. A convenience method <code>validation_error()</code> may be used to simplify this process. Raising a <code>ValidationError</code> is no different than vanilla Django, and the convenience method will simply pass the provided message through to the exception.</p>
4252
5533
  <p>When a CustomValidator is instantiated, the model instance is assigned to context dictionary using the <code>object</code> key, much like TemplateExtension. E.g. <code>self.context['object']</code>.</p>
4253
5534
  <p>Declared subclasses should be gathered into a list or tuple for integration with Nautobot. By default, Nautobot looks for an iterable named <code>custom_validators</code> within a <code>custom_validators.py</code> file. (This can be overridden by setting <code>custom_validators</code> to a custom value on the app's <code>NautobotAppConfig</code>.) An example is below.</p>
4254
- <div class="highlight"><pre><span></span><code><a id="__codelineno-16-1" name="__codelineno-16-1" href="#__codelineno-16-1"></a><span class="c1"># custom_validators.py</span>
4255
- <a id="__codelineno-16-2" name="__codelineno-16-2" href="#__codelineno-16-2"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">CustomValidator</span>
4256
- <a id="__codelineno-16-3" name="__codelineno-16-3" href="#__codelineno-16-3"></a>
4257
- <a id="__codelineno-16-4" name="__codelineno-16-4" href="#__codelineno-16-4"></a>
4258
- <a id="__codelineno-16-5" name="__codelineno-16-5" href="#__codelineno-16-5"></a><span class="k">class</span> <span class="nc">SiteValidator</span><span class="p">(</span><span class="n">CustomValidator</span><span class="p">):</span>
4259
- <a id="__codelineno-16-6" name="__codelineno-16-6" href="#__codelineno-16-6"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Custom validator for Sites to enforce that they must have a Region.&quot;&quot;&quot;</span>
4260
- <a id="__codelineno-16-7" name="__codelineno-16-7" href="#__codelineno-16-7"></a>
4261
- <a id="__codelineno-16-8" name="__codelineno-16-8" href="#__codelineno-16-8"></a> <span class="n">model</span> <span class="o">=</span> <span class="s1">&#39;dcim.site&#39;</span>
4262
- <a id="__codelineno-16-9" name="__codelineno-16-9" href="#__codelineno-16-9"></a>
4263
- <a id="__codelineno-16-10" name="__codelineno-16-10" href="#__codelineno-16-10"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4264
- <a id="__codelineno-16-11" name="__codelineno-16-11" href="#__codelineno-16-11"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s1">&#39;object&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">region</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4265
- <a id="__codelineno-16-12" name="__codelineno-16-12" href="#__codelineno-16-12"></a> <span class="c1"># Enforce that all sites must be assigned to a region</span>
4266
- <a id="__codelineno-16-13" name="__codelineno-16-13" href="#__codelineno-16-13"></a> <span class="bp">self</span><span class="o">.</span><span class="n">validation_error</span><span class="p">({</span>
4267
- <a id="__codelineno-16-14" name="__codelineno-16-14" href="#__codelineno-16-14"></a> <span class="s2">&quot;region&quot;</span><span class="p">:</span> <span class="s2">&quot;All sites must be assigned to a region&quot;</span>
4268
- <a id="__codelineno-16-15" name="__codelineno-16-15" href="#__codelineno-16-15"></a> <span class="p">})</span>
4269
- <a id="__codelineno-16-16" name="__codelineno-16-16" href="#__codelineno-16-16"></a>
4270
- <a id="__codelineno-16-17" name="__codelineno-16-17" href="#__codelineno-16-17"></a>
4271
- <a id="__codelineno-16-18" name="__codelineno-16-18" href="#__codelineno-16-18"></a><span class="n">custom_validators</span> <span class="o">=</span> <span class="p">[</span><span class="n">SiteValidator</span><span class="p">]</span>
5535
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="c1"># custom_validators.py</span>
5536
+ <a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">CustomValidator</span>
5537
+ <a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a>
5538
+ <a id="__codelineno-20-4" name="__codelineno-20-4" href="#__codelineno-20-4"></a>
5539
+ <a id="__codelineno-20-5" name="__codelineno-20-5" href="#__codelineno-20-5"></a><span class="k">class</span> <span class="nc">SiteValidator</span><span class="p">(</span><span class="n">CustomValidator</span><span class="p">):</span>
5540
+ <a id="__codelineno-20-6" name="__codelineno-20-6" href="#__codelineno-20-6"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Custom validator for Sites to enforce that they must have a Region.&quot;&quot;&quot;</span>
5541
+ <a id="__codelineno-20-7" name="__codelineno-20-7" href="#__codelineno-20-7"></a>
5542
+ <a id="__codelineno-20-8" name="__codelineno-20-8" href="#__codelineno-20-8"></a> <span class="n">model</span> <span class="o">=</span> <span class="s1">&#39;dcim.site&#39;</span>
5543
+ <a id="__codelineno-20-9" name="__codelineno-20-9" href="#__codelineno-20-9"></a>
5544
+ <a id="__codelineno-20-10" name="__codelineno-20-10" href="#__codelineno-20-10"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5545
+ <a id="__codelineno-20-11" name="__codelineno-20-11" href="#__codelineno-20-11"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">context</span><span class="p">[</span><span class="s1">&#39;object&#39;</span><span class="p">]</span><span class="o">.</span><span class="n">region</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
5546
+ <a id="__codelineno-20-12" name="__codelineno-20-12" href="#__codelineno-20-12"></a> <span class="c1"># Enforce that all sites must be assigned to a region</span>
5547
+ <a id="__codelineno-20-13" name="__codelineno-20-13" href="#__codelineno-20-13"></a> <span class="bp">self</span><span class="o">.</span><span class="n">validation_error</span><span class="p">({</span>
5548
+ <a id="__codelineno-20-14" name="__codelineno-20-14" href="#__codelineno-20-14"></a> <span class="s2">&quot;region&quot;</span><span class="p">:</span> <span class="s2">&quot;All sites must be assigned to a region&quot;</span>
5549
+ <a id="__codelineno-20-15" name="__codelineno-20-15" href="#__codelineno-20-15"></a> <span class="p">})</span>
5550
+ <a id="__codelineno-20-16" name="__codelineno-20-16" href="#__codelineno-20-16"></a>
5551
+ <a id="__codelineno-20-17" name="__codelineno-20-17" href="#__codelineno-20-17"></a>
5552
+ <a id="__codelineno-20-18" name="__codelineno-20-18" href="#__codelineno-20-18"></a><span class="n">custom_validators</span> <span class="o">=</span> <span class="p">[</span><span class="n">SiteValidator</span><span class="p">]</span>
4272
5553
  </code></pre></div>
4273
5554
  <h3 id="loading-data-from-a-git-repository">Loading Data from a Git Repository<a class="headerlink" href="#loading-data-from-a-git-repository" title="Permanent link">&para;</a></h3>
4274
5555
  <p>It's possible for an app to register additional types of data that can be provided by a <a href="../models/extras/gitrepository.html">Git repository</a> and be automatically notified when such a repository is refreshed with new data. By default, Nautobot looks for an iterable named <code>datasource_contents</code> within a <code>datasources.py</code> file. (This can be overridden by setting <code>datasource_contents</code> to a custom value on the app's <code>NautobotAppConfig</code>.) An example is below.</p>
4275
- <div class="highlight"><pre><span></span><code><a id="__codelineno-17-1" name="__codelineno-17-1" href="#__codelineno-17-1"></a><span class="c1"># datasources.py</span>
4276
- <a id="__codelineno-17-2" name="__codelineno-17-2" href="#__codelineno-17-2"></a><span class="kn">import</span> <span class="nn">yaml</span>
4277
- <a id="__codelineno-17-3" name="__codelineno-17-3" href="#__codelineno-17-3"></a><span class="kn">import</span> <span class="nn">os</span>
4278
- <a id="__codelineno-17-4" name="__codelineno-17-4" href="#__codelineno-17-4"></a>
4279
- <a id="__codelineno-17-5" name="__codelineno-17-5" href="#__codelineno-17-5"></a><span class="kn">from</span> <span class="nn">nautobot.extras.choices</span> <span class="kn">import</span> <span class="n">LogLevelChoices</span>
4280
- <a id="__codelineno-17-6" name="__codelineno-17-6" href="#__codelineno-17-6"></a><span class="kn">from</span> <span class="nn">nautobot.apps.datasources</span> <span class="kn">import</span> <span class="n">DatasourceContent</span>
4281
- <a id="__codelineno-17-7" name="__codelineno-17-7" href="#__codelineno-17-7"></a>
4282
- <a id="__codelineno-17-8" name="__codelineno-17-8" href="#__codelineno-17-8"></a><span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Animal</span>
4283
- <a id="__codelineno-17-9" name="__codelineno-17-9" href="#__codelineno-17-9"></a>
4284
- <a id="__codelineno-17-10" name="__codelineno-17-10" href="#__codelineno-17-10"></a>
4285
- <a id="__codelineno-17-11" name="__codelineno-17-11" href="#__codelineno-17-11"></a><span class="k">def</span> <span class="nf">refresh_git_animals</span><span class="p">(</span><span class="n">repository_record</span><span class="p">,</span> <span class="n">job_result</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
4286
- <a id="__codelineno-17-12" name="__codelineno-17-12" href="#__codelineno-17-12"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Callback for GitRepository updates - refresh Animals managed by it.&quot;&quot;&quot;</span>
4287
- <a id="__codelineno-17-13" name="__codelineno-17-13" href="#__codelineno-17-13"></a> <span class="k">if</span> <span class="s1">&#39;nautobot_animal_sounds.Animal&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">repository_record</span><span class="o">.</span><span class="n">provided_contents</span> <span class="ow">or</span> <span class="n">delete</span><span class="p">:</span>
4288
- <a id="__codelineno-17-14" name="__codelineno-17-14" href="#__codelineno-17-14"></a> <span class="c1"># This repository is defined not to provide Animal records.</span>
4289
- <a id="__codelineno-17-15" name="__codelineno-17-15" href="#__codelineno-17-15"></a> <span class="c1"># In a more complete worked example, we might want to iterate over any</span>
4290
- <a id="__codelineno-17-16" name="__codelineno-17-16" href="#__codelineno-17-16"></a> <span class="c1"># Animals that might have been previously created by this GitRepository</span>
4291
- <a id="__codelineno-17-17" name="__codelineno-17-17" href="#__codelineno-17-17"></a> <span class="c1"># and ensure their deletion, but for now this is a no-op.</span>
4292
- <a id="__codelineno-17-18" name="__codelineno-17-18" href="#__codelineno-17-18"></a> <span class="k">return</span>
4293
- <a id="__codelineno-17-19" name="__codelineno-17-19" href="#__codelineno-17-19"></a>
4294
- <a id="__codelineno-17-20" name="__codelineno-17-20" href="#__codelineno-17-20"></a> <span class="c1"># We have decided that a Git repository can provide YAML files in a</span>
4295
- <a id="__codelineno-17-21" name="__codelineno-17-21" href="#__codelineno-17-21"></a> <span class="c1"># /animals/ directory at the repository root.</span>
4296
- <a id="__codelineno-17-22" name="__codelineno-17-22" href="#__codelineno-17-22"></a> <span class="n">animal_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">repository_record</span><span class="o">.</span><span class="n">filesystem_path</span><span class="p">,</span> <span class="s1">&#39;animals&#39;</span><span class="p">)</span>
4297
- <a id="__codelineno-17-23" name="__codelineno-17-23" href="#__codelineno-17-23"></a> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">animal_path</span><span class="p">):</span>
4298
- <a id="__codelineno-17-24" name="__codelineno-17-24" href="#__codelineno-17-24"></a> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">animal_path</span><span class="p">,</span> <span class="n">filename</span><span class="p">))</span> <span class="k">as</span> <span class="n">fd</span><span class="p">:</span>
4299
- <a id="__codelineno-17-25" name="__codelineno-17-25" href="#__codelineno-17-25"></a> <span class="n">animal_data</span> <span class="o">=</span> <span class="n">yaml</span><span class="o">.</span><span class="n">safe_load</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span>
4300
- <a id="__codelineno-17-26" name="__codelineno-17-26" href="#__codelineno-17-26"></a>
4301
- <a id="__codelineno-17-27" name="__codelineno-17-27" href="#__codelineno-17-27"></a> <span class="c1"># Create or update an Animal record based on the provided data</span>
4302
- <a id="__codelineno-17-28" name="__codelineno-17-28" href="#__codelineno-17-28"></a> <span class="n">animal_record</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
4303
- <a id="__codelineno-17-29" name="__codelineno-17-29" href="#__codelineno-17-29"></a> <span class="n">name</span><span class="o">=</span><span class="n">animal_data</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
4304
- <a id="__codelineno-17-30" name="__codelineno-17-30" href="#__codelineno-17-30"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;sound&#39;</span><span class="p">:</span> <span class="n">animal_data</span><span class="p">[</span><span class="s1">&#39;sound&#39;</span><span class="p">]}</span>
4305
- <a id="__codelineno-17-31" name="__codelineno-17-31" href="#__codelineno-17-31"></a> <span class="p">)</span>
4306
- <a id="__codelineno-17-32" name="__codelineno-17-32" href="#__codelineno-17-32"></a>
4307
- <a id="__codelineno-17-33" name="__codelineno-17-33" href="#__codelineno-17-33"></a> <span class="c1"># Record the outcome in the JobResult record</span>
4308
- <a id="__codelineno-17-34" name="__codelineno-17-34" href="#__codelineno-17-34"></a> <span class="n">job_result</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
4309
- <a id="__codelineno-17-35" name="__codelineno-17-35" href="#__codelineno-17-35"></a> <span class="s2">&quot;Successfully created/updated animal&quot;</span><span class="p">,</span>
4310
- <a id="__codelineno-17-36" name="__codelineno-17-36" href="#__codelineno-17-36"></a> <span class="n">obj</span><span class="o">=</span><span class="n">animal_record</span><span class="p">,</span>
4311
- <a id="__codelineno-17-37" name="__codelineno-17-37" href="#__codelineno-17-37"></a> <span class="n">level_choice</span><span class="o">=</span><span class="n">LogLevelChoices</span><span class="o">.</span><span class="n">LOG_SUCCESS</span><span class="p">,</span>
4312
- <a id="__codelineno-17-38" name="__codelineno-17-38" href="#__codelineno-17-38"></a> <span class="n">grouping</span><span class="o">=</span><span class="s2">&quot;animals&quot;</span><span class="p">,</span>
4313
- <a id="__codelineno-17-39" name="__codelineno-17-39" href="#__codelineno-17-39"></a> <span class="p">)</span>
4314
- <a id="__codelineno-17-40" name="__codelineno-17-40" href="#__codelineno-17-40"></a>
4315
- <a id="__codelineno-17-41" name="__codelineno-17-41" href="#__codelineno-17-41"></a>
4316
- <a id="__codelineno-17-42" name="__codelineno-17-42" href="#__codelineno-17-42"></a><span class="c1"># Register that Animal records can be loaded from a Git repository,</span>
4317
- <a id="__codelineno-17-43" name="__codelineno-17-43" href="#__codelineno-17-43"></a><span class="c1"># and register the callback function used to do so</span>
4318
- <a id="__codelineno-17-44" name="__codelineno-17-44" href="#__codelineno-17-44"></a><span class="n">datasource_contents</span> <span class="o">=</span> <span class="p">[</span>
4319
- <a id="__codelineno-17-45" name="__codelineno-17-45" href="#__codelineno-17-45"></a> <span class="p">(</span>
4320
- <a id="__codelineno-17-46" name="__codelineno-17-46" href="#__codelineno-17-46"></a> <span class="s1">&#39;extras.gitrepository&#39;</span><span class="p">,</span> <span class="c1"># datasource class we are registering for</span>
4321
- <a id="__codelineno-17-47" name="__codelineno-17-47" href="#__codelineno-17-47"></a> <span class="n">DatasourceContent</span><span class="p">(</span>
4322
- <a id="__codelineno-17-48" name="__codelineno-17-48" href="#__codelineno-17-48"></a> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;animals&#39;</span><span class="p">,</span> <span class="c1"># human-readable name to display in the UI</span>
4323
- <a id="__codelineno-17-49" name="__codelineno-17-49" href="#__codelineno-17-49"></a> <span class="n">content_identifier</span><span class="o">=</span><span class="s1">&#39;nautobot_animal_sounds.animal&#39;</span><span class="p">,</span> <span class="c1"># internal slug to identify the data type</span>
4324
- <a id="__codelineno-17-50" name="__codelineno-17-50" href="#__codelineno-17-50"></a> <span class="n">icon</span><span class="o">=</span><span class="s1">&#39;mdi-paw&#39;</span><span class="p">,</span> <span class="c1"># Material Design Icons icon to use in UI</span>
4325
- <a id="__codelineno-17-51" name="__codelineno-17-51" href="#__codelineno-17-51"></a> <span class="n">callback</span><span class="o">=</span><span class="n">refresh_git_animals</span><span class="p">,</span> <span class="c1"># callback function on GitRepository refresh</span>
4326
- <a id="__codelineno-17-52" name="__codelineno-17-52" href="#__codelineno-17-52"></a> <span class="p">)</span>
4327
- <a id="__codelineno-17-53" name="__codelineno-17-53" href="#__codelineno-17-53"></a> <span class="p">)</span>
4328
- <a id="__codelineno-17-54" name="__codelineno-17-54" href="#__codelineno-17-54"></a><span class="p">]</span>
5556
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="c1"># datasources.py</span>
5557
+ <a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a><span class="kn">import</span> <span class="nn">yaml</span>
5558
+ <a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a><span class="kn">import</span> <span class="nn">os</span>
5559
+ <a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a>
5560
+ <a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a><span class="kn">from</span> <span class="nn">nautobot.extras.choices</span> <span class="kn">import</span> <span class="n">LogLevelChoices</span>
5561
+ <a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a><span class="kn">from</span> <span class="nn">nautobot.apps.datasources</span> <span class="kn">import</span> <span class="n">DatasourceContent</span>
5562
+ <a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a>
5563
+ <a id="__codelineno-21-8" name="__codelineno-21-8" href="#__codelineno-21-8"></a><span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Animal</span>
5564
+ <a id="__codelineno-21-9" name="__codelineno-21-9" href="#__codelineno-21-9"></a>
5565
+ <a id="__codelineno-21-10" name="__codelineno-21-10" href="#__codelineno-21-10"></a>
5566
+ <a id="__codelineno-21-11" name="__codelineno-21-11" href="#__codelineno-21-11"></a><span class="k">def</span> <span class="nf">refresh_git_animals</span><span class="p">(</span><span class="n">repository_record</span><span class="p">,</span> <span class="n">job_result</span><span class="p">,</span> <span class="n">delete</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
5567
+ <a id="__codelineno-21-12" name="__codelineno-21-12" href="#__codelineno-21-12"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Callback for GitRepository updates - refresh Animals managed by it.&quot;&quot;&quot;</span>
5568
+ <a id="__codelineno-21-13" name="__codelineno-21-13" href="#__codelineno-21-13"></a> <span class="k">if</span> <span class="s1">&#39;nautobot_animal_sounds.Animal&#39;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">repository_record</span><span class="o">.</span><span class="n">provided_contents</span> <span class="ow">or</span> <span class="n">delete</span><span class="p">:</span>
5569
+ <a id="__codelineno-21-14" name="__codelineno-21-14" href="#__codelineno-21-14"></a> <span class="c1"># This repository is defined not to provide Animal records.</span>
5570
+ <a id="__codelineno-21-15" name="__codelineno-21-15" href="#__codelineno-21-15"></a> <span class="c1"># In a more complete worked example, we might want to iterate over any</span>
5571
+ <a id="__codelineno-21-16" name="__codelineno-21-16" href="#__codelineno-21-16"></a> <span class="c1"># Animals that might have been previously created by this GitRepository</span>
5572
+ <a id="__codelineno-21-17" name="__codelineno-21-17" href="#__codelineno-21-17"></a> <span class="c1"># and ensure their deletion, but for now this is a no-op.</span>
5573
+ <a id="__codelineno-21-18" name="__codelineno-21-18" href="#__codelineno-21-18"></a> <span class="k">return</span>
5574
+ <a id="__codelineno-21-19" name="__codelineno-21-19" href="#__codelineno-21-19"></a>
5575
+ <a id="__codelineno-21-20" name="__codelineno-21-20" href="#__codelineno-21-20"></a> <span class="c1"># We have decided that a Git repository can provide YAML files in a</span>
5576
+ <a id="__codelineno-21-21" name="__codelineno-21-21" href="#__codelineno-21-21"></a> <span class="c1"># /animals/ directory at the repository root.</span>
5577
+ <a id="__codelineno-21-22" name="__codelineno-21-22" href="#__codelineno-21-22"></a> <span class="n">animal_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">repository_record</span><span class="o">.</span><span class="n">filesystem_path</span><span class="p">,</span> <span class="s1">&#39;animals&#39;</span><span class="p">)</span>
5578
+ <a id="__codelineno-21-23" name="__codelineno-21-23" href="#__codelineno-21-23"></a> <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">os</span><span class="o">.</span><span class="n">listdir</span><span class="p">(</span><span class="n">animal_path</span><span class="p">):</span>
5579
+ <a id="__codelineno-21-24" name="__codelineno-21-24" href="#__codelineno-21-24"></a> <span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">animal_path</span><span class="p">,</span> <span class="n">filename</span><span class="p">))</span> <span class="k">as</span> <span class="n">fd</span><span class="p">:</span>
5580
+ <a id="__codelineno-21-25" name="__codelineno-21-25" href="#__codelineno-21-25"></a> <span class="n">animal_data</span> <span class="o">=</span> <span class="n">yaml</span><span class="o">.</span><span class="n">safe_load</span><span class="p">(</span><span class="n">fd</span><span class="p">)</span>
5581
+ <a id="__codelineno-21-26" name="__codelineno-21-26" href="#__codelineno-21-26"></a>
5582
+ <a id="__codelineno-21-27" name="__codelineno-21-27" href="#__codelineno-21-27"></a> <span class="c1"># Create or update an Animal record based on the provided data</span>
5583
+ <a id="__codelineno-21-28" name="__codelineno-21-28" href="#__codelineno-21-28"></a> <span class="n">animal_record</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
5584
+ <a id="__codelineno-21-29" name="__codelineno-21-29" href="#__codelineno-21-29"></a> <span class="n">name</span><span class="o">=</span><span class="n">animal_data</span><span class="p">[</span><span class="s1">&#39;name&#39;</span><span class="p">],</span>
5585
+ <a id="__codelineno-21-30" name="__codelineno-21-30" href="#__codelineno-21-30"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="s1">&#39;sound&#39;</span><span class="p">:</span> <span class="n">animal_data</span><span class="p">[</span><span class="s1">&#39;sound&#39;</span><span class="p">]}</span>
5586
+ <a id="__codelineno-21-31" name="__codelineno-21-31" href="#__codelineno-21-31"></a> <span class="p">)</span>
5587
+ <a id="__codelineno-21-32" name="__codelineno-21-32" href="#__codelineno-21-32"></a>
5588
+ <a id="__codelineno-21-33" name="__codelineno-21-33" href="#__codelineno-21-33"></a> <span class="c1"># Record the outcome in the JobResult record</span>
5589
+ <a id="__codelineno-21-34" name="__codelineno-21-34" href="#__codelineno-21-34"></a> <span class="n">job_result</span><span class="o">.</span><span class="n">log</span><span class="p">(</span>
5590
+ <a id="__codelineno-21-35" name="__codelineno-21-35" href="#__codelineno-21-35"></a> <span class="s2">&quot;Successfully created/updated animal&quot;</span><span class="p">,</span>
5591
+ <a id="__codelineno-21-36" name="__codelineno-21-36" href="#__codelineno-21-36"></a> <span class="n">obj</span><span class="o">=</span><span class="n">animal_record</span><span class="p">,</span>
5592
+ <a id="__codelineno-21-37" name="__codelineno-21-37" href="#__codelineno-21-37"></a> <span class="n">level_choice</span><span class="o">=</span><span class="n">LogLevelChoices</span><span class="o">.</span><span class="n">LOG_INFO</span><span class="p">,</span>
5593
+ <a id="__codelineno-21-38" name="__codelineno-21-38" href="#__codelineno-21-38"></a> <span class="n">grouping</span><span class="o">=</span><span class="s2">&quot;animals&quot;</span><span class="p">,</span>
5594
+ <a id="__codelineno-21-39" name="__codelineno-21-39" href="#__codelineno-21-39"></a> <span class="p">)</span>
5595
+ <a id="__codelineno-21-40" name="__codelineno-21-40" href="#__codelineno-21-40"></a>
5596
+ <a id="__codelineno-21-41" name="__codelineno-21-41" href="#__codelineno-21-41"></a>
5597
+ <a id="__codelineno-21-42" name="__codelineno-21-42" href="#__codelineno-21-42"></a><span class="c1"># Register that Animal records can be loaded from a Git repository,</span>
5598
+ <a id="__codelineno-21-43" name="__codelineno-21-43" href="#__codelineno-21-43"></a><span class="c1"># and register the callback function used to do so</span>
5599
+ <a id="__codelineno-21-44" name="__codelineno-21-44" href="#__codelineno-21-44"></a><span class="n">datasource_contents</span> <span class="o">=</span> <span class="p">[</span>
5600
+ <a id="__codelineno-21-45" name="__codelineno-21-45" href="#__codelineno-21-45"></a> <span class="p">(</span>
5601
+ <a id="__codelineno-21-46" name="__codelineno-21-46" href="#__codelineno-21-46"></a> <span class="s1">&#39;extras.gitrepository&#39;</span><span class="p">,</span> <span class="c1"># datasource class we are registering for</span>
5602
+ <a id="__codelineno-21-47" name="__codelineno-21-47" href="#__codelineno-21-47"></a> <span class="n">DatasourceContent</span><span class="p">(</span>
5603
+ <a id="__codelineno-21-48" name="__codelineno-21-48" href="#__codelineno-21-48"></a> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;animals&#39;</span><span class="p">,</span> <span class="c1"># human-readable name to display in the UI</span>
5604
+ <a id="__codelineno-21-49" name="__codelineno-21-49" href="#__codelineno-21-49"></a> <span class="n">content_identifier</span><span class="o">=</span><span class="s1">&#39;nautobot_animal_sounds.animal&#39;</span><span class="p">,</span> <span class="c1"># internal slug to identify the data type</span>
5605
+ <a id="__codelineno-21-50" name="__codelineno-21-50" href="#__codelineno-21-50"></a> <span class="n">icon</span><span class="o">=</span><span class="s1">&#39;mdi-paw&#39;</span><span class="p">,</span> <span class="c1"># Material Design Icons icon to use in UI</span>
5606
+ <a id="__codelineno-21-51" name="__codelineno-21-51" href="#__codelineno-21-51"></a> <span class="n">callback</span><span class="o">=</span><span class="n">refresh_git_animals</span><span class="p">,</span> <span class="c1"># callback function on GitRepository refresh</span>
5607
+ <a id="__codelineno-21-52" name="__codelineno-21-52" href="#__codelineno-21-52"></a> <span class="p">)</span>
5608
+ <a id="__codelineno-21-53" name="__codelineno-21-53" href="#__codelineno-21-53"></a> <span class="p">)</span>
5609
+ <a id="__codelineno-21-54" name="__codelineno-21-54" href="#__codelineno-21-54"></a><span class="p">]</span>
4329
5610
  </code></pre></div>
4330
5611
  <p>With this code, once your app is installed, the Git repository creation/editing UI will now include "Animals" as an option for the type(s) of data that a given repository may provide. If this option is selected for a given Git repository, your <code>refresh_git_animals</code> function will be automatically called when the repository is synced.</p>
4331
5612
  <h3 id="populating-extensibility-features">Populating Extensibility Features<a class="headerlink" href="#populating-extensibility-features" title="Permanent link">&para;</a></h3>
@@ -4335,47 +5616,47 @@ namedtuple to assist in the configurations.</p>
4335
5616
  <p>In many cases, an app may wish to make use of Nautobot's various extensibility features, such as <a href="../models/extras/customfield.html">custom fields</a> or <a href="../models/extras/relationship.html">relationships</a>. It can be useful for an app to automatically create a custom field definition or relationship definition as a consequence of being installed and activated, so that everyday usage of the app can rely upon these definitions to be present.</p>
4336
5617
  <p>To make this possible, Nautobot provides a custom <a href="https://docs.djangoproject.com/en/stable/topics/signals/">signal</a>, <code>nautobot_database_ready</code>, that apps can register to listen for. This signal is triggered when <code>nautobot-server migrate</code> or <code>nautobot-server post_upgrade</code> is run after installing an app, and provides an opportunity for the app to make any desired additions to the database at this time.</p>
4337
5618
  <p>For example, maybe we want our app to make use of a Relationship allowing each Site to be linked to our Animal model. We would define our callback function that makes sure this Relationship exists, by convention in a <code>signals.py</code> file:</p>
4338
- <div class="highlight"><pre><span></span><code><a id="__codelineno-18-1" name="__codelineno-18-1" href="#__codelineno-18-1"></a><span class="c1"># signals.py</span>
4339
- <a id="__codelineno-18-2" name="__codelineno-18-2" href="#__codelineno-18-2"></a>
4340
- <a id="__codelineno-18-3" name="__codelineno-18-3" href="#__codelineno-18-3"></a><span class="kn">from</span> <span class="nn">nautobot.extras.choices</span> <span class="kn">import</span> <span class="n">RelationshipTypeChoices</span>
4341
- <a id="__codelineno-18-4" name="__codelineno-18-4" href="#__codelineno-18-4"></a>
4342
- <a id="__codelineno-18-5" name="__codelineno-18-5" href="#__codelineno-18-5"></a><span class="k">def</span> <span class="nf">create_site_to_animal_relationship</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">apps</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
4343
- <a id="__codelineno-18-6" name="__codelineno-18-6" href="#__codelineno-18-6"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Create a Site-to-Animal Relationship if it doesn&#39;t already exist.&quot;&quot;&quot;</span>
4344
- <a id="__codelineno-18-7" name="__codelineno-18-7" href="#__codelineno-18-7"></a> <span class="c1"># Use apps.get_model to look up Nautobot core models</span>
4345
- <a id="__codelineno-18-8" name="__codelineno-18-8" href="#__codelineno-18-8"></a> <span class="n">ContentType</span> <span class="o">=</span> <span class="n">apps</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;contenttypes&quot;</span><span class="p">,</span> <span class="s2">&quot;ContentType&quot;</span><span class="p">)</span>
4346
- <a id="__codelineno-18-9" name="__codelineno-18-9" href="#__codelineno-18-9"></a> <span class="n">Relationship</span> <span class="o">=</span> <span class="n">apps</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;extras&quot;</span><span class="p">,</span> <span class="s2">&quot;Relationship&quot;</span><span class="p">)</span>
4347
- <a id="__codelineno-18-10" name="__codelineno-18-10" href="#__codelineno-18-10"></a> <span class="n">Site</span> <span class="o">=</span> <span class="n">apps</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;dcim&quot;</span><span class="p">,</span> <span class="s2">&quot;Site&quot;</span><span class="p">)</span>
4348
- <a id="__codelineno-18-11" name="__codelineno-18-11" href="#__codelineno-18-11"></a> <span class="c1"># Use sender.get_model to look up models from this app</span>
4349
- <a id="__codelineno-18-12" name="__codelineno-18-12" href="#__codelineno-18-12"></a> <span class="n">Animal</span> <span class="o">=</span> <span class="n">sender</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;Animal&quot;</span><span class="p">)</span>
4350
- <a id="__codelineno-18-13" name="__codelineno-18-13" href="#__codelineno-18-13"></a>
4351
- <a id="__codelineno-18-14" name="__codelineno-18-14" href="#__codelineno-18-14"></a> <span class="c1"># Ensure that the Relationship exists</span>
4352
- <a id="__codelineno-18-15" name="__codelineno-18-15" href="#__codelineno-18-15"></a> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
4353
- <a id="__codelineno-18-16" name="__codelineno-18-16" href="#__codelineno-18-16"></a> <span class="n">slug</span><span class="o">=</span><span class="s2">&quot;site-favorite-animal&quot;</span><span class="p">,</span>
4354
- <a id="__codelineno-18-17" name="__codelineno-18-17" href="#__codelineno-18-17"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span>
4355
- <a id="__codelineno-18-18" name="__codelineno-18-18" href="#__codelineno-18-18"></a> <span class="s2">&quot;name&quot;</span><span class="p">:</span> <span class="s2">&quot;Site&#39;s Favorite Animal&quot;</span><span class="p">,</span>
4356
- <a id="__codelineno-18-19" name="__codelineno-18-19" href="#__codelineno-18-19"></a> <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="n">RelationshipTypeChoices</span><span class="o">.</span><span class="n">TYPE_ONE_TO_MANY</span><span class="p">,</span>
4357
- <a id="__codelineno-18-20" name="__codelineno-18-20" href="#__codelineno-18-20"></a> <span class="s2">&quot;source_type&quot;</span><span class="p">:</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="n">Animal</span><span class="p">),</span>
4358
- <a id="__codelineno-18-21" name="__codelineno-18-21" href="#__codelineno-18-21"></a> <span class="s2">&quot;source_label&quot;</span><span class="p">:</span> <span class="s2">&quot;Sites that love this Animal&quot;</span><span class="p">,</span>
4359
- <a id="__codelineno-18-22" name="__codelineno-18-22" href="#__codelineno-18-22"></a> <span class="s2">&quot;destination_type&quot;</span><span class="p">:</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="n">Site</span><span class="p">),</span>
4360
- <a id="__codelineno-18-23" name="__codelineno-18-23" href="#__codelineno-18-23"></a> <span class="s2">&quot;destination_label&quot;</span><span class="p">:</span> <span class="s2">&quot;Favorite Animal&quot;</span><span class="p">,</span>
4361
- <a id="__codelineno-18-24" name="__codelineno-18-24" href="#__codelineno-18-24"></a> <span class="p">},</span>
4362
- <a id="__codelineno-18-25" name="__codelineno-18-25" href="#__codelineno-18-25"></a> <span class="p">)</span>
5619
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a><span class="c1"># signals.py</span>
5620
+ <a id="__codelineno-22-2" name="__codelineno-22-2" href="#__codelineno-22-2"></a>
5621
+ <a id="__codelineno-22-3" name="__codelineno-22-3" href="#__codelineno-22-3"></a><span class="kn">from</span> <span class="nn">nautobot.extras.choices</span> <span class="kn">import</span> <span class="n">RelationshipTypeChoices</span>
5622
+ <a id="__codelineno-22-4" name="__codelineno-22-4" href="#__codelineno-22-4"></a>
5623
+ <a id="__codelineno-22-5" name="__codelineno-22-5" href="#__codelineno-22-5"></a><span class="k">def</span> <span class="nf">create_site_to_animal_relationship</span><span class="p">(</span><span class="n">sender</span><span class="p">,</span> <span class="n">apps</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
5624
+ <a id="__codelineno-22-6" name="__codelineno-22-6" href="#__codelineno-22-6"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Create a Site-to-Animal Relationship if it doesn&#39;t already exist.&quot;&quot;&quot;</span>
5625
+ <a id="__codelineno-22-7" name="__codelineno-22-7" href="#__codelineno-22-7"></a> <span class="c1"># Use apps.get_model to look up Nautobot core models</span>
5626
+ <a id="__codelineno-22-8" name="__codelineno-22-8" href="#__codelineno-22-8"></a> <span class="n">ContentType</span> <span class="o">=</span> <span class="n">apps</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;contenttypes&quot;</span><span class="p">,</span> <span class="s2">&quot;ContentType&quot;</span><span class="p">)</span>
5627
+ <a id="__codelineno-22-9" name="__codelineno-22-9" href="#__codelineno-22-9"></a> <span class="n">Relationship</span> <span class="o">=</span> <span class="n">apps</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;extras&quot;</span><span class="p">,</span> <span class="s2">&quot;Relationship&quot;</span><span class="p">)</span>
5628
+ <a id="__codelineno-22-10" name="__codelineno-22-10" href="#__codelineno-22-10"></a> <span class="n">Site</span> <span class="o">=</span> <span class="n">apps</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;dcim&quot;</span><span class="p">,</span> <span class="s2">&quot;Site&quot;</span><span class="p">)</span>
5629
+ <a id="__codelineno-22-11" name="__codelineno-22-11" href="#__codelineno-22-11"></a> <span class="c1"># Use sender.get_model to look up models from this app</span>
5630
+ <a id="__codelineno-22-12" name="__codelineno-22-12" href="#__codelineno-22-12"></a> <span class="n">Animal</span> <span class="o">=</span> <span class="n">sender</span><span class="o">.</span><span class="n">get_model</span><span class="p">(</span><span class="s2">&quot;Animal&quot;</span><span class="p">)</span>
5631
+ <a id="__codelineno-22-13" name="__codelineno-22-13" href="#__codelineno-22-13"></a>
5632
+ <a id="__codelineno-22-14" name="__codelineno-22-14" href="#__codelineno-22-14"></a> <span class="c1"># Ensure that the Relationship exists</span>
5633
+ <a id="__codelineno-22-15" name="__codelineno-22-15" href="#__codelineno-22-15"></a> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
5634
+ <a id="__codelineno-22-16" name="__codelineno-22-16" href="#__codelineno-22-16"></a> <span class="n">key</span><span class="o">=</span><span class="s2">&quot;site_favorite_animal&quot;</span><span class="p">,</span>
5635
+ <a id="__codelineno-22-17" name="__codelineno-22-17" href="#__codelineno-22-17"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span>
5636
+ <a id="__codelineno-22-18" name="__codelineno-22-18" href="#__codelineno-22-18"></a> <span class="s2">&quot;label&quot;</span><span class="p">:</span> <span class="s2">&quot;Site&#39;s Favorite Animal&quot;</span><span class="p">,</span>
5637
+ <a id="__codelineno-22-19" name="__codelineno-22-19" href="#__codelineno-22-19"></a> <span class="s2">&quot;type&quot;</span><span class="p">:</span> <span class="n">RelationshipTypeChoices</span><span class="o">.</span><span class="n">TYPE_ONE_TO_MANY</span><span class="p">,</span>
5638
+ <a id="__codelineno-22-20" name="__codelineno-22-20" href="#__codelineno-22-20"></a> <span class="s2">&quot;source_type&quot;</span><span class="p">:</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="n">Animal</span><span class="p">),</span>
5639
+ <a id="__codelineno-22-21" name="__codelineno-22-21" href="#__codelineno-22-21"></a> <span class="s2">&quot;source_label&quot;</span><span class="p">:</span> <span class="s2">&quot;Sites that love this Animal&quot;</span><span class="p">,</span>
5640
+ <a id="__codelineno-22-22" name="__codelineno-22-22" href="#__codelineno-22-22"></a> <span class="s2">&quot;destination_type&quot;</span><span class="p">:</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="n">Site</span><span class="p">),</span>
5641
+ <a id="__codelineno-22-23" name="__codelineno-22-23" href="#__codelineno-22-23"></a> <span class="s2">&quot;destination_label&quot;</span><span class="p">:</span> <span class="s2">&quot;Favorite Animal&quot;</span><span class="p">,</span>
5642
+ <a id="__codelineno-22-24" name="__codelineno-22-24" href="#__codelineno-22-24"></a> <span class="p">},</span>
5643
+ <a id="__codelineno-22-25" name="__codelineno-22-25" href="#__codelineno-22-25"></a> <span class="p">)</span>
4363
5644
  </code></pre></div>
4364
5645
  <p>Then, in the <code>NautobotAppConfig</code> <code>ready()</code> function, we connect this callback function to the <code>nautobot_database_ready</code> signal:</p>
4365
- <div class="highlight"><pre><span></span><code><a id="__codelineno-19-1" name="__codelineno-19-1" href="#__codelineno-19-1"></a><span class="c1"># __init__.py</span>
4366
- <a id="__codelineno-19-2" name="__codelineno-19-2" href="#__codelineno-19-2"></a>
4367
- <a id="__codelineno-19-3" name="__codelineno-19-3" href="#__codelineno-19-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps</span> <span class="kn">import</span> <span class="n">nautobot_database_ready</span><span class="p">,</span> <span class="n">NautobotAppConfig</span>
4368
- <a id="__codelineno-19-4" name="__codelineno-19-4" href="#__codelineno-19-4"></a>
4369
- <a id="__codelineno-19-5" name="__codelineno-19-5" href="#__codelineno-19-5"></a><span class="kn">from</span> <span class="nn">.signals</span> <span class="kn">import</span> <span class="n">create_site_to_animal_relationship</span>
4370
- <a id="__codelineno-19-6" name="__codelineno-19-6" href="#__codelineno-19-6"></a>
4371
- <a id="__codelineno-19-7" name="__codelineno-19-7" href="#__codelineno-19-7"></a><span class="k">class</span> <span class="nc">AnimalSoundsConfig</span><span class="p">(</span><span class="n">NautobotAppConfig</span><span class="p">):</span>
4372
- <a id="__codelineno-19-8" name="__codelineno-19-8" href="#__codelineno-19-8"></a> <span class="c1"># ...</span>
4373
- <a id="__codelineno-19-9" name="__codelineno-19-9" href="#__codelineno-19-9"></a>
4374
- <a id="__codelineno-19-10" name="__codelineno-19-10" href="#__codelineno-19-10"></a> <span class="k">def</span> <span class="nf">ready</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4375
- <a id="__codelineno-19-11" name="__codelineno-19-11" href="#__codelineno-19-11"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">ready</span><span class="p">()</span>
4376
- <a id="__codelineno-19-12" name="__codelineno-19-12" href="#__codelineno-19-12"></a> <span class="n">nautobot_database_ready</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">create_site_to_animal_relationship</span><span class="p">,</span> <span class="n">sender</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
4377
- <a id="__codelineno-19-13" name="__codelineno-19-13" href="#__codelineno-19-13"></a>
4378
- <a id="__codelineno-19-14" name="__codelineno-19-14" href="#__codelineno-19-14"></a><span class="n">config</span> <span class="o">=</span> <span class="n">AnimalSoundsConfig</span>
5646
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a><span class="c1"># __init__.py</span>
5647
+ <a id="__codelineno-23-2" name="__codelineno-23-2" href="#__codelineno-23-2"></a>
5648
+ <a id="__codelineno-23-3" name="__codelineno-23-3" href="#__codelineno-23-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps</span> <span class="kn">import</span> <span class="n">nautobot_database_ready</span><span class="p">,</span> <span class="n">NautobotAppConfig</span>
5649
+ <a id="__codelineno-23-4" name="__codelineno-23-4" href="#__codelineno-23-4"></a>
5650
+ <a id="__codelineno-23-5" name="__codelineno-23-5" href="#__codelineno-23-5"></a><span class="kn">from</span> <span class="nn">.signals</span> <span class="kn">import</span> <span class="n">create_site_to_animal_relationship</span>
5651
+ <a id="__codelineno-23-6" name="__codelineno-23-6" href="#__codelineno-23-6"></a>
5652
+ <a id="__codelineno-23-7" name="__codelineno-23-7" href="#__codelineno-23-7"></a><span class="k">class</span> <span class="nc">AnimalSoundsConfig</span><span class="p">(</span><span class="n">NautobotAppConfig</span><span class="p">):</span>
5653
+ <a id="__codelineno-23-8" name="__codelineno-23-8" href="#__codelineno-23-8"></a> <span class="c1"># ...</span>
5654
+ <a id="__codelineno-23-9" name="__codelineno-23-9" href="#__codelineno-23-9"></a>
5655
+ <a id="__codelineno-23-10" name="__codelineno-23-10" href="#__codelineno-23-10"></a> <span class="k">def</span> <span class="nf">ready</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5656
+ <a id="__codelineno-23-11" name="__codelineno-23-11" href="#__codelineno-23-11"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">ready</span><span class="p">()</span>
5657
+ <a id="__codelineno-23-12" name="__codelineno-23-12" href="#__codelineno-23-12"></a> <span class="n">nautobot_database_ready</span><span class="o">.</span><span class="n">connect</span><span class="p">(</span><span class="n">create_site_to_animal_relationship</span><span class="p">,</span> <span class="n">sender</span><span class="o">=</span><span class="bp">self</span><span class="p">)</span>
5658
+ <a id="__codelineno-23-13" name="__codelineno-23-13" href="#__codelineno-23-13"></a>
5659
+ <a id="__codelineno-23-14" name="__codelineno-23-14" href="#__codelineno-23-14"></a><span class="n">config</span> <span class="o">=</span> <span class="n">AnimalSoundsConfig</span>
4379
5660
  </code></pre></div>
4380
5661
  <p>After writing this code, run <code>nautobot-server migrate</code> or <code>nautobot-server post_upgrade</code>, then restart the Nautobot server, and you should see that this custom Relationship has now been automatically created.</p>
4381
5662
  <h3 id="implementing-secrets-providers">Implementing Secrets Providers<a class="headerlink" href="#implementing-secrets-providers" title="Permanent link">&para;</a></h3>
@@ -4395,48 +5676,48 @@ namedtuple to assist in the configurations.</p>
4395
5676
  <p class="admonition-title">Warning</p>
4396
5677
  <p>This is an intentionally simplistic example and should not be used in practice! Sensitive secret data should never be stored directly in Nautobot's database itself.</p>
4397
5678
  </div>
4398
- <div class="highlight"><pre><span></span><code><a id="__codelineno-20-1" name="__codelineno-20-1" href="#__codelineno-20-1"></a><span class="c1"># secrets.py</span>
4399
- <a id="__codelineno-20-2" name="__codelineno-20-2" href="#__codelineno-20-2"></a><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
4400
- <a id="__codelineno-20-3" name="__codelineno-20-3" href="#__codelineno-20-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps.secrets</span> <span class="kn">import</span> <span class="n">SecretsProvider</span>
4401
- <a id="__codelineno-20-4" name="__codelineno-20-4" href="#__codelineno-20-4"></a><span class="kn">from</span> <span class="nn">nautobot.utilities.forms</span> <span class="kn">import</span> <span class="n">BootstrapMixin</span>
4402
- <a id="__codelineno-20-5" name="__codelineno-20-5" href="#__codelineno-20-5"></a>
4403
- <a id="__codelineno-20-6" name="__codelineno-20-6" href="#__codelineno-20-6"></a>
4404
- <a id="__codelineno-20-7" name="__codelineno-20-7" href="#__codelineno-20-7"></a><span class="k">class</span> <span class="nc">ConstantValueSecretsProvider</span><span class="p">(</span><span class="n">SecretsProvider</span><span class="p">):</span>
4405
- <a id="__codelineno-20-8" name="__codelineno-20-8" href="#__codelineno-20-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4406
- <a id="__codelineno-20-9" name="__codelineno-20-9" href="#__codelineno-20-9"></a><span class="sd"> Example SecretsProvider - this one just returns a user-specified constant value.</span>
4407
- <a id="__codelineno-20-10" name="__codelineno-20-10" href="#__codelineno-20-10"></a>
4408
- <a id="__codelineno-20-11" name="__codelineno-20-11" href="#__codelineno-20-11"></a><span class="sd"> Obviously this is insecure and not something you&#39;d want to actually use!</span>
4409
- <a id="__codelineno-20-12" name="__codelineno-20-12" href="#__codelineno-20-12"></a><span class="sd"> &quot;&quot;&quot;</span>
4410
- <a id="__codelineno-20-13" name="__codelineno-20-13" href="#__codelineno-20-13"></a>
4411
- <a id="__codelineno-20-14" name="__codelineno-20-14" href="#__codelineno-20-14"></a> <span class="n">slug</span> <span class="o">=</span> <span class="s2">&quot;constant-value&quot;</span>
4412
- <a id="__codelineno-20-15" name="__codelineno-20-15" href="#__codelineno-20-15"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;Constant Value&quot;</span>
4413
- <a id="__codelineno-20-16" name="__codelineno-20-16" href="#__codelineno-20-16"></a>
4414
- <a id="__codelineno-20-17" name="__codelineno-20-17" href="#__codelineno-20-17"></a> <span class="k">class</span> <span class="nc">ParametersForm</span><span class="p">(</span><span class="n">BootstrapMixin</span><span class="p">,</span> <span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
4415
- <a id="__codelineno-20-18" name="__codelineno-20-18" href="#__codelineno-20-18"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4416
- <a id="__codelineno-20-19" name="__codelineno-20-19" href="#__codelineno-20-19"></a><span class="sd"> User-friendly form for specifying the required parameters of this provider.</span>
4417
- <a id="__codelineno-20-20" name="__codelineno-20-20" href="#__codelineno-20-20"></a><span class="sd"> &quot;&quot;&quot;</span>
4418
- <a id="__codelineno-20-21" name="__codelineno-20-21" href="#__codelineno-20-21"></a> <span class="n">constant</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span>
4419
- <a id="__codelineno-20-22" name="__codelineno-20-22" href="#__codelineno-20-22"></a> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
4420
- <a id="__codelineno-20-23" name="__codelineno-20-23" href="#__codelineno-20-23"></a> <span class="n">help_text</span><span class="o">=</span><span class="s2">&quot;Constant secret value. &lt;strong&gt;DO NOT USE FOR REAL DATA&lt;/strong&gt;&quot;</span>
4421
- <a id="__codelineno-20-24" name="__codelineno-20-24" href="#__codelineno-20-24"></a> <span class="p">)</span>
4422
- <a id="__codelineno-20-25" name="__codelineno-20-25" href="#__codelineno-20-25"></a>
4423
- <a id="__codelineno-20-26" name="__codelineno-20-26" href="#__codelineno-20-26"></a> <span class="nd">@classmethod</span>
4424
- <a id="__codelineno-20-27" name="__codelineno-20-27" href="#__codelineno-20-27"></a> <span class="k">def</span> <span class="nf">get_value_for_secret</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">secret</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
4425
- <a id="__codelineno-20-28" name="__codelineno-20-28" href="#__codelineno-20-28"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4426
- <a id="__codelineno-20-29" name="__codelineno-20-29" href="#__codelineno-20-29"></a><span class="sd"> Return the value defined in the Secret.parameters &quot;constant&quot; key.</span>
4427
- <a id="__codelineno-20-30" name="__codelineno-20-30" href="#__codelineno-20-30"></a>
4428
- <a id="__codelineno-20-31" name="__codelineno-20-31" href="#__codelineno-20-31"></a><span class="sd"> A more realistic SecretsProvider would make calls to external APIs, etc.,</span>
4429
- <a id="__codelineno-20-32" name="__codelineno-20-32" href="#__codelineno-20-32"></a><span class="sd"> to retrieve a secret from another system as desired.</span>
4430
- <a id="__codelineno-20-33" name="__codelineno-20-33" href="#__codelineno-20-33"></a>
4431
- <a id="__codelineno-20-34" name="__codelineno-20-34" href="#__codelineno-20-34"></a><span class="sd"> Args:</span>
4432
- <a id="__codelineno-20-35" name="__codelineno-20-35" href="#__codelineno-20-35"></a><span class="sd"> secret (nautobot.extras.models.Secret): The secret whose value should be retrieved.</span>
4433
- <a id="__codelineno-20-36" name="__codelineno-20-36" href="#__codelineno-20-36"></a><span class="sd"> obj (object): The object (Django model or similar) providing context for the secret&#39;s</span>
4434
- <a id="__codelineno-20-37" name="__codelineno-20-37" href="#__codelineno-20-37"></a><span class="sd"> parameters.</span>
4435
- <a id="__codelineno-20-38" name="__codelineno-20-38" href="#__codelineno-20-38"></a><span class="sd"> &quot;&quot;&quot;</span>
4436
- <a id="__codelineno-20-39" name="__codelineno-20-39" href="#__codelineno-20-39"></a> <span class="k">return</span> <span class="n">secret</span><span class="o">.</span><span class="n">rendered_parameters</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">obj</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;constant&quot;</span><span class="p">)</span>
4437
- <a id="__codelineno-20-40" name="__codelineno-20-40" href="#__codelineno-20-40"></a>
4438
- <a id="__codelineno-20-41" name="__codelineno-20-41" href="#__codelineno-20-41"></a>
4439
- <a id="__codelineno-20-42" name="__codelineno-20-42" href="#__codelineno-20-42"></a><span class="n">secrets_providers</span> <span class="o">=</span> <span class="p">[</span><span class="n">ConstantValueSecretsProvider</span><span class="p">]</span>
5679
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a><span class="c1"># secrets.py</span>
5680
+ <a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a><span class="kn">from</span> <span class="nn">django</span> <span class="kn">import</span> <span class="n">forms</span>
5681
+ <a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps.secrets</span> <span class="kn">import</span> <span class="n">SecretsProvider</span>
5682
+ <a id="__codelineno-24-4" name="__codelineno-24-4" href="#__codelineno-24-4"></a><span class="kn">from</span> <span class="nn">nautobot.utilities.forms</span> <span class="kn">import</span> <span class="n">BootstrapMixin</span>
5683
+ <a id="__codelineno-24-5" name="__codelineno-24-5" href="#__codelineno-24-5"></a>
5684
+ <a id="__codelineno-24-6" name="__codelineno-24-6" href="#__codelineno-24-6"></a>
5685
+ <a id="__codelineno-24-7" name="__codelineno-24-7" href="#__codelineno-24-7"></a><span class="k">class</span> <span class="nc">ConstantValueSecretsProvider</span><span class="p">(</span><span class="n">SecretsProvider</span><span class="p">):</span>
5686
+ <a id="__codelineno-24-8" name="__codelineno-24-8" href="#__codelineno-24-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5687
+ <a id="__codelineno-24-9" name="__codelineno-24-9" href="#__codelineno-24-9"></a><span class="sd"> Example SecretsProvider - this one just returns a user-specified constant value.</span>
5688
+ <a id="__codelineno-24-10" name="__codelineno-24-10" href="#__codelineno-24-10"></a>
5689
+ <a id="__codelineno-24-11" name="__codelineno-24-11" href="#__codelineno-24-11"></a><span class="sd"> Obviously this is insecure and not something you&#39;d want to actually use!</span>
5690
+ <a id="__codelineno-24-12" name="__codelineno-24-12" href="#__codelineno-24-12"></a><span class="sd"> &quot;&quot;&quot;</span>
5691
+ <a id="__codelineno-24-13" name="__codelineno-24-13" href="#__codelineno-24-13"></a>
5692
+ <a id="__codelineno-24-14" name="__codelineno-24-14" href="#__codelineno-24-14"></a> <span class="n">slug</span> <span class="o">=</span> <span class="s2">&quot;constant-value&quot;</span>
5693
+ <a id="__codelineno-24-15" name="__codelineno-24-15" href="#__codelineno-24-15"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;Constant Value&quot;</span>
5694
+ <a id="__codelineno-24-16" name="__codelineno-24-16" href="#__codelineno-24-16"></a>
5695
+ <a id="__codelineno-24-17" name="__codelineno-24-17" href="#__codelineno-24-17"></a> <span class="k">class</span> <span class="nc">ParametersForm</span><span class="p">(</span><span class="n">BootstrapMixin</span><span class="p">,</span> <span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
5696
+ <a id="__codelineno-24-18" name="__codelineno-24-18" href="#__codelineno-24-18"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5697
+ <a id="__codelineno-24-19" name="__codelineno-24-19" href="#__codelineno-24-19"></a><span class="sd"> User-friendly form for specifying the required parameters of this provider.</span>
5698
+ <a id="__codelineno-24-20" name="__codelineno-24-20" href="#__codelineno-24-20"></a><span class="sd"> &quot;&quot;&quot;</span>
5699
+ <a id="__codelineno-24-21" name="__codelineno-24-21" href="#__codelineno-24-21"></a> <span class="n">constant</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span>
5700
+ <a id="__codelineno-24-22" name="__codelineno-24-22" href="#__codelineno-24-22"></a> <span class="n">required</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span>
5701
+ <a id="__codelineno-24-23" name="__codelineno-24-23" href="#__codelineno-24-23"></a> <span class="n">help_text</span><span class="o">=</span><span class="s2">&quot;Constant secret value. &lt;strong&gt;DO NOT USE FOR REAL DATA&lt;/strong&gt;&quot;</span>
5702
+ <a id="__codelineno-24-24" name="__codelineno-24-24" href="#__codelineno-24-24"></a> <span class="p">)</span>
5703
+ <a id="__codelineno-24-25" name="__codelineno-24-25" href="#__codelineno-24-25"></a>
5704
+ <a id="__codelineno-24-26" name="__codelineno-24-26" href="#__codelineno-24-26"></a> <span class="nd">@classmethod</span>
5705
+ <a id="__codelineno-24-27" name="__codelineno-24-27" href="#__codelineno-24-27"></a> <span class="k">def</span> <span class="nf">get_value_for_secret</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">secret</span><span class="p">,</span> <span class="n">obj</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
5706
+ <a id="__codelineno-24-28" name="__codelineno-24-28" href="#__codelineno-24-28"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5707
+ <a id="__codelineno-24-29" name="__codelineno-24-29" href="#__codelineno-24-29"></a><span class="sd"> Return the value defined in the Secret.parameters &quot;constant&quot; key.</span>
5708
+ <a id="__codelineno-24-30" name="__codelineno-24-30" href="#__codelineno-24-30"></a>
5709
+ <a id="__codelineno-24-31" name="__codelineno-24-31" href="#__codelineno-24-31"></a><span class="sd"> A more realistic SecretsProvider would make calls to external APIs, etc.,</span>
5710
+ <a id="__codelineno-24-32" name="__codelineno-24-32" href="#__codelineno-24-32"></a><span class="sd"> to retrieve a secret from another system as desired.</span>
5711
+ <a id="__codelineno-24-33" name="__codelineno-24-33" href="#__codelineno-24-33"></a>
5712
+ <a id="__codelineno-24-34" name="__codelineno-24-34" href="#__codelineno-24-34"></a><span class="sd"> Args:</span>
5713
+ <a id="__codelineno-24-35" name="__codelineno-24-35" href="#__codelineno-24-35"></a><span class="sd"> secret (nautobot.extras.models.Secret): The secret whose value should be retrieved.</span>
5714
+ <a id="__codelineno-24-36" name="__codelineno-24-36" href="#__codelineno-24-36"></a><span class="sd"> obj (object): The object (Django model or similar) providing context for the secret&#39;s</span>
5715
+ <a id="__codelineno-24-37" name="__codelineno-24-37" href="#__codelineno-24-37"></a><span class="sd"> parameters.</span>
5716
+ <a id="__codelineno-24-38" name="__codelineno-24-38" href="#__codelineno-24-38"></a><span class="sd"> &quot;&quot;&quot;</span>
5717
+ <a id="__codelineno-24-39" name="__codelineno-24-39" href="#__codelineno-24-39"></a> <span class="k">return</span> <span class="n">secret</span><span class="o">.</span><span class="n">rendered_parameters</span><span class="p">(</span><span class="n">obj</span><span class="o">=</span><span class="n">obj</span><span class="p">)</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">&quot;constant&quot;</span><span class="p">)</span>
5718
+ <a id="__codelineno-24-40" name="__codelineno-24-40" href="#__codelineno-24-40"></a>
5719
+ <a id="__codelineno-24-41" name="__codelineno-24-41" href="#__codelineno-24-41"></a>
5720
+ <a id="__codelineno-24-42" name="__codelineno-24-42" href="#__codelineno-24-42"></a><span class="n">secrets_providers</span> <span class="o">=</span> <span class="p">[</span><span class="n">ConstantValueSecretsProvider</span><span class="p">]</span>
4440
5721
  </code></pre></div>
4441
5722
  <p>After installing and enabling your app, you should now be able to navigate to <code>Secrets &gt; Secrets</code> and create a new Secret, at which point <code>"constant-value"</code> should now be available as a new secrets provider to use.</p>
4442
5723
  <h3 id="extending-filters">Extending Filters<a class="headerlink" href="#extending-filters" title="Permanent link">&para;</a></h3>
@@ -4568,61 +5849,61 @@ namedtuple to assist in the configurations.</p>
4568
5849
  </tbody>
4569
5850
  </table>
4570
5851
  <p>Below is an example <code>models.py</code> file containing a basic model with two character fields:</p>
4571
- <div class="highlight"><pre><span></span><code><a id="__codelineno-21-1" name="__codelineno-21-1" href="#__codelineno-21-1"></a><span class="c1"># models.py</span>
4572
- <a id="__codelineno-21-2" name="__codelineno-21-2" href="#__codelineno-21-2"></a><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
4573
- <a id="__codelineno-21-3" name="__codelineno-21-3" href="#__codelineno-21-3"></a>
4574
- <a id="__codelineno-21-4" name="__codelineno-21-4" href="#__codelineno-21-4"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">BaseModel</span>
4575
- <a id="__codelineno-21-5" name="__codelineno-21-5" href="#__codelineno-21-5"></a>
4576
- <a id="__codelineno-21-6" name="__codelineno-21-6" href="#__codelineno-21-6"></a>
4577
- <a id="__codelineno-21-7" name="__codelineno-21-7" href="#__codelineno-21-7"></a><span class="k">class</span> <span class="nc">Animal</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
4578
- <a id="__codelineno-21-8" name="__codelineno-21-8" href="#__codelineno-21-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Base model for animals.&quot;&quot;&quot;</span>
4579
- <a id="__codelineno-21-9" name="__codelineno-21-9" href="#__codelineno-21-9"></a>
4580
- <a id="__codelineno-21-10" name="__codelineno-21-10" href="#__codelineno-21-10"></a> <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
4581
- <a id="__codelineno-21-11" name="__codelineno-21-11" href="#__codelineno-21-11"></a> <span class="n">sound</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
4582
- <a id="__codelineno-21-12" name="__codelineno-21-12" href="#__codelineno-21-12"></a>
4583
- <a id="__codelineno-21-13" name="__codelineno-21-13" href="#__codelineno-21-13"></a> <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4584
- <a id="__codelineno-21-14" name="__codelineno-21-14" href="#__codelineno-21-14"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
4585
- <a id="__codelineno-21-15" name="__codelineno-21-15" href="#__codelineno-21-15"></a>
4586
- <a id="__codelineno-21-16" name="__codelineno-21-16" href="#__codelineno-21-16"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
4587
- <a id="__codelineno-21-17" name="__codelineno-21-17" href="#__codelineno-21-17"></a> <span class="n">unique_together</span> <span class="o">=</span> <span class="p">[[</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;sound&quot;</span><span class="p">]]</span>
5852
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a><span class="c1"># models.py</span>
5853
+ <a id="__codelineno-25-2" name="__codelineno-25-2" href="#__codelineno-25-2"></a><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
5854
+ <a id="__codelineno-25-3" name="__codelineno-25-3" href="#__codelineno-25-3"></a>
5855
+ <a id="__codelineno-25-4" name="__codelineno-25-4" href="#__codelineno-25-4"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">BaseModel</span>
5856
+ <a id="__codelineno-25-5" name="__codelineno-25-5" href="#__codelineno-25-5"></a>
5857
+ <a id="__codelineno-25-6" name="__codelineno-25-6" href="#__codelineno-25-6"></a>
5858
+ <a id="__codelineno-25-7" name="__codelineno-25-7" href="#__codelineno-25-7"></a><span class="k">class</span> <span class="nc">Animal</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
5859
+ <a id="__codelineno-25-8" name="__codelineno-25-8" href="#__codelineno-25-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Base model for animals.&quot;&quot;&quot;</span>
5860
+ <a id="__codelineno-25-9" name="__codelineno-25-9" href="#__codelineno-25-9"></a>
5861
+ <a id="__codelineno-25-10" name="__codelineno-25-10" href="#__codelineno-25-10"></a> <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
5862
+ <a id="__codelineno-25-11" name="__codelineno-25-11" href="#__codelineno-25-11"></a> <span class="n">sound</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
5863
+ <a id="__codelineno-25-12" name="__codelineno-25-12" href="#__codelineno-25-12"></a>
5864
+ <a id="__codelineno-25-13" name="__codelineno-25-13" href="#__codelineno-25-13"></a> <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5865
+ <a id="__codelineno-25-14" name="__codelineno-25-14" href="#__codelineno-25-14"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
5866
+ <a id="__codelineno-25-15" name="__codelineno-25-15" href="#__codelineno-25-15"></a>
5867
+ <a id="__codelineno-25-16" name="__codelineno-25-16" href="#__codelineno-25-16"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
5868
+ <a id="__codelineno-25-17" name="__codelineno-25-17" href="#__codelineno-25-17"></a> <span class="n">unique_together</span> <span class="o">=</span> <span class="p">[[</span><span class="s2">&quot;name&quot;</span><span class="p">,</span> <span class="s2">&quot;sound&quot;</span><span class="p">]]</span>
4588
5869
  </code></pre></div>
4589
5870
  <p>Once you have defined the model(s) for your app, you'll need to create the database schema migrations. A migration file is essentially a set of instructions for manipulating the database to support your new model, or to alter existing models.</p>
4590
5871
  <p>Creating migrations can be done automatically using the <code>nautobot-server makemigrations &lt;app_name&gt;</code> management command, where <code>&lt;app_name&gt;</code> is the name of the Python package for your app (e.g. <code>animal_sounds</code>):</p>
4591
- <div class="highlight"><pre><span></span><code><a id="__codelineno-22-1" name="__codelineno-22-1" href="#__codelineno-22-1"></a>nautobot-server makemigrations nautobot_animal_sounds
5872
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a>nautobot-server makemigrations nautobot_animal_sounds
4592
5873
  </code></pre></div>
4593
5874
  <div class="admonition note">
4594
5875
  <p class="admonition-title">Note</p>
4595
5876
  <p>An app must be installed before it can be used with Django management commands. If you skipped this step above, run <code>poetry install</code> from the app's root directory.</p>
4596
5877
  </div>
4597
- <div class="highlight"><pre><span></span><code><a id="__codelineno-23-1" name="__codelineno-23-1" href="#__codelineno-23-1"></a>nautobot-server makemigrations nautobot_animal_sounds
5878
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a>nautobot-server makemigrations nautobot_animal_sounds
4598
5879
  </code></pre></div>
4599
5880
  <p>Example output:</p>
4600
- <div class="highlight"><pre><span></span><code><a id="__codelineno-24-1" name="__codelineno-24-1" href="#__codelineno-24-1"></a>Migrations for &#39;nautobot_animal_sounds&#39;:
4601
- <a id="__codelineno-24-2" name="__codelineno-24-2" href="#__codelineno-24-2"></a> /home/bjones/animal_sounds/nautobot_animal_sounds/migrations/0001_initial.py
4602
- <a id="__codelineno-24-3" name="__codelineno-24-3" href="#__codelineno-24-3"></a> - Create model Animal
5881
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a>Migrations for &#39;nautobot_animal_sounds&#39;:
5882
+ <a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a> /home/bjones/animal_sounds/nautobot_animal_sounds/migrations/0001_initial.py
5883
+ <a id="__codelineno-28-3" name="__codelineno-28-3" href="#__codelineno-28-3"></a> - Create model Animal
4603
5884
  </code></pre></div>
4604
5885
  <p>Next, apply the migration to the database with the <code>nautobot-server migrate &lt;app_name&gt;</code> command:</p>
4605
- <div class="highlight"><pre><span></span><code><a id="__codelineno-25-1" name="__codelineno-25-1" href="#__codelineno-25-1"></a>nautobot-server migrate nautobot_animal_sounds
5886
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a>nautobot-server migrate nautobot_animal_sounds
4606
5887
  </code></pre></div>
4607
5888
  <p>Example output:</p>
4608
- <div class="highlight"><pre><span></span><code><a id="__codelineno-26-1" name="__codelineno-26-1" href="#__codelineno-26-1"></a>Operations to perform:
4609
- <a id="__codelineno-26-2" name="__codelineno-26-2" href="#__codelineno-26-2"></a> Apply all migrations: nautobot_animal_sounds
4610
- <a id="__codelineno-26-3" name="__codelineno-26-3" href="#__codelineno-26-3"></a>Running migrations:
4611
- <a id="__codelineno-26-4" name="__codelineno-26-4" href="#__codelineno-26-4"></a> Applying nautobot_animal_sounds.0001_initial... OK
5889
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a>Operations to perform:
5890
+ <a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a> Apply all migrations: nautobot_animal_sounds
5891
+ <a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a>Running migrations:
5892
+ <a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a> Applying nautobot_animal_sounds.0001_initial... OK
4612
5893
  </code></pre></div>
4613
5894
  <p>For more background on schema migrations, see the <a href="https://docs.djangoproject.com/en/stable/topics/migrations/">Django documentation</a>.</p>
4614
5895
  <h3 id="using-the-django-admin-interface">Using the Django Admin Interface<a class="headerlink" href="#using-the-django-admin-interface" title="Permanent link">&para;</a></h3>
4615
5896
  <p>Apps can optionally expose their models via Django's built-in <a href="https://docs.djangoproject.com/en/stable/ref/contrib/admin/">administrative interface</a>. This can greatly improve troubleshooting ability, particularly during development. To expose a model, simply register it using Django's <code>admin.register()</code> function. An example <code>admin.py</code> file for the above model is shown below:</p>
4616
- <div class="highlight"><pre><span></span><code><a id="__codelineno-27-1" name="__codelineno-27-1" href="#__codelineno-27-1"></a><span class="c1"># admin.py</span>
4617
- <a id="__codelineno-27-2" name="__codelineno-27-2" href="#__codelineno-27-2"></a><span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
4618
- <a id="__codelineno-27-3" name="__codelineno-27-3" href="#__codelineno-27-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps.admin</span> <span class="kn">import</span> <span class="n">NautobotModelAdmin</span>
4619
- <a id="__codelineno-27-4" name="__codelineno-27-4" href="#__codelineno-27-4"></a>
4620
- <a id="__codelineno-27-5" name="__codelineno-27-5" href="#__codelineno-27-5"></a><span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Animal</span>
4621
- <a id="__codelineno-27-6" name="__codelineno-27-6" href="#__codelineno-27-6"></a>
4622
- <a id="__codelineno-27-7" name="__codelineno-27-7" href="#__codelineno-27-7"></a>
4623
- <a id="__codelineno-27-8" name="__codelineno-27-8" href="#__codelineno-27-8"></a><span class="nd">@admin</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">Animal</span><span class="p">)</span>
4624
- <a id="__codelineno-27-9" name="__codelineno-27-9" href="#__codelineno-27-9"></a><span class="k">class</span> <span class="nc">AnimalAdmin</span><span class="p">(</span><span class="n">NautobotModelAdmin</span><span class="p">):</span>
4625
- <a id="__codelineno-27-10" name="__codelineno-27-10" href="#__codelineno-27-10"></a> <span class="n">list_display</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">,</span> <span class="s1">&#39;sound&#39;</span><span class="p">)</span>
5897
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-31-1" name="__codelineno-31-1" href="#__codelineno-31-1"></a><span class="c1"># admin.py</span>
5898
+ <a id="__codelineno-31-2" name="__codelineno-31-2" href="#__codelineno-31-2"></a><span class="kn">from</span> <span class="nn">django.contrib</span> <span class="kn">import</span> <span class="n">admin</span>
5899
+ <a id="__codelineno-31-3" name="__codelineno-31-3" href="#__codelineno-31-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps.admin</span> <span class="kn">import</span> <span class="n">NautobotModelAdmin</span>
5900
+ <a id="__codelineno-31-4" name="__codelineno-31-4" href="#__codelineno-31-4"></a>
5901
+ <a id="__codelineno-31-5" name="__codelineno-31-5" href="#__codelineno-31-5"></a><span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Animal</span>
5902
+ <a id="__codelineno-31-6" name="__codelineno-31-6" href="#__codelineno-31-6"></a>
5903
+ <a id="__codelineno-31-7" name="__codelineno-31-7" href="#__codelineno-31-7"></a>
5904
+ <a id="__codelineno-31-8" name="__codelineno-31-8" href="#__codelineno-31-8"></a><span class="nd">@admin</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="n">Animal</span><span class="p">)</span>
5905
+ <a id="__codelineno-31-9" name="__codelineno-31-9" href="#__codelineno-31-9"></a><span class="k">class</span> <span class="nc">AnimalAdmin</span><span class="p">(</span><span class="n">NautobotModelAdmin</span><span class="p">):</span>
5906
+ <a id="__codelineno-31-10" name="__codelineno-31-10" href="#__codelineno-31-10"></a> <span class="n">list_display</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;name&#39;</span><span class="p">,</span> <span class="s1">&#39;sound&#39;</span><span class="p">)</span>
4626
5907
  </code></pre></div>
4627
5908
  <p>This will display the app and its model in the admin UI. Staff users can create, change, and delete model instances via the admin UI without needing to create a custom view.</p>
4628
5909
  <p><img alt="Nautobot app in the admin UI" src="../media/plugins/plugin_admin_ui.png" /></p>
@@ -4631,9 +5912,9 @@ namedtuple to assist in the configurations.</p>
4631
5912
  <p class="admonition-title">Added in version 2.0.0</p>
4632
5913
  </div>
4633
5914
  <p>Simply define a <code>searchable_models</code> array on the NautobotAppConfig for your app, listing the lowercase names of the model(s) from your app that you wish to include in the Nautobot global search.</p>
4634
- <div class="highlight"><pre><span></span><code><a id="__codelineno-28-1" name="__codelineno-28-1" href="#__codelineno-28-1"></a><span class="k">class</span> <span class="nc">AnimalSoundsConfig</span><span class="p">(</span><span class="n">NautobotAppConfig</span><span class="p">):</span>
4635
- <a id="__codelineno-28-2" name="__codelineno-28-2" href="#__codelineno-28-2"></a> <span class="o">...</span>
4636
- <a id="__codelineno-28-3" name="__codelineno-28-3" href="#__codelineno-28-3"></a> <span class="n">searchable_models</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;animal&quot;</span><span class="p">]</span>
5915
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a><span class="k">class</span> <span class="nc">AnimalSoundsConfig</span><span class="p">(</span><span class="n">NautobotAppConfig</span><span class="p">):</span>
5916
+ <a id="__codelineno-32-2" name="__codelineno-32-2" href="#__codelineno-32-2"></a> <span class="o">...</span>
5917
+ <a id="__codelineno-32-3" name="__codelineno-32-3" href="#__codelineno-32-3"></a> <span class="n">searchable_models</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;animal&quot;</span><span class="p">]</span>
4637
5918
  </code></pre></div>
4638
5919
  <h3 id="integrating-with-graphql">Integrating with GraphQL<a class="headerlink" href="#integrating-with-graphql" title="Permanent link">&para;</a></h3>
4639
5920
  <p>Apps can optionally expose their models via the GraphQL interface to allow the models to be part of the Graph and to be queried easily. There are two mutually exclusive ways to expose a model to the GraphQL interface.</p>
@@ -4650,21 +5931,21 @@ namedtuple to assist in the configurations.</p>
4650
5931
  </ul>
4651
5932
  <h4 id="using-the-extras_features-decorator-for-graphql">Using the <code>@extras_features</code> Decorator for GraphQL<a class="headerlink" href="#using-the-extras_features-decorator-for-graphql" title="Permanent link">&para;</a></h4>
4652
5933
  <p>To expose a model via GraphQL, simply register it using the <code>@extras_features("graphql")</code> decorator. Nautobot will detect this and will automatically create a GraphQL type definition based on the model. Additionally, if a <code>FilterSet</code> is available at <code>&lt;app_name&gt;.filters.&lt;ModelName&gt;FilterSet</code>, Nautobot will automatically use the filterset to generate GraphQL filtering options for this type as well.</p>
4653
- <div class="highlight"><pre><span></span><code><a id="__codelineno-29-1" name="__codelineno-29-1" href="#__codelineno-29-1"></a><span class="c1"># models.py</span>
4654
- <a id="__codelineno-29-2" name="__codelineno-29-2" href="#__codelineno-29-2"></a><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
4655
- <a id="__codelineno-29-3" name="__codelineno-29-3" href="#__codelineno-29-3"></a>
4656
- <a id="__codelineno-29-4" name="__codelineno-29-4" href="#__codelineno-29-4"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">extras_features</span>
4657
- <a id="__codelineno-29-5" name="__codelineno-29-5" href="#__codelineno-29-5"></a>
4658
- <a id="__codelineno-29-6" name="__codelineno-29-6" href="#__codelineno-29-6"></a>
4659
- <a id="__codelineno-29-7" name="__codelineno-29-7" href="#__codelineno-29-7"></a><span class="nd">@extras_features</span><span class="p">(</span><span class="s2">&quot;graphql&quot;</span><span class="p">)</span>
4660
- <a id="__codelineno-29-8" name="__codelineno-29-8" href="#__codelineno-29-8"></a><span class="k">class</span> <span class="nc">Animal</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
4661
- <a id="__codelineno-29-9" name="__codelineno-29-9" href="#__codelineno-29-9"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Base model for animals.&quot;&quot;&quot;</span>
4662
- <a id="__codelineno-29-10" name="__codelineno-29-10" href="#__codelineno-29-10"></a>
4663
- <a id="__codelineno-29-11" name="__codelineno-29-11" href="#__codelineno-29-11"></a> <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
4664
- <a id="__codelineno-29-12" name="__codelineno-29-12" href="#__codelineno-29-12"></a> <span class="n">sound</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
4665
- <a id="__codelineno-29-13" name="__codelineno-29-13" href="#__codelineno-29-13"></a>
4666
- <a id="__codelineno-29-14" name="__codelineno-29-14" href="#__codelineno-29-14"></a> <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4667
- <a id="__codelineno-29-15" name="__codelineno-29-15" href="#__codelineno-29-15"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
5934
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-33-1" name="__codelineno-33-1" href="#__codelineno-33-1"></a><span class="c1"># models.py</span>
5935
+ <a id="__codelineno-33-2" name="__codelineno-33-2" href="#__codelineno-33-2"></a><span class="kn">from</span> <span class="nn">django.db</span> <span class="kn">import</span> <span class="n">models</span>
5936
+ <a id="__codelineno-33-3" name="__codelineno-33-3" href="#__codelineno-33-3"></a>
5937
+ <a id="__codelineno-33-4" name="__codelineno-33-4" href="#__codelineno-33-4"></a><span class="kn">from</span> <span class="nn">nautobot.apps.models</span> <span class="kn">import</span> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">extras_features</span>
5938
+ <a id="__codelineno-33-5" name="__codelineno-33-5" href="#__codelineno-33-5"></a>
5939
+ <a id="__codelineno-33-6" name="__codelineno-33-6" href="#__codelineno-33-6"></a>
5940
+ <a id="__codelineno-33-7" name="__codelineno-33-7" href="#__codelineno-33-7"></a><span class="nd">@extras_features</span><span class="p">(</span><span class="s2">&quot;graphql&quot;</span><span class="p">)</span>
5941
+ <a id="__codelineno-33-8" name="__codelineno-33-8" href="#__codelineno-33-8"></a><span class="k">class</span> <span class="nc">Animal</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">):</span>
5942
+ <a id="__codelineno-33-9" name="__codelineno-33-9" href="#__codelineno-33-9"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Base model for animals.&quot;&quot;&quot;</span>
5943
+ <a id="__codelineno-33-10" name="__codelineno-33-10" href="#__codelineno-33-10"></a>
5944
+ <a id="__codelineno-33-11" name="__codelineno-33-11" href="#__codelineno-33-11"></a> <span class="n">name</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
5945
+ <a id="__codelineno-33-12" name="__codelineno-33-12" href="#__codelineno-33-12"></a> <span class="n">sound</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">(</span><span class="n">max_length</span><span class="o">=</span><span class="mi">50</span><span class="p">)</span>
5946
+ <a id="__codelineno-33-13" name="__codelineno-33-13" href="#__codelineno-33-13"></a>
5947
+ <a id="__codelineno-33-14" name="__codelineno-33-14" href="#__codelineno-33-14"></a> <span class="k">def</span> <span class="fm">__str__</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5948
+ <a id="__codelineno-33-15" name="__codelineno-33-15" href="#__codelineno-33-15"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">name</span>
4668
5949
  </code></pre></div>
4669
5950
  <h4 id="creating-your-own-graphql-type-object">Creating Your Own GraphQL Type Object<a class="headerlink" href="#creating-your-own-graphql-type-object" title="Permanent link">&para;</a></h4>
4670
5951
  <p>In some cases, such as when a model is using Generic Foreign Keys, or when a model has constructed fields that should also be reflected in GraphQL, the default GraphQL type definition generated by the <code>@extras_features</code> decorator may not work as the developer intends, and it will be preferable to provide custom GraphQL types.</p>
@@ -4674,21 +5955,21 @@ namedtuple to assist in the configurations.</p>
4674
5955
  <p class="admonition-title">Warning</p>
4675
5956
  <p>When defining types this way, do <strong>not</strong> use the <code>@extras_features("graphql")</code> decorator on the corresponding Model class, as no auto-generated GraphQL type is desired for this model.</p>
4676
5957
  </div>
4677
- <div class="highlight"><pre><span></span><code><a id="__codelineno-30-1" name="__codelineno-30-1" href="#__codelineno-30-1"></a><span class="c1"># graphql/types.py</span>
4678
- <a id="__codelineno-30-2" name="__codelineno-30-2" href="#__codelineno-30-2"></a><span class="kn">import</span> <span class="nn">graphene_django_optimizer</span> <span class="k">as</span> <span class="nn">gql_optimizer</span>
4679
- <a id="__codelineno-30-3" name="__codelineno-30-3" href="#__codelineno-30-3"></a>
4680
- <a id="__codelineno-30-4" name="__codelineno-30-4" href="#__codelineno-30-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
4681
- <a id="__codelineno-30-5" name="__codelineno-30-5" href="#__codelineno-30-5"></a>
4682
- <a id="__codelineno-30-6" name="__codelineno-30-6" href="#__codelineno-30-6"></a>
4683
- <a id="__codelineno-30-7" name="__codelineno-30-7" href="#__codelineno-30-7"></a><span class="k">class</span> <span class="nc">AnimalType</span><span class="p">(</span><span class="n">gql_optimizer</span><span class="o">.</span><span class="n">OptimizedDjangoObjectType</span><span class="p">):</span>
4684
- <a id="__codelineno-30-8" name="__codelineno-30-8" href="#__codelineno-30-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;GraphQL Type for Animal&quot;&quot;&quot;</span>
4685
- <a id="__codelineno-30-9" name="__codelineno-30-9" href="#__codelineno-30-9"></a>
4686
- <a id="__codelineno-30-10" name="__codelineno-30-10" href="#__codelineno-30-10"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
4687
- <a id="__codelineno-30-11" name="__codelineno-30-11" href="#__codelineno-30-11"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">Animal</span>
4688
- <a id="__codelineno-30-12" name="__codelineno-30-12" href="#__codelineno-30-12"></a> <span class="n">exclude</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;sound&quot;</span><span class="p">]</span>
4689
- <a id="__codelineno-30-13" name="__codelineno-30-13" href="#__codelineno-30-13"></a>
4690
- <a id="__codelineno-30-14" name="__codelineno-30-14" href="#__codelineno-30-14"></a>
4691
- <a id="__codelineno-30-15" name="__codelineno-30-15" href="#__codelineno-30-15"></a><span class="n">graphql_types</span> <span class="o">=</span> <span class="p">[</span><span class="n">AnimalType</span><span class="p">]</span>
5958
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-34-1" name="__codelineno-34-1" href="#__codelineno-34-1"></a><span class="c1"># graphql/types.py</span>
5959
+ <a id="__codelineno-34-2" name="__codelineno-34-2" href="#__codelineno-34-2"></a><span class="kn">import</span> <span class="nn">graphene_django_optimizer</span> <span class="k">as</span> <span class="nn">gql_optimizer</span>
5960
+ <a id="__codelineno-34-3" name="__codelineno-34-3" href="#__codelineno-34-3"></a>
5961
+ <a id="__codelineno-34-4" name="__codelineno-34-4" href="#__codelineno-34-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
5962
+ <a id="__codelineno-34-5" name="__codelineno-34-5" href="#__codelineno-34-5"></a>
5963
+ <a id="__codelineno-34-6" name="__codelineno-34-6" href="#__codelineno-34-6"></a>
5964
+ <a id="__codelineno-34-7" name="__codelineno-34-7" href="#__codelineno-34-7"></a><span class="k">class</span> <span class="nc">AnimalType</span><span class="p">(</span><span class="n">gql_optimizer</span><span class="o">.</span><span class="n">OptimizedDjangoObjectType</span><span class="p">):</span>
5965
+ <a id="__codelineno-34-8" name="__codelineno-34-8" href="#__codelineno-34-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;GraphQL Type for Animal&quot;&quot;&quot;</span>
5966
+ <a id="__codelineno-34-9" name="__codelineno-34-9" href="#__codelineno-34-9"></a>
5967
+ <a id="__codelineno-34-10" name="__codelineno-34-10" href="#__codelineno-34-10"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
5968
+ <a id="__codelineno-34-11" name="__codelineno-34-11" href="#__codelineno-34-11"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">Animal</span>
5969
+ <a id="__codelineno-34-12" name="__codelineno-34-12" href="#__codelineno-34-12"></a> <span class="n">exclude</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;sound&quot;</span><span class="p">]</span>
5970
+ <a id="__codelineno-34-13" name="__codelineno-34-13" href="#__codelineno-34-13"></a>
5971
+ <a id="__codelineno-34-14" name="__codelineno-34-14" href="#__codelineno-34-14"></a>
5972
+ <a id="__codelineno-34-15" name="__codelineno-34-15" href="#__codelineno-34-15"></a><span class="n">graphql_types</span> <span class="o">=</span> <span class="p">[</span><span class="n">AnimalType</span><span class="p">]</span>
4692
5973
  </code></pre></div>
4693
5974
  <h4 id="using-graphql-orm-utilities">Using GraphQL ORM Utilities<a class="headerlink" href="#using-graphql-orm-utilities" title="Permanent link">&para;</a></h4>
4694
5975
  <p>GraphQL utility functions:</p>
@@ -4696,7 +5977,11 @@ namedtuple to assist in the configurations.</p>
4696
5977
  <li><code>execute_query()</code>: Runs string as a query against GraphQL.</li>
4697
5978
  <li><code>execute_saved_query()</code>: Execute a saved query from Nautobot database.</li>
4698
5979
  </ol>
4699
- <p>Both functions have the same arguments other than <code>execute_saved_query()</code> which requires a slug to identify the saved query rather than a string holding a query.</p>
5980
+ <p>Both functions have the same arguments other than <code>execute_saved_query()</code> which requires a name to identify the saved query rather than a string holding a query.</p>
5981
+ <div class="admonition version-changed">
5982
+ <p class="admonition-title">Changed in version 2.0.0</p>
5983
+ <p><code>execute_saved_query()</code> now expects a <code>saved_query_name</code> rather than a <code>saved_query_slug</code>.</p>
5984
+ </div>
4700
5985
  <p>For authentication either a request object or user object needs to be passed in. If there is none, the function will error out.</p>
4701
5986
  <p>Arguments:</p>
4702
5987
  <ul>
@@ -4708,7 +5993,7 @@ namedtuple to assist in the configurations.</p>
4708
5993
  </ul>
4709
5994
  </li>
4710
5995
  <li><code>execute_saved_query()</code>:<ul>
4711
- <li><code>saved_query_slug</code> (str): Slug of a saved GraphQL query.</li>
5996
+ <li><code>saved_query_name</code> (str): Name of a saved GraphQL query.</li>
4712
5997
  <li><code>variables</code> (dict, optional): If the query has variables they need to be passed in as a dictionary.</li>
4713
5998
  <li><code>request</code> (django.test.client.RequestFactory, optional): Used to authenticate.</li>
4714
5999
  <li><code>user</code> (django.contrib.auth.models.User, optional): Used to authenticate.</li>
@@ -4726,28 +6011,37 @@ namedtuple to assist in the configurations.</p>
4726
6011
  <p>Note that this ViewSet is catered specifically to the UI, not the API.</p>
4727
6012
  <p>Concrete examples on how to use <code>NautobotUIViewSet</code> resides in <code>nautobot.circuits.views</code>.</p>
4728
6013
  <p>Below we provide an example on how to use <code>NautobotUIViewSet</code> on a theoretical app model.</p>
4729
- <div class="highlight"><pre><span></span><code><a id="__codelineno-31-1" name="__codelineno-31-1" href="#__codelineno-31-1"></a><span class="kn">from</span> <span class="nn">nautobot.apps.views</span> <span class="kn">import</span> <span class="n">NautobotUIViewset</span>
4730
- <a id="__codelineno-31-2" name="__codelineno-31-2" href="#__codelineno-31-2"></a>
4731
- <a id="__codelineno-31-3" name="__codelineno-31-3" href="#__codelineno-31-3"></a><span class="k">class</span> <span class="nc">YourAppModelUIViewSet</span><span class="p">(</span><span class="n">NautobotUIViewSet</span><span class="p">):</span>
4732
- <a id="__codelineno-31-4" name="__codelineno-31-4" href="#__codelineno-31-4"></a> <span class="n">bulk_create_form_class</span> <span class="o">=</span> <span class="n">YourAppModelCSVForm</span>
4733
- <a id="__codelineno-31-5" name="__codelineno-31-5" href="#__codelineno-31-5"></a> <span class="n">bulk_update_form_class</span> <span class="o">=</span> <span class="n">YourAppModelBulkEditForm</span>
4734
- <a id="__codelineno-31-6" name="__codelineno-31-6" href="#__codelineno-31-6"></a> <span class="n">filterset_class</span> <span class="o">=</span> <span class="n">YourAppModelFilterSet</span>
4735
- <a id="__codelineno-31-7" name="__codelineno-31-7" href="#__codelineno-31-7"></a> <span class="n">filterset_form_class</span> <span class="o">=</span> <span class="n">YourAppModelFilterForm</span>
4736
- <a id="__codelineno-31-8" name="__codelineno-31-8" href="#__codelineno-31-8"></a> <span class="n">form_class</span> <span class="o">=</span> <span class="n">YourAppModelForm</span>
4737
- <a id="__codelineno-31-9" name="__codelineno-31-9" href="#__codelineno-31-9"></a> <span class="n">queryset</span> <span class="o">=</span> <span class="n">YourAppModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
4738
- <a id="__codelineno-31-10" name="__codelineno-31-10" href="#__codelineno-31-10"></a> <span class="n">serializer_class</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">YourAppModelSerializer</span>
4739
- <a id="__codelineno-31-11" name="__codelineno-31-11" href="#__codelineno-31-11"></a> <span class="n">table_class</span> <span class="o">=</span> <span class="n">YourAppModelTable</span>
6014
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-35-1" name="__codelineno-35-1" href="#__codelineno-35-1"></a><span class="kn">from</span> <span class="nn">nautobot.apps.views</span> <span class="kn">import</span> <span class="n">NautobotUIViewSet</span>
6015
+ <a id="__codelineno-35-2" name="__codelineno-35-2" href="#__codelineno-35-2"></a><span class="kn">from</span> <span class="nn">yourapp</span> <span class="kn">import</span> <span class="n">filters</span><span class="p">,</span> <span class="n">forms</span><span class="p">,</span> <span class="n">models</span><span class="p">,</span> <span class="n">tables</span>
6016
+ <a id="__codelineno-35-3" name="__codelineno-35-3" href="#__codelineno-35-3"></a><span class="kn">from</span> <span class="nn">yourapp.api</span> <span class="kn">import</span> <span class="n">serializers</span>
6017
+ <a id="__codelineno-35-4" name="__codelineno-35-4" href="#__codelineno-35-4"></a>
6018
+ <a id="__codelineno-35-5" name="__codelineno-35-5" href="#__codelineno-35-5"></a><span class="k">class</span> <span class="nc">YourAppModelUIViewSet</span><span class="p">(</span><span class="n">NautobotUIViewSet</span><span class="p">):</span>
6019
+ <a id="__codelineno-35-6" name="__codelineno-35-6" href="#__codelineno-35-6"></a> <span class="n">bulk_update_form_class</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">YourAppModelBulkEditForm</span>
6020
+ <a id="__codelineno-35-7" name="__codelineno-35-7" href="#__codelineno-35-7"></a> <span class="n">filterset_class</span> <span class="o">=</span> <span class="n">filters</span><span class="o">.</span><span class="n">YourAppModelFilterSet</span>
6021
+ <a id="__codelineno-35-8" name="__codelineno-35-8" href="#__codelineno-35-8"></a> <span class="n">filterset_form_class</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">YourAppModelFilterForm</span>
6022
+ <a id="__codelineno-35-9" name="__codelineno-35-9" href="#__codelineno-35-9"></a> <span class="n">form_class</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">YourAppModelForm</span>
6023
+ <a id="__codelineno-35-10" name="__codelineno-35-10" href="#__codelineno-35-10"></a> <span class="n">queryset</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">YourAppModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
6024
+ <a id="__codelineno-35-11" name="__codelineno-35-11" href="#__codelineno-35-11"></a> <span class="n">serializer_class</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">YourAppModelSerializer</span>
6025
+ <a id="__codelineno-35-12" name="__codelineno-35-12" href="#__codelineno-35-12"></a> <span class="n">table_class</span> <span class="o">=</span> <span class="n">tables</span><span class="o">.</span><span class="n">YourAppModelTable</span>
4740
6026
  </code></pre></div>
4741
6027
  <h4 id="setting-viewset-attributes">Setting ViewSet Attributes<a class="headerlink" href="#setting-viewset-attributes" title="Permanent link">&para;</a></h4>
4742
6028
  <p><strong>One caveat of using the NautobotUIViewSet is that the <code>queryset</code>, <code>serializer_class</code> and <code>table_class</code> attribute of the <code>YourAppModelUIViewSet</code> has to be set before most of the <code>NautobotUIViewSet</code> functionalities will become available.</strong></p>
4743
- <p>By default the URL patterns generated by a <code>NautobotUIViewSet</code> are based on the model's <code>slug</code> (<code>/model-name/&lt;slug&gt;/</code> for the detail view, <code>/model-name/&lt;slug&gt;/edit/</code> for the edit view, etc.). If your model lacks a <code>slug</code> field, or if you otherwise need to use a different field to look up an object, just override the default <code>lookup_field</code> in your ViewSet attributes:</p>
4744
- <div class="highlight"><pre><span></span><code><a id="__codelineno-32-1" name="__codelineno-32-1" href="#__codelineno-32-1"></a><span class="kn">from</span> <span class="nn">nautobot.apps.views</span> <span class="kn">import</span> <span class="n">NautobotUIViewset</span>
4745
- <a id="__codelineno-32-2" name="__codelineno-32-2" href="#__codelineno-32-2"></a>
4746
- <a id="__codelineno-32-3" name="__codelineno-32-3" href="#__codelineno-32-3"></a><span class="k">class</span> <span class="nc">YourAppModelUIViewSet</span><span class="p">(</span><span class="n">NautobotUIViewSet</span><span class="p">):</span>
4747
- <a id="__codelineno-32-4" name="__codelineno-32-4" href="#__codelineno-32-4"></a> <span class="o">...</span>
4748
- <a id="__codelineno-32-5" name="__codelineno-32-5" href="#__codelineno-32-5"></a> <span class="n">lookup_field</span> <span class="o">=</span> <span class="s2">&quot;pk&quot;</span>
4749
- <a id="__codelineno-32-6" name="__codelineno-32-6" href="#__codelineno-32-6"></a> <span class="o">...</span>
6029
+ <p>By default the URL patterns generated by a <code>NautobotUIViewSet</code> are based on the model's <code>pk</code> (<code>/model-name/&lt;pk&gt;/</code> for the detail view, <code>/model-name/&lt;pk&gt;/edit/</code> for the edit view, etc.). if you need to use a different field to look up an object, just override the default <code>lookup_field</code> in your ViewSet attributes:</p>
6030
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-36-1" name="__codelineno-36-1" href="#__codelineno-36-1"></a><span class="kn">from</span> <span class="nn">nautobot.apps.views</span> <span class="kn">import</span> <span class="n">NautobotUIViewSet</span>
6031
+ <a id="__codelineno-36-2" name="__codelineno-36-2" href="#__codelineno-36-2"></a>
6032
+ <a id="__codelineno-36-3" name="__codelineno-36-3" href="#__codelineno-36-3"></a><span class="k">class</span> <span class="nc">YourAppModelUIViewSet</span><span class="p">(</span><span class="n">NautobotUIViewSet</span><span class="p">):</span>
6033
+ <a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a> <span class="o">...</span>
6034
+ <a id="__codelineno-36-5" name="__codelineno-36-5" href="#__codelineno-36-5"></a> <span class="n">lookup_field</span> <span class="o">=</span> <span class="s2">&quot;slug&quot;</span>
6035
+ <a id="__codelineno-36-6" name="__codelineno-36-6" href="#__codelineno-36-6"></a> <span class="o">...</span>
4750
6036
  </code></pre></div>
6037
+ <div class="admonition version-changed">
6038
+ <p class="admonition-title">Changed in version 2.0.0</p>
6039
+ <p>The default <code>lookup_field</code> for <code>NautobotUIViewSet</code> has been changed from <code>"slug"</code> to <code>"pk"</code>.</p>
6040
+ </div>
6041
+ <div class="admonition note">
6042
+ <p class="admonition-title">Note</p>
6043
+ <p>Using a field other than the default <code>pk</code> or the alternative field <code>slug</code> (as shown in the example above), may result in certain pieces of the UI not displaying (for example, the edit and delete buttons on the object detail view). This is due to the URL expecting a named key of slug or pk, rather than id.</p>
6044
+ </div>
4751
6045
  <h4 id="view-template-context">View Template Context<a class="headerlink" href="#view-template-context" title="Permanent link">&para;</a></h4>
4752
6046
  <p>Templates can benefit from a very rich context passed down from the views and renderer, including forms, tables, as well as any other information that may be helpful for rendering templates. The keys it provides are as follows:</p>
4753
6047
  <ul>
@@ -4763,18 +6057,18 @@ namedtuple to assist in the configurations.</p>
4763
6057
  <li><code>verbose_name_plural</code>: The plural form of the model's name</li>
4764
6058
  </ul>
4765
6059
  <p>An example from editing a Provider object:</p>
4766
- <div class="highlight"><pre><span></span><code><a id="__codelineno-33-1" name="__codelineno-33-1" href="#__codelineno-33-1"></a><span class="p">{</span>
4767
- <a id="__codelineno-33-2" name="__codelineno-33-2" href="#__codelineno-33-2"></a> <span class="s1">&#39;content_type&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">ContentType</span><span class="p">:</span> <span class="n">circuits</span> <span class="o">|</span> <span class="n">provider</span><span class="o">&gt;</span><span class="p">,</span>
4768
- <a id="__codelineno-33-3" name="__codelineno-33-3" href="#__codelineno-33-3"></a> <span class="s1">&#39;filter_form&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">ProviderFilterForm</span> <span class="n">bound</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">valid</span><span class="o">=</span><span class="n">Unknown</span><span class="p">,</span> <span class="n">fields</span><span class="o">=</span><span class="p">(</span><span class="n">region</span><span class="p">;</span><span class="n">site</span><span class="p">;</span><span class="n">location</span><span class="p">;</span><span class="n">q</span><span class="p">;</span><span class="n">asn</span><span class="p">;</span><span class="n">tag</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span>
4769
- <a id="__codelineno-33-4" name="__codelineno-33-4" href="#__codelineno-33-4"></a> <span class="s1">&#39;form&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">ProviderForm</span> <span class="n">bound</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">valid</span><span class="o">=</span><span class="n">Unknown</span><span class="p">,</span> <span class="n">fields</span><span class="o">=</span><span class="p">(</span><span class="n">name</span><span class="p">;</span><span class="n">slug</span><span class="p">;</span><span class="n">asn</span><span class="p">;</span><span class="n">account</span><span class="p">;</span><span class="n">portal_url</span><span class="p">;</span><span class="n">noc_contact</span><span class="p">;</span><span class="n">admin_contact</span><span class="p">;</span><span class="n">comments</span><span class="p">;</span><span class="n">tags</span><span class="p">;</span><span class="n">object_note</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span>
4770
- <a id="__codelineno-33-5" name="__codelineno-33-5" href="#__codelineno-33-5"></a> <span class="s1">&#39;object&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">Provider</span><span class="p">:</span> <span class="n">NautobotProvider</span><span class="o">&gt;</span><span class="p">,</span>
4771
- <a id="__codelineno-33-6" name="__codelineno-33-6" href="#__codelineno-33-6"></a> <span class="s1">&#39;permissions&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;add&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;change&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;delete&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;view&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
4772
- <a id="__codelineno-33-7" name="__codelineno-33-7" href="#__codelineno-33-7"></a> <span class="s1">&#39;return_url&#39;</span><span class="p">:</span> <span class="s1">&#39;/circuits/providers/nautobotprovider&#39;</span><span class="p">,</span>
4773
- <a id="__codelineno-33-8" name="__codelineno-33-8" href="#__codelineno-33-8"></a> <span class="s1">&#39;table&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
4774
- <a id="__codelineno-33-9" name="__codelineno-33-9" href="#__codelineno-33-9"></a> <span class="s1">&#39;table_config_form&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
4775
- <a id="__codelineno-33-10" name="__codelineno-33-10" href="#__codelineno-33-10"></a> <span class="s1">&#39;verbose_name&#39;</span><span class="p">:</span> <span class="s1">&#39;provider&#39;</span><span class="p">,</span>
4776
- <a id="__codelineno-33-11" name="__codelineno-33-11" href="#__codelineno-33-11"></a> <span class="s1">&#39;verbose_name_plural&#39;</span><span class="p">:</span> <span class="s1">&#39;providers&#39;</span>
4777
- <a id="__codelineno-33-12" name="__codelineno-33-12" href="#__codelineno-33-12"></a><span class="p">}</span>
6060
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-37-1" name="__codelineno-37-1" href="#__codelineno-37-1"></a><span class="p">{</span>
6061
+ <a id="__codelineno-37-2" name="__codelineno-37-2" href="#__codelineno-37-2"></a> <span class="s1">&#39;content_type&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">ContentType</span><span class="p">:</span> <span class="n">circuits</span> <span class="o">|</span> <span class="n">provider</span><span class="o">&gt;</span><span class="p">,</span>
6062
+ <a id="__codelineno-37-3" name="__codelineno-37-3" href="#__codelineno-37-3"></a> <span class="s1">&#39;filter_form&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">ProviderFilterForm</span> <span class="n">bound</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">valid</span><span class="o">=</span><span class="n">Unknown</span><span class="p">,</span> <span class="n">fields</span><span class="o">=</span><span class="p">(</span><span class="n">region</span><span class="p">;</span><span class="n">site</span><span class="p">;</span><span class="n">location</span><span class="p">;</span><span class="n">q</span><span class="p">;</span><span class="n">asn</span><span class="p">;</span><span class="n">tag</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span>
6063
+ <a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a> <span class="s1">&#39;form&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">ProviderForm</span> <span class="n">bound</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">valid</span><span class="o">=</span><span class="n">Unknown</span><span class="p">,</span> <span class="n">fields</span><span class="o">=</span><span class="p">(</span><span class="n">name</span><span class="p">;</span><span class="n">slug</span><span class="p">;</span><span class="n">asn</span><span class="p">;</span><span class="n">account</span><span class="p">;</span><span class="n">portal_url</span><span class="p">;</span><span class="n">noc_contact</span><span class="p">;</span><span class="n">admin_contact</span><span class="p">;</span><span class="n">comments</span><span class="p">;</span><span class="n">tags</span><span class="p">;</span><span class="n">object_note</span><span class="p">)</span><span class="o">&gt;</span><span class="p">,</span>
6064
+ <a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a> <span class="s1">&#39;object&#39;</span><span class="p">:</span> <span class="o">&lt;</span><span class="n">Provider</span><span class="p">:</span> <span class="n">NautobotProvider</span><span class="o">&gt;</span><span class="p">,</span>
6065
+ <a id="__codelineno-37-6" name="__codelineno-37-6" href="#__codelineno-37-6"></a> <span class="s1">&#39;permissions&#39;</span><span class="p">:</span> <span class="p">{</span><span class="s1">&#39;add&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;change&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;delete&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">,</span> <span class="s1">&#39;view&#39;</span><span class="p">:</span> <span class="kc">True</span><span class="p">},</span>
6066
+ <a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a> <span class="s1">&#39;return_url&#39;</span><span class="p">:</span> <span class="s1">&#39;/circuits/providers/nautobotprovider&#39;</span><span class="p">,</span>
6067
+ <a id="__codelineno-37-8" name="__codelineno-37-8" href="#__codelineno-37-8"></a> <span class="s1">&#39;table&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
6068
+ <a id="__codelineno-37-9" name="__codelineno-37-9" href="#__codelineno-37-9"></a> <span class="s1">&#39;table_config_form&#39;</span><span class="p">:</span> <span class="kc">None</span><span class="p">,</span>
6069
+ <a id="__codelineno-37-10" name="__codelineno-37-10" href="#__codelineno-37-10"></a> <span class="s1">&#39;verbose_name&#39;</span><span class="p">:</span> <span class="s1">&#39;provider&#39;</span><span class="p">,</span>
6070
+ <a id="__codelineno-37-11" name="__codelineno-37-11" href="#__codelineno-37-11"></a> <span class="s1">&#39;verbose_name_plural&#39;</span><span class="p">:</span> <span class="s1">&#39;providers&#39;</span>
6071
+ <a id="__codelineno-37-12" name="__codelineno-37-12" href="#__codelineno-37-12"></a><span class="p">}</span>
4778
6072
  </code></pre></div>
4779
6073
  <p>Other context keys may be available for certain views:</p>
4780
6074
  <ul>
@@ -4783,36 +6077,39 @@ namedtuple to assist in the configurations.</p>
4783
6077
  </ul>
4784
6078
  <p>You may see other context keys as well, but any not documented above should not be relied upon as they may be removed in a future release. Some examples of those are:</p>
4785
6079
  <ul>
4786
- <li><code>changelog_url</code>: This can now be retrieved from the object itself, via <code>object.get_changelog_url</code>, if the object supports change-logging</li>
4787
6080
  <li><code>obj</code>: Please use <code>object</code> instead</li>
4788
6081
  <li><code>obj_type</code>: Please use <code>verbose_name</code> instead</li>
4789
6082
  <li><code>obj_type_plural</code>: Please use <code>verbose_name_plural</code> instead</li>
4790
6083
  </ul>
6084
+ <div class="admonition version-removed">
6085
+ <p class="admonition-title">Removed in version 2.0.0</p>
6086
+ <p>The <code>changelog_url</code> context key was removed. Use <code>object.get_changelog_url</code> instead.</p>
6087
+ </div>
4791
6088
  <h4 id="excluding-viewmixins-from-nautobotuiviewset">Excluding ViewMixins from NautobotUIViewSet<a class="headerlink" href="#excluding-viewmixins-from-nautobotuiviewset" title="Permanent link">&para;</a></h4>
4792
6089
  <p>For app models that do not require certain views, simply inherit directly from the <code>ViewMixin</code> classes available in <code>nautobot.apps.views</code> instead of <code>NautobotUIViewSet</code>.</p>
4793
6090
  <p>Concrete examples for excluding <code>ViewMixins</code>, checkout <code>CircuitTerminationUIViewSet</code> and <code>CircuitTypeUIViewSet</code> in <code>nautobot.circuits.views</code>.</p>
4794
- <div class="highlight"><pre><span></span><code><a id="__codelineno-34-1" name="__codelineno-34-1" href="#__codelineno-34-1"></a><span class="c1">## An app model viewset that does not support bulk views and operations</span>
4795
- <a id="__codelineno-34-2" name="__codelineno-34-2" href="#__codelineno-34-2"></a><span class="kn">import</span> <span class="nn">nautobot.apps.views</span>
4796
- <a id="__codelineno-34-3" name="__codelineno-34-3" href="#__codelineno-34-3"></a>
4797
- <a id="__codelineno-34-4" name="__codelineno-34-4" href="#__codelineno-34-4"></a><span class="k">class</span> <span class="nc">YourAppModelUIViewSet</span><span class="p">(</span>
4798
- <a id="__codelineno-34-5" name="__codelineno-34-5" href="#__codelineno-34-5"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectListViewMixin</span><span class="p">,</span>
4799
- <a id="__codelineno-34-6" name="__codelineno-34-6" href="#__codelineno-34-6"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectDetailViewMixin</span><span class="p">,</span>
4800
- <a id="__codelineno-34-7" name="__codelineno-34-7" href="#__codelineno-34-7"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectEditViewMixin</span><span class="p">,</span>
4801
- <a id="__codelineno-34-8" name="__codelineno-34-8" href="#__codelineno-34-8"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectDestroyViewMixin</span><span class="p">,</span>
4802
- <a id="__codelineno-34-9" name="__codelineno-34-9" href="#__codelineno-34-9"></a><span class="p">):</span>
4803
- <a id="__codelineno-34-10" name="__codelineno-34-10" href="#__codelineno-34-10"></a>
4804
- <a id="__codelineno-34-11" name="__codelineno-34-11" href="#__codelineno-34-11"></a> <span class="n">filterset_class</span> <span class="o">=</span> <span class="n">YourAppModelFilterSet</span>
4805
- <a id="__codelineno-34-12" name="__codelineno-34-12" href="#__codelineno-34-12"></a> <span class="n">filterset_form_class</span> <span class="o">=</span> <span class="n">YourAppModelFilterForm</span>
4806
- <a id="__codelineno-34-13" name="__codelineno-34-13" href="#__codelineno-34-13"></a> <span class="n">form_class</span> <span class="o">=</span> <span class="n">YourAppModelForm</span>
4807
- <a id="__codelineno-34-14" name="__codelineno-34-14" href="#__codelineno-34-14"></a> <span class="n">queryset</span> <span class="o">=</span> <span class="n">YourAppModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
4808
- <a id="__codelineno-34-15" name="__codelineno-34-15" href="#__codelineno-34-15"></a> <span class="n">serializer_class</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">YourAppModelSerializer</span>
4809
- <a id="__codelineno-34-16" name="__codelineno-34-16" href="#__codelineno-34-16"></a> <span class="n">table_class</span> <span class="o">=</span> <span class="n">YourAppModelTable</span>
4810
- <a id="__codelineno-34-17" name="__codelineno-34-17" href="#__codelineno-34-17"></a> <span class="c1"># You do not need to specify attributes that are not needed.</span>
6091
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-38-1" name="__codelineno-38-1" href="#__codelineno-38-1"></a><span class="c1">## An app model viewset that does not support bulk views and operations</span>
6092
+ <a id="__codelineno-38-2" name="__codelineno-38-2" href="#__codelineno-38-2"></a><span class="kn">import</span> <span class="nn">nautobot.apps.views</span>
6093
+ <a id="__codelineno-38-3" name="__codelineno-38-3" href="#__codelineno-38-3"></a>
6094
+ <a id="__codelineno-38-4" name="__codelineno-38-4" href="#__codelineno-38-4"></a><span class="k">class</span> <span class="nc">YourAppModelUIViewSet</span><span class="p">(</span>
6095
+ <a id="__codelineno-38-5" name="__codelineno-38-5" href="#__codelineno-38-5"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectListViewMixin</span><span class="p">,</span>
6096
+ <a id="__codelineno-38-6" name="__codelineno-38-6" href="#__codelineno-38-6"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectDetailViewMixin</span><span class="p">,</span>
6097
+ <a id="__codelineno-38-7" name="__codelineno-38-7" href="#__codelineno-38-7"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectEditViewMixin</span><span class="p">,</span>
6098
+ <a id="__codelineno-38-8" name="__codelineno-38-8" href="#__codelineno-38-8"></a> <span class="n">nautobot</span><span class="o">.</span><span class="n">apps</span><span class="o">.</span><span class="n">views</span><span class="o">.</span><span class="n">ObjectDestroyViewMixin</span><span class="p">,</span>
6099
+ <a id="__codelineno-38-9" name="__codelineno-38-9" href="#__codelineno-38-9"></a><span class="p">):</span>
6100
+ <a id="__codelineno-38-10" name="__codelineno-38-10" href="#__codelineno-38-10"></a>
6101
+ <a id="__codelineno-38-11" name="__codelineno-38-11" href="#__codelineno-38-11"></a> <span class="n">filterset_class</span> <span class="o">=</span> <span class="n">YourAppModelFilterSet</span>
6102
+ <a id="__codelineno-38-12" name="__codelineno-38-12" href="#__codelineno-38-12"></a> <span class="n">filterset_form_class</span> <span class="o">=</span> <span class="n">YourAppModelFilterForm</span>
6103
+ <a id="__codelineno-38-13" name="__codelineno-38-13" href="#__codelineno-38-13"></a> <span class="n">form_class</span> <span class="o">=</span> <span class="n">YourAppModelForm</span>
6104
+ <a id="__codelineno-38-14" name="__codelineno-38-14" href="#__codelineno-38-14"></a> <span class="n">queryset</span> <span class="o">=</span> <span class="n">YourAppModel</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
6105
+ <a id="__codelineno-38-15" name="__codelineno-38-15" href="#__codelineno-38-15"></a> <span class="n">serializer_class</span> <span class="o">=</span> <span class="n">serializers</span><span class="o">.</span><span class="n">YourAppModelSerializer</span>
6106
+ <a id="__codelineno-38-16" name="__codelineno-38-16" href="#__codelineno-38-16"></a> <span class="n">table_class</span> <span class="o">=</span> <span class="n">YourAppModelTable</span>
6107
+ <a id="__codelineno-38-17" name="__codelineno-38-17" href="#__codelineno-38-17"></a> <span class="c1"># You do not need to specify attributes that are not needed.</span>
4811
6108
  </code></pre></div>
4812
6109
  <p>Excluding unwanted urls from <code>NautobotUIViewSetRouter</code> is done for you at the ViewSet level. If you do not inherit the unwanted ViewMixins, the corresponding route from the router will not be published.</p>
4813
- <div class="highlight"><pre><span></span><code><a id="__codelineno-35-1" name="__codelineno-35-1" href="#__codelineno-35-1"></a><span class="c1"># urls.py</span>
4814
- <a id="__codelineno-35-2" name="__codelineno-35-2" href="#__codelineno-35-2"></a><span class="c1"># All the urls correspond to BulkViewMixins will not be published when you register your ViewSet with the router.</span>
4815
- <a id="__codelineno-35-3" name="__codelineno-35-3" href="#__codelineno-35-3"></a><span class="n">router</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s2">&quot;yourappmodel&quot;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">YourAppModelUIViewSet</span><span class="p">)</span>
6110
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-39-1" name="__codelineno-39-1" href="#__codelineno-39-1"></a><span class="c1"># urls.py</span>
6111
+ <a id="__codelineno-39-2" name="__codelineno-39-2" href="#__codelineno-39-2"></a><span class="c1"># All the urls correspond to BulkViewMixins will not be published when you register your ViewSet with the router.</span>
6112
+ <a id="__codelineno-39-3" name="__codelineno-39-3" href="#__codelineno-39-3"></a><span class="n">router</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s2">&quot;yourappmodel&quot;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">YourAppModelUIViewSet</span><span class="p">)</span>
4816
6113
  </code></pre></div>
4817
6114
  <h4 id="template-naming-for-nautobotuiviewset">Template Naming for NautobotUIViewSet<a class="headerlink" href="#template-naming-for-nautobotuiviewset" title="Permanent link">&para;</a></h4>
4818
6115
  <p>Template naming is very intuitive in NautobotUIViewSet. In <code>templates/yourapp</code> folder, name your templates following the convention <code>{model_name}_{action}.html</code>.</p>
@@ -4861,34 +6158,34 @@ namedtuple to assist in the configurations.</p>
4861
6158
  <p>With <code>NautobotUIViewSet</code> as the base UI ViewSet for <code>YourAppModel</code>, it is required to register your urls with the help of <code>NautobotUIViewSetRouter</code>.</p>
4862
6159
  <p>For a concrete example on how to use <code>NautobotUIViewSetRouter</code>, see <code>nautobot.circuits.urls</code>.</p>
4863
6160
  <p>Below is a theoretical <code>urls.py</code> file for <code>YourAppModel</code>:</p>
4864
- <div class="highlight"><pre><span></span><code><a id="__codelineno-36-1" name="__codelineno-36-1" href="#__codelineno-36-1"></a><span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span>
4865
- <a id="__codelineno-36-2" name="__codelineno-36-2" href="#__codelineno-36-2"></a>
4866
- <a id="__codelineno-36-3" name="__codelineno-36-3" href="#__codelineno-36-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps.urls</span> <span class="kn">import</span> <span class="n">NautobotUIViewSetRouter</span>
4867
- <a id="__codelineno-36-4" name="__codelineno-36-4" href="#__codelineno-36-4"></a><span class="kn">from</span> <span class="nn">your_app</span> <span class="kn">import</span> <span class="n">views</span>
4868
- <a id="__codelineno-36-5" name="__codelineno-36-5" href="#__codelineno-36-5"></a>
4869
- <a id="__codelineno-36-6" name="__codelineno-36-6" href="#__codelineno-36-6"></a>
4870
- <a id="__codelineno-36-7" name="__codelineno-36-7" href="#__codelineno-36-7"></a><span class="n">router</span> <span class="o">=</span> <span class="n">NautobotUIViewSetRouter</span><span class="p">()</span>
4871
- <a id="__codelineno-36-8" name="__codelineno-36-8" href="#__codelineno-36-8"></a><span class="n">router</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s2">&quot;yourappmodel&quot;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">YourAppModelUIViewSet</span><span class="p">)</span>
4872
- <a id="__codelineno-36-9" name="__codelineno-36-9" href="#__codelineno-36-9"></a>
4873
- <a id="__codelineno-36-10" name="__codelineno-36-10" href="#__codelineno-36-10"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
4874
- <a id="__codelineno-36-11" name="__codelineno-36-11" href="#__codelineno-36-11"></a> <span class="c1"># Extra urls that do not follow the patterns of `NautobotUIViewSetRouter` go here.</span>
4875
- <a id="__codelineno-36-12" name="__codelineno-36-12" href="#__codelineno-36-12"></a> <span class="c1"># changelog, notes and etc.</span>
4876
- <a id="__codelineno-36-13" name="__codelineno-36-13" href="#__codelineno-36-13"></a> <span class="o">...</span>
4877
- <a id="__codelineno-36-14" name="__codelineno-36-14" href="#__codelineno-36-14"></a> <span class="n">path</span><span class="p">(</span>
4878
- <a id="__codelineno-36-15" name="__codelineno-36-15" href="#__codelineno-36-15"></a> <span class="s2">&quot;yourappmodels/&lt;slug:slug&gt;/changelog/&quot;</span><span class="p">,</span>
4879
- <a id="__codelineno-36-16" name="__codelineno-36-16" href="#__codelineno-36-16"></a> <span class="n">ObjectChangeLogView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
4880
- <a id="__codelineno-36-17" name="__codelineno-36-17" href="#__codelineno-36-17"></a> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;yourappmodel_changelog&quot;</span><span class="p">,</span>
4881
- <a id="__codelineno-36-18" name="__codelineno-36-18" href="#__codelineno-36-18"></a> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="n">yourappmodel</span><span class="p">},</span>
4882
- <a id="__codelineno-36-19" name="__codelineno-36-19" href="#__codelineno-36-19"></a> <span class="p">),</span>
4883
- <a id="__codelineno-36-20" name="__codelineno-36-20" href="#__codelineno-36-20"></a> <span class="n">path</span><span class="p">(</span>
4884
- <a id="__codelineno-36-21" name="__codelineno-36-21" href="#__codelineno-36-21"></a> <span class="s2">&quot;yourappmodels/&lt;slug:slug&gt;/notes/&quot;</span><span class="p">,</span>
4885
- <a id="__codelineno-36-22" name="__codelineno-36-22" href="#__codelineno-36-22"></a> <span class="n">ObjectNotesView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
4886
- <a id="__codelineno-36-23" name="__codelineno-36-23" href="#__codelineno-36-23"></a> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;yourappmodel_notes&quot;</span><span class="p">,</span>
4887
- <a id="__codelineno-36-24" name="__codelineno-36-24" href="#__codelineno-36-24"></a> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="n">yourappmodel</span><span class="p">},</span>
4888
- <a id="__codelineno-36-25" name="__codelineno-36-25" href="#__codelineno-36-25"></a> <span class="p">),</span>
4889
- <a id="__codelineno-36-26" name="__codelineno-36-26" href="#__codelineno-36-26"></a> <span class="o">...</span>
4890
- <a id="__codelineno-36-27" name="__codelineno-36-27" href="#__codelineno-36-27"></a><span class="p">]</span>
4891
- <a id="__codelineno-36-28" name="__codelineno-36-28" href="#__codelineno-36-28"></a><span class="n">urlpatterns</span> <span class="o">+=</span> <span class="n">router</span><span class="o">.</span><span class="n">urls</span>
6161
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-40-1" name="__codelineno-40-1" href="#__codelineno-40-1"></a><span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span>
6162
+ <a id="__codelineno-40-2" name="__codelineno-40-2" href="#__codelineno-40-2"></a>
6163
+ <a id="__codelineno-40-3" name="__codelineno-40-3" href="#__codelineno-40-3"></a><span class="kn">from</span> <span class="nn">nautobot.apps.urls</span> <span class="kn">import</span> <span class="n">NautobotUIViewSetRouter</span>
6164
+ <a id="__codelineno-40-4" name="__codelineno-40-4" href="#__codelineno-40-4"></a><span class="kn">from</span> <span class="nn">your_app</span> <span class="kn">import</span> <span class="n">views</span>
6165
+ <a id="__codelineno-40-5" name="__codelineno-40-5" href="#__codelineno-40-5"></a>
6166
+ <a id="__codelineno-40-6" name="__codelineno-40-6" href="#__codelineno-40-6"></a>
6167
+ <a id="__codelineno-40-7" name="__codelineno-40-7" href="#__codelineno-40-7"></a><span class="n">router</span> <span class="o">=</span> <span class="n">NautobotUIViewSetRouter</span><span class="p">()</span>
6168
+ <a id="__codelineno-40-8" name="__codelineno-40-8" href="#__codelineno-40-8"></a><span class="n">router</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s2">&quot;yourappmodel&quot;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">YourAppModelUIViewSet</span><span class="p">)</span>
6169
+ <a id="__codelineno-40-9" name="__codelineno-40-9" href="#__codelineno-40-9"></a>
6170
+ <a id="__codelineno-40-10" name="__codelineno-40-10" href="#__codelineno-40-10"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
6171
+ <a id="__codelineno-40-11" name="__codelineno-40-11" href="#__codelineno-40-11"></a> <span class="c1"># Extra urls that do not follow the patterns of `NautobotUIViewSetRouter` go here.</span>
6172
+ <a id="__codelineno-40-12" name="__codelineno-40-12" href="#__codelineno-40-12"></a> <span class="c1"># changelog, notes and etc.</span>
6173
+ <a id="__codelineno-40-13" name="__codelineno-40-13" href="#__codelineno-40-13"></a> <span class="o">...</span>
6174
+ <a id="__codelineno-40-14" name="__codelineno-40-14" href="#__codelineno-40-14"></a> <span class="n">path</span><span class="p">(</span>
6175
+ <a id="__codelineno-40-15" name="__codelineno-40-15" href="#__codelineno-40-15"></a> <span class="s2">&quot;yourappmodels/&lt;uuid:pk&gt;/changelog/&quot;</span><span class="p">,</span>
6176
+ <a id="__codelineno-40-16" name="__codelineno-40-16" href="#__codelineno-40-16"></a> <span class="n">ObjectChangeLogView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
6177
+ <a id="__codelineno-40-17" name="__codelineno-40-17" href="#__codelineno-40-17"></a> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;yourappmodel_changelog&quot;</span><span class="p">,</span>
6178
+ <a id="__codelineno-40-18" name="__codelineno-40-18" href="#__codelineno-40-18"></a> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="n">yourappmodel</span><span class="p">},</span>
6179
+ <a id="__codelineno-40-19" name="__codelineno-40-19" href="#__codelineno-40-19"></a> <span class="p">),</span>
6180
+ <a id="__codelineno-40-20" name="__codelineno-40-20" href="#__codelineno-40-20"></a> <span class="n">path</span><span class="p">(</span>
6181
+ <a id="__codelineno-40-21" name="__codelineno-40-21" href="#__codelineno-40-21"></a> <span class="s2">&quot;yourappmodels/&lt;uuid:pk&gt;/notes/&quot;</span><span class="p">,</span>
6182
+ <a id="__codelineno-40-22" name="__codelineno-40-22" href="#__codelineno-40-22"></a> <span class="n">ObjectNotesView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
6183
+ <a id="__codelineno-40-23" name="__codelineno-40-23" href="#__codelineno-40-23"></a> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;yourappmodel_notes&quot;</span><span class="p">,</span>
6184
+ <a id="__codelineno-40-24" name="__codelineno-40-24" href="#__codelineno-40-24"></a> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="n">yourappmodel</span><span class="p">},</span>
6185
+ <a id="__codelineno-40-25" name="__codelineno-40-25" href="#__codelineno-40-25"></a> <span class="p">),</span>
6186
+ <a id="__codelineno-40-26" name="__codelineno-40-26" href="#__codelineno-40-26"></a> <span class="o">...</span>
6187
+ <a id="__codelineno-40-27" name="__codelineno-40-27" href="#__codelineno-40-27"></a><span class="p">]</span>
6188
+ <a id="__codelineno-40-28" name="__codelineno-40-28" href="#__codelineno-40-28"></a><span class="n">urlpatterns</span> <span class="o">+=</span> <span class="n">router</span><span class="o">.</span><span class="n">urls</span>
4892
6189
  </code></pre></div>
4893
6190
  <div class="admonition version-added">
4894
6191
  <p class="admonition-title">Added in version 1.5.1</p>
@@ -4896,21 +6193,21 @@ namedtuple to assist in the configurations.</p>
4896
6193
  </div>
4897
6194
  <h3 id="utilizing-generic-django-views">Utilizing Generic Django Views<a class="headerlink" href="#utilizing-generic-django-views" title="Permanent link">&para;</a></h3>
4898
6195
  <p>The use of <code>generic</code> Django views can aid in app development. As an example, let's write a view which displays a random animal and the sound it makes. First, create the view in <code>views.py</code>:</p>
4899
- <div class="highlight"><pre><span></span><code><a id="__codelineno-37-1" name="__codelineno-37-1" href="#__codelineno-37-1"></a><span class="c1"># views.py</span>
4900
- <a id="__codelineno-37-2" name="__codelineno-37-2" href="#__codelineno-37-2"></a><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
4901
- <a id="__codelineno-37-3" name="__codelineno-37-3" href="#__codelineno-37-3"></a><span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">View</span>
4902
- <a id="__codelineno-37-4" name="__codelineno-37-4" href="#__codelineno-37-4"></a>
4903
- <a id="__codelineno-37-5" name="__codelineno-37-5" href="#__codelineno-37-5"></a><span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Animal</span>
4904
- <a id="__codelineno-37-6" name="__codelineno-37-6" href="#__codelineno-37-6"></a>
4905
- <a id="__codelineno-37-7" name="__codelineno-37-7" href="#__codelineno-37-7"></a>
4906
- <a id="__codelineno-37-8" name="__codelineno-37-8" href="#__codelineno-37-8"></a><span class="k">class</span> <span class="nc">RandomAnimalView</span><span class="p">(</span><span class="n">View</span><span class="p">):</span>
4907
- <a id="__codelineno-37-9" name="__codelineno-37-9" href="#__codelineno-37-9"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Display a randomly-selected Animal.&quot;&quot;&quot;</span>
4908
- <a id="__codelineno-37-10" name="__codelineno-37-10" href="#__codelineno-37-10"></a>
4909
- <a id="__codelineno-37-11" name="__codelineno-37-11" href="#__codelineno-37-11"></a> <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
4910
- <a id="__codelineno-37-12" name="__codelineno-37-12" href="#__codelineno-37-12"></a> <span class="n">animal</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s1">&#39;?&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
4911
- <a id="__codelineno-37-13" name="__codelineno-37-13" href="#__codelineno-37-13"></a> <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;nautobot_animal_sounds/animal.html&#39;</span><span class="p">,</span> <span class="p">{</span>
4912
- <a id="__codelineno-37-14" name="__codelineno-37-14" href="#__codelineno-37-14"></a> <span class="s1">&#39;animal&#39;</span><span class="p">:</span> <span class="n">animal</span><span class="p">,</span>
4913
- <a id="__codelineno-37-15" name="__codelineno-37-15" href="#__codelineno-37-15"></a> <span class="p">})</span>
6196
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a><span class="c1"># views.py</span>
6197
+ <a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">render</span>
6198
+ <a id="__codelineno-41-3" name="__codelineno-41-3" href="#__codelineno-41-3"></a><span class="kn">from</span> <span class="nn">django.views.generic</span> <span class="kn">import</span> <span class="n">View</span>
6199
+ <a id="__codelineno-41-4" name="__codelineno-41-4" href="#__codelineno-41-4"></a>
6200
+ <a id="__codelineno-41-5" name="__codelineno-41-5" href="#__codelineno-41-5"></a><span class="kn">from</span> <span class="nn">.models</span> <span class="kn">import</span> <span class="n">Animal</span>
6201
+ <a id="__codelineno-41-6" name="__codelineno-41-6" href="#__codelineno-41-6"></a>
6202
+ <a id="__codelineno-41-7" name="__codelineno-41-7" href="#__codelineno-41-7"></a>
6203
+ <a id="__codelineno-41-8" name="__codelineno-41-8" href="#__codelineno-41-8"></a><span class="k">class</span> <span class="nc">RandomAnimalView</span><span class="p">(</span><span class="n">View</span><span class="p">):</span>
6204
+ <a id="__codelineno-41-9" name="__codelineno-41-9" href="#__codelineno-41-9"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Display a randomly-selected Animal.&quot;&quot;&quot;</span>
6205
+ <a id="__codelineno-41-10" name="__codelineno-41-10" href="#__codelineno-41-10"></a>
6206
+ <a id="__codelineno-41-11" name="__codelineno-41-11" href="#__codelineno-41-11"></a> <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">):</span>
6207
+ <a id="__codelineno-41-12" name="__codelineno-41-12" href="#__codelineno-41-12"></a> <span class="n">animal</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s1">&#39;?&#39;</span><span class="p">)</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
6208
+ <a id="__codelineno-41-13" name="__codelineno-41-13" href="#__codelineno-41-13"></a> <span class="k">return</span> <span class="n">render</span><span class="p">(</span><span class="n">request</span><span class="p">,</span> <span class="s1">&#39;nautobot_animal_sounds/animal.html&#39;</span><span class="p">,</span> <span class="p">{</span>
6209
+ <a id="__codelineno-41-14" name="__codelineno-41-14" href="#__codelineno-41-14"></a> <span class="s1">&#39;animal&#39;</span><span class="p">:</span> <span class="n">animal</span><span class="p">,</span>
6210
+ <a id="__codelineno-41-15" name="__codelineno-41-15" href="#__codelineno-41-15"></a> <span class="p">})</span>
4914
6211
  </code></pre></div>
4915
6212
  <p>This view retrieves a random animal from the database and and passes it as a context variable when rendering a template named <code>animal.html</code>, which doesn't exist yet. To create this template, first create a directory named <code>templates/nautobot_animal_sounds/</code> within the app source directory. (We use the app's name as a subdirectory to guard against naming collisions with other apps.) Then, create a template named <code>animal.html</code> as described below.</p>
4916
6213
  <h3 id="utilizing-nautobot-generic-views">Utilizing Nautobot Generic Views<a class="headerlink" href="#utilizing-nautobot-generic-views" title="Permanent link">&para;</a></h3>
@@ -4928,25 +6225,25 @@ namedtuple to assist in the configurations.</p>
4928
6225
  <li><code>javascript</code> - A section at the end of the page for including Javascript code</li>
4929
6226
  </ul>
4930
6227
  <p>For more information on how template blocks work, consult the <a href="https://docs.djangoproject.com/en/stable/ref/templates/builtins/#block">Django documentation</a>.</p>
4931
- <div class="highlight"><pre><span></span><code><a id="__codelineno-38-1" name="__codelineno-38-1" href="#__codelineno-38-1"></a>{# templates/nautobot_animal_sounds/animal.html #}
4932
- <a id="__codelineno-38-2" name="__codelineno-38-2" href="#__codelineno-38-2"></a>{% extends &#39;base.html&#39; %}
4933
- <a id="__codelineno-38-3" name="__codelineno-38-3" href="#__codelineno-38-3"></a>
4934
- <a id="__codelineno-38-4" name="__codelineno-38-4" href="#__codelineno-38-4"></a>{% block content %}
4935
- <a id="__codelineno-38-5" name="__codelineno-38-5" href="#__codelineno-38-5"></a> {% with config=settings.PLUGINS_CONFIG.nautobot_animal_sounds %}
4936
- <a id="__codelineno-38-6" name="__codelineno-38-6" href="#__codelineno-38-6"></a> &lt;h2 class=&quot;text-center&quot; style=&quot;margin-top: 200px&quot;&gt;
4937
- <a id="__codelineno-38-7" name="__codelineno-38-7" href="#__codelineno-38-7"></a> {% if animal %}
4938
- <a id="__codelineno-38-8" name="__codelineno-38-8" href="#__codelineno-38-8"></a> The {{ animal.name|lower }} says
4939
- <a id="__codelineno-38-9" name="__codelineno-38-9" href="#__codelineno-38-9"></a> {% if config.loud %}
4940
- <a id="__codelineno-38-10" name="__codelineno-38-10" href="#__codelineno-38-10"></a> {{ animal.sound|upper }}!
4941
- <a id="__codelineno-38-11" name="__codelineno-38-11" href="#__codelineno-38-11"></a> {% else %}
4942
- <a id="__codelineno-38-12" name="__codelineno-38-12" href="#__codelineno-38-12"></a> {{ animal.sound }}
4943
- <a id="__codelineno-38-13" name="__codelineno-38-13" href="#__codelineno-38-13"></a> {% endif %}
4944
- <a id="__codelineno-38-14" name="__codelineno-38-14" href="#__codelineno-38-14"></a> {% else %}
4945
- <a id="__codelineno-38-15" name="__codelineno-38-15" href="#__codelineno-38-15"></a> No animals have been created yet!
4946
- <a id="__codelineno-38-16" name="__codelineno-38-16" href="#__codelineno-38-16"></a> {% endif %}
4947
- <a id="__codelineno-38-17" name="__codelineno-38-17" href="#__codelineno-38-17"></a> &lt;/h2&gt;
4948
- <a id="__codelineno-38-18" name="__codelineno-38-18" href="#__codelineno-38-18"></a> {% endwith %}
4949
- <a id="__codelineno-38-19" name="__codelineno-38-19" href="#__codelineno-38-19"></a>{% endblock %}
6228
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-42-1" name="__codelineno-42-1" href="#__codelineno-42-1"></a>{# templates/nautobot_animal_sounds/animal.html #}
6229
+ <a id="__codelineno-42-2" name="__codelineno-42-2" href="#__codelineno-42-2"></a>{% extends &#39;base.html&#39; %}
6230
+ <a id="__codelineno-42-3" name="__codelineno-42-3" href="#__codelineno-42-3"></a>
6231
+ <a id="__codelineno-42-4" name="__codelineno-42-4" href="#__codelineno-42-4"></a>{% block content %}
6232
+ <a id="__codelineno-42-5" name="__codelineno-42-5" href="#__codelineno-42-5"></a> {% with config=settings.PLUGINS_CONFIG.nautobot_animal_sounds %}
6233
+ <a id="__codelineno-42-6" name="__codelineno-42-6" href="#__codelineno-42-6"></a> &lt;h2 class=&quot;text-center&quot; style=&quot;margin-top: 200px&quot;&gt;
6234
+ <a id="__codelineno-42-7" name="__codelineno-42-7" href="#__codelineno-42-7"></a> {% if animal %}
6235
+ <a id="__codelineno-42-8" name="__codelineno-42-8" href="#__codelineno-42-8"></a> The {{ animal.name|lower }} says
6236
+ <a id="__codelineno-42-9" name="__codelineno-42-9" href="#__codelineno-42-9"></a> {% if config.loud %}
6237
+ <a id="__codelineno-42-10" name="__codelineno-42-10" href="#__codelineno-42-10"></a> {{ animal.sound|upper }}!
6238
+ <a id="__codelineno-42-11" name="__codelineno-42-11" href="#__codelineno-42-11"></a> {% else %}
6239
+ <a id="__codelineno-42-12" name="__codelineno-42-12" href="#__codelineno-42-12"></a> {{ animal.sound }}
6240
+ <a id="__codelineno-42-13" name="__codelineno-42-13" href="#__codelineno-42-13"></a> {% endif %}
6241
+ <a id="__codelineno-42-14" name="__codelineno-42-14" href="#__codelineno-42-14"></a> {% else %}
6242
+ <a id="__codelineno-42-15" name="__codelineno-42-15" href="#__codelineno-42-15"></a> No animals have been created yet!
6243
+ <a id="__codelineno-42-16" name="__codelineno-42-16" href="#__codelineno-42-16"></a> {% endif %}
6244
+ <a id="__codelineno-42-17" name="__codelineno-42-17" href="#__codelineno-42-17"></a> &lt;/h2&gt;
6245
+ <a id="__codelineno-42-18" name="__codelineno-42-18" href="#__codelineno-42-18"></a> {% endwith %}
6246
+ <a id="__codelineno-42-19" name="__codelineno-42-19" href="#__codelineno-42-19"></a>{% endblock %}
4950
6247
  </code></pre></div>
4951
6248
  <p>The first line of the template instructs Django to extend the Nautobot base template and inject our custom content within its <code>content</code> block.</p>
4952
6249
  <div class="admonition note">
@@ -4955,15 +6252,15 @@ namedtuple to assist in the configurations.</p>
4955
6252
  </div>
4956
6253
  <h3 id="registering-url-patterns">Registering URL Patterns<a class="headerlink" href="#registering-url-patterns" title="Permanent link">&para;</a></h3>
4957
6254
  <p>Finally, to make the view accessible to users, we need to register a URL for it. We do this in <code>urls.py</code> by defining a <code>urlpatterns</code> variable containing a list of paths.</p>
4958
- <div class="highlight"><pre><span></span><code><a id="__codelineno-39-1" name="__codelineno-39-1" href="#__codelineno-39-1"></a><span class="c1"># urls.py</span>
4959
- <a id="__codelineno-39-2" name="__codelineno-39-2" href="#__codelineno-39-2"></a><span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span>
4960
- <a id="__codelineno-39-3" name="__codelineno-39-3" href="#__codelineno-39-3"></a>
4961
- <a id="__codelineno-39-4" name="__codelineno-39-4" href="#__codelineno-39-4"></a><span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">views</span>
4962
- <a id="__codelineno-39-5" name="__codelineno-39-5" href="#__codelineno-39-5"></a>
4963
- <a id="__codelineno-39-6" name="__codelineno-39-6" href="#__codelineno-39-6"></a>
4964
- <a id="__codelineno-39-7" name="__codelineno-39-7" href="#__codelineno-39-7"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
4965
- <a id="__codelineno-39-8" name="__codelineno-39-8" href="#__codelineno-39-8"></a> <span class="n">path</span><span class="p">(</span><span class="s1">&#39;random/&#39;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">RandomAnimalView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;random_animal&#39;</span><span class="p">),</span>
4966
- <a id="__codelineno-39-9" name="__codelineno-39-9" href="#__codelineno-39-9"></a><span class="p">]</span>
6255
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-43-1" name="__codelineno-43-1" href="#__codelineno-43-1"></a><span class="c1"># urls.py</span>
6256
+ <a id="__codelineno-43-2" name="__codelineno-43-2" href="#__codelineno-43-2"></a><span class="kn">from</span> <span class="nn">django.urls</span> <span class="kn">import</span> <span class="n">path</span>
6257
+ <a id="__codelineno-43-3" name="__codelineno-43-3" href="#__codelineno-43-3"></a>
6258
+ <a id="__codelineno-43-4" name="__codelineno-43-4" href="#__codelineno-43-4"></a><span class="kn">from</span> <span class="nn">.</span> <span class="kn">import</span> <span class="n">views</span>
6259
+ <a id="__codelineno-43-5" name="__codelineno-43-5" href="#__codelineno-43-5"></a>
6260
+ <a id="__codelineno-43-6" name="__codelineno-43-6" href="#__codelineno-43-6"></a>
6261
+ <a id="__codelineno-43-7" name="__codelineno-43-7" href="#__codelineno-43-7"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
6262
+ <a id="__codelineno-43-8" name="__codelineno-43-8" href="#__codelineno-43-8"></a> <span class="n">path</span><span class="p">(</span><span class="s1">&#39;random/&#39;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">RandomAnimalView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;random_animal&#39;</span><span class="p">),</span>
6263
+ <a id="__codelineno-43-9" name="__codelineno-43-9" href="#__codelineno-43-9"></a><span class="p">]</span>
4967
6264
  </code></pre></div>
4968
6265
  <p>A URL pattern has three components:</p>
4969
6266
  <ul>
@@ -4979,51 +6276,51 @@ namedtuple to assist in the configurations.</p>
4979
6276
  <h2 id="adding-rest-api-endpoints">Adding REST API Endpoints<a class="headerlink" href="#adding-rest-api-endpoints" title="Permanent link">&para;</a></h2>
4980
6277
  <p>Apps can declare custom endpoints on Nautobot's REST API to retrieve or manipulate models or other data. These behave very similarly to views, except that instead of rendering arbitrary content using a template, data is returned in JSON format using a serializer. Nautobot uses the <a href="https://www.django-rest-framework.org/">Django REST Framework</a>, which makes writing API serializers and views very simple.</p>
4981
6278
  <p>First, create a serializer for the <code>Animal</code> model, in <code>api/serializers.py</code>:</p>
4982
- <div class="highlight"><pre><span></span><code><a id="__codelineno-40-1" name="__codelineno-40-1" href="#__codelineno-40-1"></a><span class="c1"># api/serializers.py</span>
4983
- <a id="__codelineno-40-2" name="__codelineno-40-2" href="#__codelineno-40-2"></a><span class="kn">from</span> <span class="nn">nautobot.apps.api</span> <span class="kn">import</span> <span class="n">ValidatedModelSerializer</span>
4984
- <a id="__codelineno-40-3" name="__codelineno-40-3" href="#__codelineno-40-3"></a>
4985
- <a id="__codelineno-40-4" name="__codelineno-40-4" href="#__codelineno-40-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
4986
- <a id="__codelineno-40-5" name="__codelineno-40-5" href="#__codelineno-40-5"></a>
4987
- <a id="__codelineno-40-6" name="__codelineno-40-6" href="#__codelineno-40-6"></a>
4988
- <a id="__codelineno-40-7" name="__codelineno-40-7" href="#__codelineno-40-7"></a><span class="k">class</span> <span class="nc">AnimalSerializer</span><span class="p">(</span><span class="n">ValidatedModelSerializer</span><span class="p">):</span>
4989
- <a id="__codelineno-40-8" name="__codelineno-40-8" href="#__codelineno-40-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;API serializer for interacting with Animal objects.&quot;&quot;&quot;</span>
4990
- <a id="__codelineno-40-9" name="__codelineno-40-9" href="#__codelineno-40-9"></a>
4991
- <a id="__codelineno-40-10" name="__codelineno-40-10" href="#__codelineno-40-10"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
4992
- <a id="__codelineno-40-11" name="__codelineno-40-11" href="#__codelineno-40-11"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">Animal</span>
4993
- <a id="__codelineno-40-12" name="__codelineno-40-12" href="#__codelineno-40-12"></a> <span class="n">fields</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="s1">&#39;name&#39;</span><span class="p">,</span> <span class="s1">&#39;sound&#39;</span><span class="p">)</span>
6279
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-44-1" name="__codelineno-44-1" href="#__codelineno-44-1"></a><span class="c1"># api/serializers.py</span>
6280
+ <a id="__codelineno-44-2" name="__codelineno-44-2" href="#__codelineno-44-2"></a><span class="kn">from</span> <span class="nn">nautobot.apps.api</span> <span class="kn">import</span> <span class="n">ValidatedModelSerializer</span>
6281
+ <a id="__codelineno-44-3" name="__codelineno-44-3" href="#__codelineno-44-3"></a>
6282
+ <a id="__codelineno-44-4" name="__codelineno-44-4" href="#__codelineno-44-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
6283
+ <a id="__codelineno-44-5" name="__codelineno-44-5" href="#__codelineno-44-5"></a>
6284
+ <a id="__codelineno-44-6" name="__codelineno-44-6" href="#__codelineno-44-6"></a>
6285
+ <a id="__codelineno-44-7" name="__codelineno-44-7" href="#__codelineno-44-7"></a><span class="k">class</span> <span class="nc">AnimalSerializer</span><span class="p">(</span><span class="n">ValidatedModelSerializer</span><span class="p">):</span>
6286
+ <a id="__codelineno-44-8" name="__codelineno-44-8" href="#__codelineno-44-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;API serializer for interacting with Animal objects.&quot;&quot;&quot;</span>
6287
+ <a id="__codelineno-44-9" name="__codelineno-44-9" href="#__codelineno-44-9"></a>
6288
+ <a id="__codelineno-44-10" name="__codelineno-44-10" href="#__codelineno-44-10"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
6289
+ <a id="__codelineno-44-11" name="__codelineno-44-11" href="#__codelineno-44-11"></a> <span class="n">model</span> <span class="o">=</span> <span class="n">Animal</span>
6290
+ <a id="__codelineno-44-12" name="__codelineno-44-12" href="#__codelineno-44-12"></a> <span class="n">fields</span> <span class="o">=</span> <span class="p">(</span><span class="s1">&#39;id&#39;</span><span class="p">,</span> <span class="s1">&#39;name&#39;</span><span class="p">,</span> <span class="s1">&#39;sound&#39;</span><span class="p">)</span>
4994
6291
  </code></pre></div>
4995
6292
  <div class="admonition tip">
4996
6293
  <p class="admonition-title">Tip</p>
4997
6294
  <p>For more full-featured models, you should use one of the other base classes from <code>nautobot.apps.api</code> such as <code>NautobotModelSerializer</code>.</p>
4998
6295
  </div>
4999
6296
  <p>Next, create a generic API view set that allows basic CRUD (create, read, update, and delete) operations for Animal instances. This is defined in <code>api/views.py</code>:</p>
5000
- <div class="highlight"><pre><span></span><code><a id="__codelineno-41-1" name="__codelineno-41-1" href="#__codelineno-41-1"></a><span class="c1"># api/views.py</span>
5001
- <a id="__codelineno-41-2" name="__codelineno-41-2" href="#__codelineno-41-2"></a><span class="kn">from</span> <span class="nn">rest_framework.viewsets</span> <span class="kn">import</span> <span class="n">ModelViewSet</span>
5002
- <a id="__codelineno-41-3" name="__codelineno-41-3" href="#__codelineno-41-3"></a>
5003
- <a id="__codelineno-41-4" name="__codelineno-41-4" href="#__codelineno-41-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
5004
- <a id="__codelineno-41-5" name="__codelineno-41-5" href="#__codelineno-41-5"></a><span class="kn">from</span> <span class="nn">.serializers</span> <span class="kn">import</span> <span class="n">AnimalSerializer</span>
5005
- <a id="__codelineno-41-6" name="__codelineno-41-6" href="#__codelineno-41-6"></a>
5006
- <a id="__codelineno-41-7" name="__codelineno-41-7" href="#__codelineno-41-7"></a>
5007
- <a id="__codelineno-41-8" name="__codelineno-41-8" href="#__codelineno-41-8"></a><span class="k">class</span> <span class="nc">AnimalViewSet</span><span class="p">(</span><span class="n">ModelViewSet</span><span class="p">):</span>
5008
- <a id="__codelineno-41-9" name="__codelineno-41-9" href="#__codelineno-41-9"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;API viewset for interacting with Animal objects.&quot;&quot;&quot;</span>
5009
- <a id="__codelineno-41-10" name="__codelineno-41-10" href="#__codelineno-41-10"></a>
5010
- <a id="__codelineno-41-11" name="__codelineno-41-11" href="#__codelineno-41-11"></a> <span class="n">queryset</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
5011
- <a id="__codelineno-41-12" name="__codelineno-41-12" href="#__codelineno-41-12"></a> <span class="n">serializer_class</span> <span class="o">=</span> <span class="n">AnimalSerializer</span>
6297
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-45-1" name="__codelineno-45-1" href="#__codelineno-45-1"></a><span class="c1"># api/views.py</span>
6298
+ <a id="__codelineno-45-2" name="__codelineno-45-2" href="#__codelineno-45-2"></a><span class="kn">from</span> <span class="nn">rest_framework.viewsets</span> <span class="kn">import</span> <span class="n">ModelViewSet</span>
6299
+ <a id="__codelineno-45-3" name="__codelineno-45-3" href="#__codelineno-45-3"></a>
6300
+ <a id="__codelineno-45-4" name="__codelineno-45-4" href="#__codelineno-45-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
6301
+ <a id="__codelineno-45-5" name="__codelineno-45-5" href="#__codelineno-45-5"></a><span class="kn">from</span> <span class="nn">.serializers</span> <span class="kn">import</span> <span class="n">AnimalSerializer</span>
6302
+ <a id="__codelineno-45-6" name="__codelineno-45-6" href="#__codelineno-45-6"></a>
6303
+ <a id="__codelineno-45-7" name="__codelineno-45-7" href="#__codelineno-45-7"></a>
6304
+ <a id="__codelineno-45-8" name="__codelineno-45-8" href="#__codelineno-45-8"></a><span class="k">class</span> <span class="nc">AnimalViewSet</span><span class="p">(</span><span class="n">ModelViewSet</span><span class="p">):</span>
6305
+ <a id="__codelineno-45-9" name="__codelineno-45-9" href="#__codelineno-45-9"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;API viewset for interacting with Animal objects.&quot;&quot;&quot;</span>
6306
+ <a id="__codelineno-45-10" name="__codelineno-45-10" href="#__codelineno-45-10"></a>
6307
+ <a id="__codelineno-45-11" name="__codelineno-45-11" href="#__codelineno-45-11"></a> <span class="n">queryset</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">()</span>
6308
+ <a id="__codelineno-45-12" name="__codelineno-45-12" href="#__codelineno-45-12"></a> <span class="n">serializer_class</span> <span class="o">=</span> <span class="n">AnimalSerializer</span>
5012
6309
  </code></pre></div>
5013
6310
  <div class="admonition tip">
5014
6311
  <p class="admonition-title">Tip</p>
5015
6312
  <p>For more full-featured models, you should probably use <code>nautobot.apps.api.NautobotModelViewSet</code> as a base class.</p>
5016
6313
  </div>
5017
6314
  <p>Finally, register a URL for our endpoint in <code>api/urls.py</code>. This file <strong>must</strong> define a variable named <code>urlpatterns</code>.</p>
5018
- <div class="highlight"><pre><span></span><code><a id="__codelineno-42-1" name="__codelineno-42-1" href="#__codelineno-42-1"></a><span class="c1"># api/urls.py</span>
5019
- <a id="__codelineno-42-2" name="__codelineno-42-2" href="#__codelineno-42-2"></a><span class="kn">from</span> <span class="nn">rest_framework</span> <span class="kn">import</span> <span class="n">routers</span>
5020
- <a id="__codelineno-42-3" name="__codelineno-42-3" href="#__codelineno-42-3"></a>
5021
- <a id="__codelineno-42-4" name="__codelineno-42-4" href="#__codelineno-42-4"></a><span class="kn">from</span> <span class="nn">.views</span> <span class="kn">import</span> <span class="n">AnimalViewSet</span>
5022
- <a id="__codelineno-42-5" name="__codelineno-42-5" href="#__codelineno-42-5"></a>
5023
- <a id="__codelineno-42-6" name="__codelineno-42-6" href="#__codelineno-42-6"></a>
5024
- <a id="__codelineno-42-7" name="__codelineno-42-7" href="#__codelineno-42-7"></a><span class="n">router</span> <span class="o">=</span> <span class="n">routers</span><span class="o">.</span><span class="n">DefaultRouter</span><span class="p">()</span>
5025
- <a id="__codelineno-42-8" name="__codelineno-42-8" href="#__codelineno-42-8"></a><span class="n">router</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;animals&#39;</span><span class="p">,</span> <span class="n">AnimalViewSet</span><span class="p">)</span>
5026
- <a id="__codelineno-42-9" name="__codelineno-42-9" href="#__codelineno-42-9"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="n">router</span><span class="o">.</span><span class="n">urls</span>
6315
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-46-1" name="__codelineno-46-1" href="#__codelineno-46-1"></a><span class="c1"># api/urls.py</span>
6316
+ <a id="__codelineno-46-2" name="__codelineno-46-2" href="#__codelineno-46-2"></a><span class="kn">from</span> <span class="nn">rest_framework</span> <span class="kn">import</span> <span class="n">routers</span>
6317
+ <a id="__codelineno-46-3" name="__codelineno-46-3" href="#__codelineno-46-3"></a>
6318
+ <a id="__codelineno-46-4" name="__codelineno-46-4" href="#__codelineno-46-4"></a><span class="kn">from</span> <span class="nn">.views</span> <span class="kn">import</span> <span class="n">AnimalViewSet</span>
6319
+ <a id="__codelineno-46-5" name="__codelineno-46-5" href="#__codelineno-46-5"></a>
6320
+ <a id="__codelineno-46-6" name="__codelineno-46-6" href="#__codelineno-46-6"></a>
6321
+ <a id="__codelineno-46-7" name="__codelineno-46-7" href="#__codelineno-46-7"></a><span class="n">router</span> <span class="o">=</span> <span class="n">routers</span><span class="o">.</span><span class="n">DefaultRouter</span><span class="p">()</span>
6322
+ <a id="__codelineno-46-8" name="__codelineno-46-8" href="#__codelineno-46-8"></a><span class="n">router</span><span class="o">.</span><span class="n">register</span><span class="p">(</span><span class="s1">&#39;animals&#39;</span><span class="p">,</span> <span class="n">AnimalViewSet</span><span class="p">)</span>
6323
+ <a id="__codelineno-46-9" name="__codelineno-46-9" href="#__codelineno-46-9"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="n">router</span><span class="o">.</span><span class="n">urls</span>
5027
6324
  </code></pre></div>
5028
6325
  <p>With these three components in place, we can request <code>/api/plugins/animal-sounds/animals/</code> to retrieve a list of all Animal objects defined.</p>
5029
6326
  <p><img alt="Nautobot REST API app endpoint" src="../media/plugins/plugin_rest_api_endpoint.png" /></p>
@@ -5033,13 +6330,13 @@ namedtuple to assist in the configurations.</p>
5033
6330
  </div>
5034
6331
  <h2 id="adding-help-documentation">Adding Help Documentation<a class="headerlink" href="#adding-help-documentation" title="Permanent link">&para;</a></h2>
5035
6332
  <p>If you are using the <code>generic.ObjectEditView</code> from Nautobot for your object, the form can automatically include a help icon with a link to that object's documentation. For this to happen, Nautobot must be able to find the documentation for this object in a specific directory tree within your app:</p>
5036
- <div class="highlight"><pre><span></span><code><a id="__codelineno-43-1" name="__codelineno-43-1" href="#__codelineno-43-1"></a>app_name/ # &quot;nautobot_animal_sounds&quot;
5037
- <a id="__codelineno-43-2" name="__codelineno-43-2" href="#__codelineno-43-2"></a> - static/
5038
- <a id="__codelineno-43-3" name="__codelineno-43-3" href="#__codelineno-43-3"></a> - app_name/ # &quot;nautobot_animal_sounds&quot;
5039
- <a id="__codelineno-43-4" name="__codelineno-43-4" href="#__codelineno-43-4"></a> - docs/
5040
- <a id="__codelineno-43-5" name="__codelineno-43-5" href="#__codelineno-43-5"></a> - index.html
5041
- <a id="__codelineno-43-6" name="__codelineno-43-6" href="#__codelineno-43-6"></a> - models/
5042
- <a id="__codelineno-43-7" name="__codelineno-43-7" href="#__codelineno-43-7"></a> - object_model.html # &quot;animal.html&quot;
6333
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-47-1" name="__codelineno-47-1" href="#__codelineno-47-1"></a>app_name/ # &quot;nautobot_animal_sounds&quot;
6334
+ <a id="__codelineno-47-2" name="__codelineno-47-2" href="#__codelineno-47-2"></a> - static/
6335
+ <a id="__codelineno-47-3" name="__codelineno-47-3" href="#__codelineno-47-3"></a> - app_name/ # &quot;nautobot_animal_sounds&quot;
6336
+ <a id="__codelineno-47-4" name="__codelineno-47-4" href="#__codelineno-47-4"></a> - docs/
6337
+ <a id="__codelineno-47-5" name="__codelineno-47-5" href="#__codelineno-47-5"></a> - index.html
6338
+ <a id="__codelineno-47-6" name="__codelineno-47-6" href="#__codelineno-47-6"></a> - models/
6339
+ <a id="__codelineno-47-7" name="__codelineno-47-7" href="#__codelineno-47-7"></a> - object_model.html # &quot;animal.html&quot;
5043
6340
  </code></pre></div>
5044
6341
  <h2 id="overriding-existing-functionality">Overriding Existing Functionality<a class="headerlink" href="#overriding-existing-functionality" title="Permanent link">&para;</a></h2>
5045
6342
  <h3 id="replacing-views">Replacing Views<a class="headerlink" href="#replacing-views" title="Permanent link">&para;</a></h3>
@@ -5049,42 +6346,42 @@ namedtuple to assist in the configurations.</p>
5049
6346
  <p>You may override any of the core or app views by providing an <code>override_views</code> <code>dict</code> in an app's <code>views.py</code> file.</p>
5050
6347
  <p>To override a view, you must specify the view's fully qualified name as the <code>dict</code> key which consists of the app name followed by the view's name separated by a colon, for instance <code>dcim:device</code>. The <code>dict</code> value should be the overriding view function.</p>
5051
6348
  <p>A simple example to override the device detail view:</p>
5052
- <div class="highlight"><pre><span></span><code><a id="__codelineno-44-1" name="__codelineno-44-1" href="#__codelineno-44-1"></a><span class="c1"># views.py</span>
5053
- <a id="__codelineno-44-2" name="__codelineno-44-2" href="#__codelineno-44-2"></a><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">HttpResponse</span>
5054
- <a id="__codelineno-44-3" name="__codelineno-44-3" href="#__codelineno-44-3"></a><span class="kn">from</span> <span class="nn">django.views</span> <span class="kn">import</span> <span class="n">generic</span>
5055
- <a id="__codelineno-44-4" name="__codelineno-44-4" href="#__codelineno-44-4"></a>
5056
- <a id="__codelineno-44-5" name="__codelineno-44-5" href="#__codelineno-44-5"></a>
5057
- <a id="__codelineno-44-6" name="__codelineno-44-6" href="#__codelineno-44-6"></a><span class="k">class</span> <span class="nc">DeviceViewOverride</span><span class="p">(</span><span class="n">generic</span><span class="o">.</span><span class="n">View</span><span class="p">):</span>
5058
- <a id="__codelineno-44-7" name="__codelineno-44-7" href="#__codelineno-44-7"></a> <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
5059
- <a id="__codelineno-44-8" name="__codelineno-44-8" href="#__codelineno-44-8"></a> <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">((</span><span class="s2">&quot;Hello world! I&#39;m a view which &quot;</span>
5060
- <a id="__codelineno-44-9" name="__codelineno-44-9" href="#__codelineno-44-9"></a> <span class="s2">&quot;overrides the device object detail view.&quot;</span><span class="p">))</span>
5061
- <a id="__codelineno-44-10" name="__codelineno-44-10" href="#__codelineno-44-10"></a>
5062
- <a id="__codelineno-44-11" name="__codelineno-44-11" href="#__codelineno-44-11"></a>
5063
- <a id="__codelineno-44-12" name="__codelineno-44-12" href="#__codelineno-44-12"></a><span class="n">override_views</span> <span class="o">=</span> <span class="p">{</span>
5064
- <a id="__codelineno-44-13" name="__codelineno-44-13" href="#__codelineno-44-13"></a> <span class="s2">&quot;dcim:device&quot;</span><span class="p">:</span> <span class="n">DeviceViewOverride</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
5065
- <a id="__codelineno-44-14" name="__codelineno-44-14" href="#__codelineno-44-14"></a><span class="p">}</span>
6349
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-48-1" name="__codelineno-48-1" href="#__codelineno-48-1"></a><span class="c1"># views.py</span>
6350
+ <a id="__codelineno-48-2" name="__codelineno-48-2" href="#__codelineno-48-2"></a><span class="kn">from</span> <span class="nn">django.shortcuts</span> <span class="kn">import</span> <span class="n">HttpResponse</span>
6351
+ <a id="__codelineno-48-3" name="__codelineno-48-3" href="#__codelineno-48-3"></a><span class="kn">from</span> <span class="nn">django.views</span> <span class="kn">import</span> <span class="n">generic</span>
6352
+ <a id="__codelineno-48-4" name="__codelineno-48-4" href="#__codelineno-48-4"></a>
6353
+ <a id="__codelineno-48-5" name="__codelineno-48-5" href="#__codelineno-48-5"></a>
6354
+ <a id="__codelineno-48-6" name="__codelineno-48-6" href="#__codelineno-48-6"></a><span class="k">class</span> <span class="nc">DeviceViewOverride</span><span class="p">(</span><span class="n">generic</span><span class="o">.</span><span class="n">View</span><span class="p">):</span>
6355
+ <a id="__codelineno-48-7" name="__codelineno-48-7" href="#__codelineno-48-7"></a> <span class="k">def</span> <span class="nf">get</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">request</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
6356
+ <a id="__codelineno-48-8" name="__codelineno-48-8" href="#__codelineno-48-8"></a> <span class="k">return</span> <span class="n">HttpResponse</span><span class="p">((</span><span class="s2">&quot;Hello world! I&#39;m a view which &quot;</span>
6357
+ <a id="__codelineno-48-9" name="__codelineno-48-9" href="#__codelineno-48-9"></a> <span class="s2">&quot;overrides the device object detail view.&quot;</span><span class="p">))</span>
6358
+ <a id="__codelineno-48-10" name="__codelineno-48-10" href="#__codelineno-48-10"></a>
6359
+ <a id="__codelineno-48-11" name="__codelineno-48-11" href="#__codelineno-48-11"></a>
6360
+ <a id="__codelineno-48-12" name="__codelineno-48-12" href="#__codelineno-48-12"></a><span class="n">override_views</span> <span class="o">=</span> <span class="p">{</span>
6361
+ <a id="__codelineno-48-13" name="__codelineno-48-13" href="#__codelineno-48-13"></a> <span class="s2">&quot;dcim:device&quot;</span><span class="p">:</span> <span class="n">DeviceViewOverride</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
6362
+ <a id="__codelineno-48-14" name="__codelineno-48-14" href="#__codelineno-48-14"></a><span class="p">}</span>
5066
6363
  </code></pre></div>
5067
6364
  <h2 id="note-url-endpoint">Note URL Endpoint<a class="headerlink" href="#note-url-endpoint" title="Permanent link">&para;</a></h2>
5068
6365
  <div class="admonition version-added">
5069
6366
  <p class="admonition-title">Added in version 1.4.0</p>
5070
6367
  </div>
5071
6368
  <p>Models that inherit from <code>PrimaryModel</code> and <code>OrganizationalModel</code> can have notes associated. In order to utilize this new feature you will need to add the endpoint to <code>urls.py</code>. Here is an option to be able to support both 1.4+ and older versions of Nautobot:</p>
5072
- <div class="highlight"><pre><span></span><code><a id="__codelineno-45-1" name="__codelineno-45-1" href="#__codelineno-45-1"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
5073
- <a id="__codelineno-45-2" name="__codelineno-45-2" href="#__codelineno-45-2"></a> <span class="n">path</span><span class="p">(</span><span class="s1">&#39;random/&#39;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">RandomAnimalView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;random_animal&#39;</span><span class="p">),</span>
5074
- <a id="__codelineno-45-3" name="__codelineno-45-3" href="#__codelineno-45-3"></a><span class="p">]</span>
5075
- <a id="__codelineno-45-4" name="__codelineno-45-4" href="#__codelineno-45-4"></a>
5076
- <a id="__codelineno-45-5" name="__codelineno-45-5" href="#__codelineno-45-5"></a><span class="k">try</span><span class="p">:</span>
5077
- <a id="__codelineno-45-6" name="__codelineno-45-6" href="#__codelineno-45-6"></a> <span class="kn">from</span> <span class="nn">nautobot.extras.views</span> <span class="kn">import</span> <span class="n">ObjectNotesView</span>
5078
- <a id="__codelineno-45-7" name="__codelineno-45-7" href="#__codelineno-45-7"></a> <span class="n">urlpatterns</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
5079
- <a id="__codelineno-45-8" name="__codelineno-45-8" href="#__codelineno-45-8"></a> <span class="n">path</span><span class="p">(</span>
5080
- <a id="__codelineno-45-9" name="__codelineno-45-9" href="#__codelineno-45-9"></a> <span class="s1">&#39;random/&lt;slug:slug&gt;/notes/),</span>
5081
- <a id="__codelineno-45-10" name="__codelineno-45-10" href="#__codelineno-45-10"></a> <span class="n">ObjectNotesView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
5082
- <a id="__codelineno-45-11" name="__codelineno-45-11" href="#__codelineno-45-11"></a> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;random_notes&quot;</span><span class="p">,</span>
5083
- <a id="__codelineno-45-12" name="__codelineno-45-12" href="#__codelineno-45-12"></a> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="n">Random</span><span class="p">},</span>
5084
- <a id="__codelineno-45-13" name="__codelineno-45-13" href="#__codelineno-45-13"></a> <span class="p">)</span>
5085
- <a id="__codelineno-45-14" name="__codelineno-45-14" href="#__codelineno-45-14"></a> <span class="p">)</span>
5086
- <a id="__codelineno-45-15" name="__codelineno-45-15" href="#__codelineno-45-15"></a><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
5087
- <a id="__codelineno-45-16" name="__codelineno-45-16" href="#__codelineno-45-16"></a> <span class="k">pass</span>
6369
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-49-1" name="__codelineno-49-1" href="#__codelineno-49-1"></a><span class="n">urlpatterns</span> <span class="o">=</span> <span class="p">[</span>
6370
+ <a id="__codelineno-49-2" name="__codelineno-49-2" href="#__codelineno-49-2"></a> <span class="n">path</span><span class="p">(</span><span class="s1">&#39;random/&#39;</span><span class="p">,</span> <span class="n">views</span><span class="o">.</span><span class="n">RandomAnimalView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span> <span class="n">name</span><span class="o">=</span><span class="s1">&#39;random_animal&#39;</span><span class="p">),</span>
6371
+ <a id="__codelineno-49-3" name="__codelineno-49-3" href="#__codelineno-49-3"></a><span class="p">]</span>
6372
+ <a id="__codelineno-49-4" name="__codelineno-49-4" href="#__codelineno-49-4"></a>
6373
+ <a id="__codelineno-49-5" name="__codelineno-49-5" href="#__codelineno-49-5"></a><span class="k">try</span><span class="p">:</span>
6374
+ <a id="__codelineno-49-6" name="__codelineno-49-6" href="#__codelineno-49-6"></a> <span class="kn">from</span> <span class="nn">nautobot.extras.views</span> <span class="kn">import</span> <span class="n">ObjectNotesView</span>
6375
+ <a id="__codelineno-49-7" name="__codelineno-49-7" href="#__codelineno-49-7"></a> <span class="n">urlpatterns</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
6376
+ <a id="__codelineno-49-8" name="__codelineno-49-8" href="#__codelineno-49-8"></a> <span class="n">path</span><span class="p">(</span>
6377
+ <a id="__codelineno-49-9" name="__codelineno-49-9" href="#__codelineno-49-9"></a> <span class="s1">&#39;random/&lt;uuid:pk&gt;/notes/),</span>
6378
+ <a id="__codelineno-49-10" name="__codelineno-49-10" href="#__codelineno-49-10"></a> <span class="n">ObjectNotesView</span><span class="o">.</span><span class="n">as_view</span><span class="p">(),</span>
6379
+ <a id="__codelineno-49-11" name="__codelineno-49-11" href="#__codelineno-49-11"></a> <span class="n">name</span><span class="o">=</span><span class="s2">&quot;random_notes&quot;</span><span class="p">,</span>
6380
+ <a id="__codelineno-49-12" name="__codelineno-49-12" href="#__codelineno-49-12"></a> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;model&quot;</span><span class="p">:</span> <span class="n">Random</span><span class="p">},</span>
6381
+ <a id="__codelineno-49-13" name="__codelineno-49-13" href="#__codelineno-49-13"></a> <span class="p">)</span>
6382
+ <a id="__codelineno-49-14" name="__codelineno-49-14" href="#__codelineno-49-14"></a> <span class="p">)</span>
6383
+ <a id="__codelineno-49-15" name="__codelineno-49-15" href="#__codelineno-49-15"></a><span class="k">except</span> <span class="ne">ImportError</span><span class="p">:</span>
6384
+ <a id="__codelineno-49-16" name="__codelineno-49-16" href="#__codelineno-49-16"></a> <span class="k">pass</span>
5088
6385
  </code></pre></div>
5089
6386
  <h2 id="prometheus-metrics">Prometheus Metrics<a class="headerlink" href="#prometheus-metrics" title="Permanent link">&para;</a></h2>
5090
6387
  <div class="admonition version-added">
@@ -5095,20 +6392,20 @@ namedtuple to assist in the configurations.</p>
5095
6392
  <li>Use the <code>prometheus_client</code> library directly in your app code. Depending on whether that code runs in the web server or the worker context, the metric will show up in the respective <code>/metrics</code> endpoint(s) (i.e. metrics generated in the worker context show up in the worker's endpoint and those generated in the web application's context show up in the web application's endpoint).</li>
5096
6393
  <li>If the metric cannot be generated alongside existing code, apps can implement individual metric generator functions and register them into a list called <code>metrics</code> in a file named <code>metrics.py</code> at the root of the app. Nautobot will automatically read these and expose them via its <code>/metrics</code> endpoint. The following code snippet shows an example metric defined this way:</li>
5097
6394
  </ol>
5098
- <div class="highlight"><pre><span></span><code><a id="__codelineno-46-1" name="__codelineno-46-1" href="#__codelineno-46-1"></a><span class="c1"># metrics.py</span>
5099
- <a id="__codelineno-46-2" name="__codelineno-46-2" href="#__codelineno-46-2"></a><span class="kn">from</span> <span class="nn">prometheus_client.metrics_core</span> <span class="kn">import</span> <span class="n">GaugeMetricFamily</span>
5100
- <a id="__codelineno-46-3" name="__codelineno-46-3" href="#__codelineno-46-3"></a>
5101
- <a id="__codelineno-46-4" name="__codelineno-46-4" href="#__codelineno-46-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
5102
- <a id="__codelineno-46-5" name="__codelineno-46-5" href="#__codelineno-46-5"></a>
5103
- <a id="__codelineno-46-6" name="__codelineno-46-6" href="#__codelineno-46-6"></a>
5104
- <a id="__codelineno-46-7" name="__codelineno-46-7" href="#__codelineno-46-7"></a><span class="k">def</span> <span class="nf">metric_animals</span><span class="p">():</span>
5105
- <a id="__codelineno-46-8" name="__codelineno-46-8" href="#__codelineno-46-8"></a> <span class="n">gauges</span> <span class="o">=</span> <span class="n">GaugeMetricFamily</span><span class="p">(</span><span class="s2">&quot;nautobot_noisy_animals_count&quot;</span><span class="p">,</span> <span class="s2">&quot;Nautobot Noisy Animals Count&quot;</span><span class="p">,</span> <span class="n">labels</span><span class="o">=</span><span class="p">[])</span>
5106
- <a id="__codelineno-46-9" name="__codelineno-46-9" href="#__codelineno-46-9"></a> <span class="n">screaming_animal_count</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">loudness</span><span class="o">=</span><span class="s2">&quot;noisy&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
5107
- <a id="__codelineno-46-10" name="__codelineno-46-10" href="#__codelineno-46-10"></a> <span class="n">gauges</span><span class="o">.</span><span class="n">add_metric</span><span class="p">(</span><span class="n">labels</span><span class="o">=</span><span class="p">[],</span> <span class="n">value</span><span class="o">=</span><span class="n">screaming_animal_count</span><span class="p">)</span>
5108
- <a id="__codelineno-46-11" name="__codelineno-46-11" href="#__codelineno-46-11"></a> <span class="k">yield</span> <span class="n">gauges</span>
5109
- <a id="__codelineno-46-12" name="__codelineno-46-12" href="#__codelineno-46-12"></a>
5110
- <a id="__codelineno-46-13" name="__codelineno-46-13" href="#__codelineno-46-13"></a>
5111
- <a id="__codelineno-46-14" name="__codelineno-46-14" href="#__codelineno-46-14"></a><span class="n">metrics</span> <span class="o">=</span> <span class="p">[</span><span class="n">metric_example</span><span class="p">]</span>
6395
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-50-1" name="__codelineno-50-1" href="#__codelineno-50-1"></a><span class="c1"># metrics.py</span>
6396
+ <a id="__codelineno-50-2" name="__codelineno-50-2" href="#__codelineno-50-2"></a><span class="kn">from</span> <span class="nn">prometheus_client.metrics_core</span> <span class="kn">import</span> <span class="n">GaugeMetricFamily</span>
6397
+ <a id="__codelineno-50-3" name="__codelineno-50-3" href="#__codelineno-50-3"></a>
6398
+ <a id="__codelineno-50-4" name="__codelineno-50-4" href="#__codelineno-50-4"></a><span class="kn">from</span> <span class="nn">nautobot_animal_sounds.models</span> <span class="kn">import</span> <span class="n">Animal</span>
6399
+ <a id="__codelineno-50-5" name="__codelineno-50-5" href="#__codelineno-50-5"></a>
6400
+ <a id="__codelineno-50-6" name="__codelineno-50-6" href="#__codelineno-50-6"></a>
6401
+ <a id="__codelineno-50-7" name="__codelineno-50-7" href="#__codelineno-50-7"></a><span class="k">def</span> <span class="nf">metric_animals</span><span class="p">():</span>
6402
+ <a id="__codelineno-50-8" name="__codelineno-50-8" href="#__codelineno-50-8"></a> <span class="n">gauges</span> <span class="o">=</span> <span class="n">GaugeMetricFamily</span><span class="p">(</span><span class="s2">&quot;nautobot_noisy_animals_count&quot;</span><span class="p">,</span> <span class="s2">&quot;Nautobot Noisy Animals Count&quot;</span><span class="p">,</span> <span class="n">labels</span><span class="o">=</span><span class="p">[])</span>
6403
+ <a id="__codelineno-50-9" name="__codelineno-50-9" href="#__codelineno-50-9"></a> <span class="n">screaming_animal_count</span> <span class="o">=</span> <span class="n">Animal</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">loudness</span><span class="o">=</span><span class="s2">&quot;noisy&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">count</span><span class="p">()</span>
6404
+ <a id="__codelineno-50-10" name="__codelineno-50-10" href="#__codelineno-50-10"></a> <span class="n">gauges</span><span class="o">.</span><span class="n">add_metric</span><span class="p">(</span><span class="n">labels</span><span class="o">=</span><span class="p">[],</span> <span class="n">value</span><span class="o">=</span><span class="n">screaming_animal_count</span><span class="p">)</span>
6405
+ <a id="__codelineno-50-11" name="__codelineno-50-11" href="#__codelineno-50-11"></a> <span class="k">yield</span> <span class="n">gauges</span>
6406
+ <a id="__codelineno-50-12" name="__codelineno-50-12" href="#__codelineno-50-12"></a>
6407
+ <a id="__codelineno-50-13" name="__codelineno-50-13" href="#__codelineno-50-13"></a>
6408
+ <a id="__codelineno-50-14" name="__codelineno-50-14" href="#__codelineno-50-14"></a><span class="n">metrics</span> <span class="o">=</span> <span class="p">[</span><span class="n">metric_example</span><span class="p">]</span>
5112
6409
  </code></pre></div>
5113
6410
  <h2 id="testing-apps">Testing Apps<a class="headerlink" href="#testing-apps" title="Permanent link">&para;</a></h2>
5114
6411
  <p>In general apps can be tested like other Django apps. In most cases you'll want to run your automated tests via the <code>nautobot-server test &lt;app_module&gt;</code> command or, if using the <code>coverage</code> Python library, <code>coverage run --module nautobot.core.cli test &lt;app_module&gt;</code>.</p>
@@ -5126,31 +6423,31 @@ namedtuple to assist in the configurations.</p>
5126
6423
  <p><code>NautobotPerformanceTestRunner</code> is used by adding the flag <code>--testrunner nautobot.core.tests.runner.NautobotPerformanceTestRunner</code> to the <code>coverage run</code> command used for unit tests. This flag will replace the default <code>NautobotTestRunner</code> while retaining all its functionalities with the addition of performance evaluation after test
5127
6424
  runs.
5128
6425
  Checkout <a href="../development/testing.html#performance-tests">Performance Tests</a> for more detail.</p>
5129
- <div class="highlight"><pre><span></span><code><a id="__codelineno-47-1" name="__codelineno-47-1" href="#__codelineno-47-1"></a><span class="nd">@tag</span><span class="p">(</span><span class="s2">&quot;performance&quot;</span><span class="p">)</span>
5130
- <a id="__codelineno-47-2" name="__codelineno-47-2" href="#__codelineno-47-2"></a><span class="k">def</span> <span class="nf">test_your_app</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
5131
- <a id="__codelineno-47-3" name="__codelineno-47-3" href="#__codelineno-47-3"></a> <span class="k">pass</span>
5132
- <a id="__codelineno-47-4" name="__codelineno-47-4" href="#__codelineno-47-4"></a><span class="o">...</span>
6426
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-51-1" name="__codelineno-51-1" href="#__codelineno-51-1"></a><span class="nd">@tag</span><span class="p">(</span><span class="s2">&quot;performance&quot;</span><span class="p">)</span>
6427
+ <a id="__codelineno-51-2" name="__codelineno-51-2" href="#__codelineno-51-2"></a><span class="k">def</span> <span class="nf">test_your_app</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span>
6428
+ <a id="__codelineno-51-3" name="__codelineno-51-3" href="#__codelineno-51-3"></a> <span class="k">pass</span>
6429
+ <a id="__codelineno-51-4" name="__codelineno-51-4" href="#__codelineno-51-4"></a><span class="o">...</span>
5133
6430
  </code></pre></div>
5134
6431
  <h3 id="gathering-performance-test-baseline-data">Gathering Performance Test Baseline Data<a class="headerlink" href="#gathering-performance-test-baseline-data" title="Permanent link">&para;</a></h3>
5135
6432
  <p>If you want to add baselines for your own test to <code>nautobot/core/tests/performance_baselines.yml</code> or have your own baseline yaml file for performance testing, specify a different file path for <code>TEST_PERFORMANCE_BASELINE_FILE</code> in app's development/test <code>nautobot_config.py</code>, and store the output of <code>invoke performance-test --performance-snapshot</code> command in that file. <code>--performance-snapshot</code> flag will store the results of your performance test to <code>report.yml</code> and all you need to do is copy/paste the result to the file set by <code>TEST_PERFORMANCE_BASELINE_FILE</code>. Now you have baselines for your own tests!
5136
6433
  Example output of <code>invoke performance-test --performance-snapshot</code>:</p>
5137
- <div class="highlight"><pre><span></span><code><a id="__codelineno-48-1" name="__codelineno-48-1" href="#__codelineno-48-1"></a><span class="nt">tests</span><span class="p">:</span>
5138
- <a id="__codelineno-48-2" name="__codelineno-48-2" href="#__codelineno-48-2"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
5139
- <a id="__codelineno-48-3" name="__codelineno-48-3" href="#__codelineno-48-3"></a><span class="w"> </span><span class="no">test_run_job_with_sensitive_variables_and_requires_approval</span>
5140
- <a id="__codelineno-48-4" name="__codelineno-48-4" href="#__codelineno-48-4"></a><span class="w"> </span><span class="no">(nautobot.extras.tests.test_views.JobTestCase)</span>
5141
- <a id="__codelineno-48-5" name="__codelineno-48-5" href="#__codelineno-48-5"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4.799533</span>
5142
- <a id="__codelineno-48-6" name="__codelineno-48-6" href="#__codelineno-48-6"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">test_run_missing_schedule (nautobot.extras.tests.test_views.JobTestCase)</span>
5143
- <a id="__codelineno-48-7" name="__codelineno-48-7" href="#__codelineno-48-7"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4.367563</span>
5144
- <a id="__codelineno-48-8" name="__codelineno-48-8" href="#__codelineno-48-8"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">test_run_now_missing_args (nautobot.extras.tests.test_views.JobTestCase)</span>
5145
- <a id="__codelineno-48-9" name="__codelineno-48-9" href="#__codelineno-48-9"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4.363194</span>
5146
- <a id="__codelineno-48-10" name="__codelineno-48-10" href="#__codelineno-48-10"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
5147
- <a id="__codelineno-48-11" name="__codelineno-48-11" href="#__codelineno-48-11"></a><span class="w"> </span><span class="no">test_create_object_with_constrained_permission</span>
5148
- <a id="__codelineno-48-12" name="__codelineno-48-12" href="#__codelineno-48-12"></a><span class="w"> </span><span class="no">(nautobot.extras.tests.test_views.GraphQLQueriesTestCase)</span>
5149
- <a id="__codelineno-48-13" name="__codelineno-48-13" href="#__codelineno-48-13"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">3.474244</span>
5150
- <a id="__codelineno-48-14" name="__codelineno-48-14" href="#__codelineno-48-14"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
5151
- <a id="__codelineno-48-15" name="__codelineno-48-15" href="#__codelineno-48-15"></a><span class="w"> </span><span class="no">test_run_now_constrained_permissions</span>
5152
- <a id="__codelineno-48-16" name="__codelineno-48-16" href="#__codelineno-48-16"></a><span class="w"> </span><span class="no">(nautobot.extras.tests.test_views.JobTestCase)</span>
5153
- <a id="__codelineno-48-17" name="__codelineno-48-17" href="#__codelineno-48-17"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2.727531</span>
6434
+ <div class="highlight"><pre><span></span><code><a id="__codelineno-52-1" name="__codelineno-52-1" href="#__codelineno-52-1"></a><span class="nt">tests</span><span class="p">:</span>
6435
+ <a id="__codelineno-52-2" name="__codelineno-52-2" href="#__codelineno-52-2"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
6436
+ <a id="__codelineno-52-3" name="__codelineno-52-3" href="#__codelineno-52-3"></a><span class="w"> </span><span class="no">test_run_job_with_sensitive_variables_and_requires_approval</span>
6437
+ <a id="__codelineno-52-4" name="__codelineno-52-4" href="#__codelineno-52-4"></a><span class="w"> </span><span class="no">(nautobot.extras.tests.test_views.JobTestCase)</span>
6438
+ <a id="__codelineno-52-5" name="__codelineno-52-5" href="#__codelineno-52-5"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4.799533</span>
6439
+ <a id="__codelineno-52-6" name="__codelineno-52-6" href="#__codelineno-52-6"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">test_run_missing_schedule (nautobot.extras.tests.test_views.JobTestCase)</span>
6440
+ <a id="__codelineno-52-7" name="__codelineno-52-7" href="#__codelineno-52-7"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4.367563</span>
6441
+ <a id="__codelineno-52-8" name="__codelineno-52-8" href="#__codelineno-52-8"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">test_run_now_missing_args (nautobot.extras.tests.test_views.JobTestCase)</span>
6442
+ <a id="__codelineno-52-9" name="__codelineno-52-9" href="#__codelineno-52-9"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">4.363194</span>
6443
+ <a id="__codelineno-52-10" name="__codelineno-52-10" href="#__codelineno-52-10"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
6444
+ <a id="__codelineno-52-11" name="__codelineno-52-11" href="#__codelineno-52-11"></a><span class="w"> </span><span class="no">test_create_object_with_constrained_permission</span>
6445
+ <a id="__codelineno-52-12" name="__codelineno-52-12" href="#__codelineno-52-12"></a><span class="w"> </span><span class="no">(nautobot.extras.tests.test_views.GraphQLQueriesTestCase)</span>
6446
+ <a id="__codelineno-52-13" name="__codelineno-52-13" href="#__codelineno-52-13"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">3.474244</span>
6447
+ <a id="__codelineno-52-14" name="__codelineno-52-14" href="#__codelineno-52-14"></a><span class="w"> </span><span class="p p-Indicator">-</span><span class="w"> </span><span class="nt">name</span><span class="p">:</span><span class="w"> </span><span class="p p-Indicator">&gt;-</span>
6448
+ <a id="__codelineno-52-15" name="__codelineno-52-15" href="#__codelineno-52-15"></a><span class="w"> </span><span class="no">test_run_now_constrained_permissions</span>
6449
+ <a id="__codelineno-52-16" name="__codelineno-52-16" href="#__codelineno-52-16"></a><span class="w"> </span><span class="no">(nautobot.extras.tests.test_views.JobTestCase)</span>
6450
+ <a id="__codelineno-52-17" name="__codelineno-52-17" href="#__codelineno-52-17"></a><span class="w"> </span><span class="nt">execution_time</span><span class="p">:</span><span class="w"> </span><span class="l l-Scalar l-Scalar-Plain">2.727531</span>
5154
6451
  </code></pre></div>
5155
6452
  <p>We recommend adding <a href="https://pypi.org/project/django-slowtests/"><code>django-slowtests</code></a> to your app's development dependencies to leverage this functionality to build better performing apps.</p>
5156
6453
 
@@ -5169,42 +6466,6 @@ Example output of <code>invoke performance-test --performance-snapshot</code>:</
5169
6466
 
5170
6467
  <footer class="md-footer">
5171
6468
 
5172
-
5173
- <nav class="md-footer__inner md-grid" aria-label="Footer" >
5174
-
5175
-
5176
- <a href="index.html" class="md-footer__link md-footer__link--prev" aria-label="Previous: Installing and Using Plugins" rel="prev">
5177
- <div class="md-footer__button md-icon">
5178
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
5179
- </div>
5180
- <div class="md-footer__title">
5181
- <div class="md-ellipsis">
5182
- <span class="md-footer__direction">
5183
- Previous
5184
- </span>
5185
- Installing and Using Plugins
5186
- </div>
5187
- </div>
5188
- </a>
5189
-
5190
-
5191
-
5192
- <a href="porting-from-netbox.html" class="md-footer__link md-footer__link--next" aria-label="Next: Porting NetBox Plugins to Nautobot" rel="next">
5193
- <div class="md-footer__title">
5194
- <div class="md-ellipsis">
5195
- <span class="md-footer__direction">
5196
- Next
5197
- </span>
5198
- Porting NetBox Plugins to Nautobot
5199
- </div>
5200
- </div>
5201
- <div class="md-footer__button md-icon">
5202
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4Z"/></svg>
5203
- </div>
5204
- </a>
5205
-
5206
- </nav>
5207
-
5208
6469
  <div class="md-footer-meta md-typeset">
5209
6470
  <div class="md-footer-meta__inner md-grid">
5210
6471
  <div class="md-copyright">
@@ -5232,32 +6493,42 @@ Example output of <code>invoke performance-test --performance-snapshot</code>:</
5232
6493
 
5233
6494
 
5234
6495
 
6496
+
6497
+
5235
6498
  <a href="https://blog.networktocode.com/blog/tags/nautobot" target="_blank" rel="noopener" title="Network to Code Blog" class="md-social__link">
5236
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M0 64c0-17.7 14.3-32 32-32 229.8 0 416 186.2 416 416 0 17.7-14.3 32-32 32s-32-14.3-32-32C384 253.6 226.4 96 32 96 14.3 96 0 81.7 0 64zm128 352c0 35.3-28.7 64-64 64S0 451.3 0 416s28.7-64 64-64 64 28.7 64 64zM32 160c159.1 0 288 128.9 288 288 0 17.7-14.3 32-32 32s-32-14.3-32-32c0-123.7-100.3-224-224-224-17.7 0-32-14.3-32-32s14.3-32 32-32z"/></svg>
6499
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M0 64c0-17.7 14.3-32 32-32 229.8 0 416 186.2 416 416 0 17.7-14.3 32-32 32s-32-14.3-32-32C384 253.6 226.4 96 32 96 14.3 96 0 81.7 0 64zm0 352a64 64 0 1 1 128 0 64 64 0 1 1-128 0zm32-256c159.1 0 288 128.9 288 288 0 17.7-14.3 32-32 32s-32-14.3-32-32c0-123.7-100.3-224-224-224-17.7 0-32-14.3-32-32s14.3-32 32-32z"/></svg>
5237
6500
  </a>
5238
6501
 
5239
6502
 
5240
6503
 
6504
+
6505
+
5241
6506
  <a href="https://www.youtube.com/playlist?list=PLjA0bhxgryJ2Ts4GJMDA-tPzVWEncv4pb" target="_blank" rel="noopener" title="Nautobot Videos" class="md-social__link">
5242
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"/></svg>
6507
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"/></svg>
5243
6508
  </a>
5244
6509
 
5245
6510
 
5246
6511
 
6512
+
6513
+
5247
6514
  <a href="https://www.networktocode.com/community/" target="_blank" rel="noopener" title="Network to Code Community" class="md-social__link">
5248
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M94.12 315.1c0 25.9-21.16 47.06-47.06 47.06S0 341 0 315.1c0-25.9 21.16-47.06 47.06-47.06h47.06v47.06zm23.72 0c0-25.9 21.16-47.06 47.06-47.06s47.06 21.16 47.06 47.06v117.84c0 25.9-21.16 47.06-47.06 47.06s-47.06-21.16-47.06-47.06V315.1zm47.06-188.98c-25.9 0-47.06-21.16-47.06-47.06S139 32 164.9 32s47.06 21.16 47.06 47.06v47.06H164.9zm0 23.72c25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06H47.06C21.16 243.96 0 222.8 0 196.9s21.16-47.06 47.06-47.06H164.9zm188.98 47.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06h-47.06V196.9zm-23.72 0c0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06V79.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06V196.9zM283.1 385.88c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06v-47.06h47.06zm0-23.72c-25.9 0-47.06-21.16-47.06-47.06 0-25.9 21.16-47.06 47.06-47.06h117.84c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06H283.1z"/></svg>
6515
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M94.12 315.1c0 25.9-21.16 47.06-47.06 47.06S0 341 0 315.1c0-25.9 21.16-47.06 47.06-47.06h47.06v47.06zm23.72 0c0-25.9 21.16-47.06 47.06-47.06s47.06 21.16 47.06 47.06v117.84c0 25.9-21.16 47.06-47.06 47.06s-47.06-21.16-47.06-47.06V315.1zm47.06-188.98c-25.9 0-47.06-21.16-47.06-47.06S139 32 164.9 32s47.06 21.16 47.06 47.06v47.06H164.9zm0 23.72c25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06H47.06C21.16 243.96 0 222.8 0 196.9s21.16-47.06 47.06-47.06H164.9zm188.98 47.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06h-47.06V196.9zm-23.72 0c0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06V79.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06V196.9zM283.1 385.88c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06v-47.06h47.06zm0-23.72c-25.9 0-47.06-21.16-47.06-47.06 0-25.9 21.16-47.06 47.06-47.06h117.84c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06H283.1z"/></svg>
5249
6516
  </a>
5250
6517
 
5251
6518
 
5252
6519
 
6520
+
6521
+
5253
6522
  <a href="https://github.com/nautobot/nautobot" target="_blank" rel="noopener" title="GitHub Repo" class="md-social__link">
5254
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
6523
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
5255
6524
  </a>
5256
6525
 
5257
6526
 
5258
6527
 
6528
+
6529
+
5259
6530
  <a href="https://twitter.com/networktocode" target="_blank" rel="noopener" title="Network to Code Twitter" class="md-social__link">
5260
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
6531
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
5261
6532
  </a>
5262
6533
 
5263
6534
  </div>
@@ -5271,14 +6542,13 @@ Example output of <code>invoke performance-test --performance-snapshot</code>:</
5271
6542
  <div class="md-dialog__inner md-typeset"></div>
5272
6543
  </div>
5273
6544
 
5274
- <script id="__config" type="application/json">{"base": "..", "features": ["navigation.tracking", "navigation.tabs", "navigation.tabs.sticky", "search.suggest", "search.highlight", "search.share"], "search": "../assets/javascripts/workers/search.16e2a7d4.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.placeholder": "Search", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version.title": "Select version"}}</script>
6545
+ <script id="__config" type="application/json">{"base": "..", "features": ["navigation.tracking", "navigation.tabs", "navigation.tabs.sticky", "search.suggest", "search.highlight", "search.share"], "search": "../assets/javascripts/workers/search.208ed371.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
5275
6546
 
5276
6547
 
5277
- <script src="../assets/javascripts/bundle.5a2dcb6a.min.js"></script>
6548
+ <script src="../assets/javascripts/bundle.51198bba.min.js"></script>
5278
6549
 
5279
6550
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
5280
6551
 
5281
6552
 
5282
-
5283
6553
  </body>
5284
6554
  </html>