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/code-reference/nautobot/apps/models.html">
12
12
 
13
+
14
+ <link rel="prev" href="forms.html">
15
+
16
+
17
+ <link rel="next" href="secrets.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,17 +1151,18 @@
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" >
1149
1157
 
1150
1158
 
1151
- <label class="md-nav__link" for="__nav_2_7">
1159
+
1160
+ <label class="md-nav__link" for="__nav_2_7" id="__nav_2_7_label" tabindex="0">
1152
1161
  Core Functionality
1153
1162
  <span class="md-nav__icon md-icon"></span>
1154
1163
  </label>
1155
1164
 
1156
- <nav class="md-nav" aria-label="Core Functionality" data-md-level="2">
1165
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_7_label" aria-expanded="false">
1157
1166
  <label class="md-nav__title" for="__nav_2_7">
1158
1167
  <span class="md-nav__icon md-icon"></span>
1159
1168
  Core Functionality
@@ -1330,20 +1339,48 @@
1330
1339
  <li class="md-nav__item md-nav__item--nested">
1331
1340
 
1332
1341
 
1333
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_8" type="checkbox" id="__nav_2_8" >
1334
1342
 
1335
1343
 
1344
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8" >
1336
1345
 
1337
1346
 
1338
- <label class="md-nav__link" for="__nav_2_8">
1339
- Additional Features
1347
+
1348
+ <label class="md-nav__link" for="__nav_2_8" id="__nav_2_8_label" tabindex="0">
1349
+ Model Details
1340
1350
  <span class="md-nav__icon md-icon"></span>
1341
1351
  </label>
1342
1352
 
1343
- <nav class="md-nav" aria-label="Additional Features" data-md-level="2">
1353
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
1344
1354
  <label class="md-nav__title" for="__nav_2_8">
1345
1355
  <span class="md-nav__icon md-icon"></span>
1346
- Additional Features
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
1347
1384
  </label>
1348
1385
  <ul class="md-nav__list" data-md-scrollfix>
1349
1386
 
@@ -1353,8 +1390,8 @@
1353
1390
 
1354
1391
 
1355
1392
  <li class="md-nav__item">
1356
- <a href="../../../additional-features/caching.html" class="md-nav__link">
1357
- Caching
1393
+ <a href="../../../models/circuits/circuit.html" class="md-nav__link">
1394
+ Circuit
1358
1395
  </a>
1359
1396
  </li>
1360
1397
 
@@ -1367,8 +1404,8 @@
1367
1404
 
1368
1405
 
1369
1406
  <li class="md-nav__item">
1370
- <a href="../../../additional-features/change-logging.html" class="md-nav__link">
1371
- Change Logging
1407
+ <a href="../../../models/circuits/circuittermination.html" class="md-nav__link">
1408
+ Circuit Termination
1372
1409
  </a>
1373
1410
  </li>
1374
1411
 
@@ -1381,8 +1418,8 @@
1381
1418
 
1382
1419
 
1383
1420
  <li class="md-nav__item">
1384
- <a href="../../../models/extras/computedfield.html" class="md-nav__link">
1385
- Computed Fields
1421
+ <a href="../../../models/circuits/circuittype.html" class="md-nav__link">
1422
+ Circuit Type
1386
1423
  </a>
1387
1424
  </li>
1388
1425
 
@@ -1395,8 +1432,8 @@
1395
1432
 
1396
1433
 
1397
1434
  <li class="md-nav__item">
1398
- <a href="../../../additional-features/config-contexts.html" class="md-nav__link">
1399
- Context Data
1435
+ <a href="../../../models/circuits/provider.html" class="md-nav__link">
1436
+ Circuit Provider
1400
1437
  </a>
1401
1438
  </li>
1402
1439
 
@@ -1409,22 +1446,56 @@
1409
1446
 
1410
1447
 
1411
1448
  <li class="md-nav__item">
1412
- <a href="../../../models/extras/customfield.html" class="md-nav__link">
1413
- Custom Fields
1449
+ <a href="../../../models/circuits/providernetwork.html" class="md-nav__link">
1450
+ Circuit Provider Network
1414
1451
  </a>
1415
1452
  </li>
1416
1453
 
1417
1454
 
1418
1455
 
1419
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
+
1420
1491
 
1421
1492
 
1422
1493
 
1423
1494
 
1424
1495
 
1425
1496
  <li class="md-nav__item">
1426
- <a href="../../../models/extras/customlink.html" class="md-nav__link">
1427
- Custom Links
1497
+ <a href="../../../models/dcim/cable.html" class="md-nav__link">
1498
+ Cable
1428
1499
  </a>
1429
1500
  </li>
1430
1501
 
@@ -1437,8 +1508,8 @@
1437
1508
 
1438
1509
 
1439
1510
  <li class="md-nav__item">
1440
- <a href="../../../models/extras/dynamicgroup.html" class="md-nav__link">
1441
- Dynamic Groups
1511
+ <a href="../../../models/dcim/consoleport.html" class="md-nav__link">
1512
+ Console Port
1442
1513
  </a>
1443
1514
  </li>
1444
1515
 
@@ -1451,8 +1522,8 @@
1451
1522
 
1452
1523
 
1453
1524
  <li class="md-nav__item">
1454
- <a href="../../../models/extras/exporttemplate.html" class="md-nav__link">
1455
- Export Templates
1525
+ <a href="../../../models/dcim/consoleporttemplate.html" class="md-nav__link">
1526
+ Console Port Template
1456
1527
  </a>
1457
1528
  </li>
1458
1529
 
@@ -1465,8 +1536,8 @@
1465
1536
 
1466
1537
 
1467
1538
  <li class="md-nav__item">
1468
- <a href="../../../models/extras/gitrepository.html" class="md-nav__link">
1469
- Git Repositories
1539
+ <a href="../../../models/dcim/consoleserverport.html" class="md-nav__link">
1540
+ Console Server Port
1470
1541
  </a>
1471
1542
  </li>
1472
1543
 
@@ -1479,8 +1550,8 @@
1479
1550
 
1480
1551
 
1481
1552
  <li class="md-nav__item">
1482
- <a href="../../../additional-features/healthcheck.html" class="md-nav__link">
1483
- Health Check
1553
+ <a href="../../../models/dcim/consoleserverporttemplate.html" class="md-nav__link">
1554
+ Console Server Port Template
1484
1555
  </a>
1485
1556
  </li>
1486
1557
 
@@ -1493,8 +1564,8 @@
1493
1564
 
1494
1565
 
1495
1566
  <li class="md-nav__item">
1496
- <a href="../../../additional-features/jobs.html" class="md-nav__link">
1497
- Jobs
1567
+ <a href="../../../models/dcim/device.html" class="md-nav__link">
1568
+ Device
1498
1569
  </a>
1499
1570
  </li>
1500
1571
 
@@ -1507,8 +1578,8 @@
1507
1578
 
1508
1579
 
1509
1580
  <li class="md-nav__item">
1510
- <a href="../../../models/extras/jobbutton.html" class="md-nav__link">
1511
- Job Buttons
1581
+ <a href="../../../models/dcim/devicebay.html" class="md-nav__link">
1582
+ Device Bay
1512
1583
  </a>
1513
1584
  </li>
1514
1585
 
@@ -1521,8 +1592,8 @@
1521
1592
 
1522
1593
 
1523
1594
  <li class="md-nav__item">
1524
- <a href="../../../models/extras/jobhook.html" class="md-nav__link">
1525
- Job Hooks
1595
+ <a href="../../../models/dcim/devicebaytemplate.html" class="md-nav__link">
1596
+ Device Bay Template
1526
1597
  </a>
1527
1598
  </li>
1528
1599
 
@@ -1535,8 +1606,8 @@
1535
1606
 
1536
1607
 
1537
1608
  <li class="md-nav__item">
1538
- <a href="../../../additional-features/job-scheduling-and-approvals.html" class="md-nav__link">
1539
- Job Scheduling and Approvals
1609
+ <a href="../../../models/dcim/deviceredundancygroup.html" class="md-nav__link">
1610
+ Device Redundancy Group
1540
1611
  </a>
1541
1612
  </li>
1542
1613
 
@@ -1549,8 +1620,8 @@
1549
1620
 
1550
1621
 
1551
1622
  <li class="md-nav__item">
1552
- <a href="../../../additional-features/napalm.html" class="md-nav__link">
1553
- NAPALM
1623
+ <a href="../../../models/dcim/devicetype.html" class="md-nav__link">
1624
+ Device Type
1554
1625
  </a>
1555
1626
  </li>
1556
1627
 
@@ -1563,8 +1634,8 @@
1563
1634
 
1564
1635
 
1565
1636
  <li class="md-nav__item">
1566
- <a href="../../../models/extras/note.html" class="md-nav__link">
1567
- Notes
1637
+ <a href="../../../models/dcim/frontport.html" class="md-nav__link">
1638
+ Front Port
1568
1639
  </a>
1569
1640
  </li>
1570
1641
 
@@ -1577,8 +1648,8 @@
1577
1648
 
1578
1649
 
1579
1650
  <li class="md-nav__item">
1580
- <a href="../../../additional-features/prometheus-metrics.html" class="md-nav__link">
1581
- Prometheus Metrics
1651
+ <a href="../../../models/dcim/frontporttemplate.html" class="md-nav__link">
1652
+ Front Port Template
1582
1653
  </a>
1583
1654
  </li>
1584
1655
 
@@ -1591,8 +1662,8 @@
1591
1662
 
1592
1663
 
1593
1664
  <li class="md-nav__item">
1594
- <a href="../../../models/extras/relationship.html" class="md-nav__link">
1595
- Relationships
1665
+ <a href="../../../models/dcim/interface.html" class="md-nav__link">
1666
+ Interface
1596
1667
  </a>
1597
1668
  </li>
1598
1669
 
@@ -1605,8 +1676,8 @@
1605
1676
 
1606
1677
 
1607
1678
  <li class="md-nav__item">
1608
- <a href="../../../models/extras/status.html" class="md-nav__link">
1609
- Statuses
1679
+ <a href="../../../models/dcim/interfacetemplate.html" class="md-nav__link">
1680
+ Interface Template
1610
1681
  </a>
1611
1682
  </li>
1612
1683
 
@@ -1619,8 +1690,8 @@
1619
1690
 
1620
1691
 
1621
1692
  <li class="md-nav__item">
1622
- <a href="../../../models/extras/tag.html" class="md-nav__link">
1623
- Tags
1693
+ <a href="../../../models/dcim/inventoryitem.html" class="md-nav__link">
1694
+ Inventory Item
1624
1695
  </a>
1625
1696
  </li>
1626
1697
 
@@ -1633,8 +1704,8 @@
1633
1704
 
1634
1705
 
1635
1706
  <li class="md-nav__item">
1636
- <a href="../../../additional-features/template-filters.html" class="md-nav__link">
1637
- Template Filters
1707
+ <a href="../../../models/dcim/location.html" class="md-nav__link">
1708
+ Location
1638
1709
  </a>
1639
1710
  </li>
1640
1711
 
@@ -1647,46 +1718,27 @@
1647
1718
 
1648
1719
 
1649
1720
  <li class="md-nav__item">
1650
- <a href="../../../models/extras/webhook.html" class="md-nav__link">
1651
- Webhooks
1721
+ <a href="../../../models/dcim/locationtype.html" class="md-nav__link">
1722
+ Location Type
1652
1723
  </a>
1653
1724
  </li>
1654
1725
 
1655
1726
 
1656
1727
 
1657
1728
 
1658
- </ul>
1659
- </nav>
1660
- </li>
1661
-
1662
-
1663
-
1664
-
1665
1729
 
1666
1730
 
1667
1731
 
1668
1732
 
1669
1733
 
1670
-
1671
- <li class="md-nav__item md-nav__item--nested">
1672
-
1673
-
1674
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_9" type="checkbox" id="__nav_2_9" >
1675
-
1676
-
1677
-
1678
-
1679
- <label class="md-nav__link" for="__nav_2_9">
1680
- REST API
1681
- <span class="md-nav__icon md-icon"></span>
1682
- </label>
1683
-
1684
- <nav class="md-nav" aria-label="REST API" data-md-level="2">
1685
- <label class="md-nav__title" for="__nav_2_9">
1686
- <span class="md-nav__icon md-icon"></span>
1687
- REST API
1688
- </label>
1689
- <ul class="md-nav__list" data-md-scrollfix>
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
+
1690
1742
 
1691
1743
 
1692
1744
 
@@ -1694,8 +1746,8 @@
1694
1746
 
1695
1747
 
1696
1748
  <li class="md-nav__item">
1697
- <a href="../../../rest-api/overview.html" class="md-nav__link">
1698
- Overview
1749
+ <a href="../../../models/dcim/platform.html" class="md-nav__link">
1750
+ Platform
1699
1751
  </a>
1700
1752
  </li>
1701
1753
 
@@ -1708,8 +1760,8 @@
1708
1760
 
1709
1761
 
1710
1762
  <li class="md-nav__item">
1711
- <a href="../../../rest-api/filtering.html" class="md-nav__link">
1712
- Filtering
1763
+ <a href="../../../models/dcim/powerfeed.html" class="md-nav__link">
1764
+ Power Feed
1713
1765
  </a>
1714
1766
  </li>
1715
1767
 
@@ -1722,46 +1774,27 @@
1722
1774
 
1723
1775
 
1724
1776
  <li class="md-nav__item">
1725
- <a href="../../../rest-api/authentication.html" class="md-nav__link">
1726
- Authentication
1777
+ <a href="../../../models/dcim/poweroutlet.html" class="md-nav__link">
1778
+ Power Outlet
1727
1779
  </a>
1728
1780
  </li>
1729
1781
 
1730
1782
 
1731
1783
 
1732
1784
 
1733
- </ul>
1734
- </nav>
1735
- </li>
1736
-
1737
-
1738
-
1739
-
1740
1785
 
1741
1786
 
1742
1787
 
1743
1788
 
1744
1789
 
1745
-
1746
- <li class="md-nav__item md-nav__item--nested">
1747
-
1748
-
1749
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_10" type="checkbox" id="__nav_2_10" >
1750
-
1751
-
1752
-
1753
-
1754
- <label class="md-nav__link" for="__nav_2_10">
1755
- GraphQL API
1756
- <span class="md-nav__icon md-icon"></span>
1757
- </label>
1758
-
1759
- <nav class="md-nav" aria-label="GraphQL API" data-md-level="2">
1760
- <label class="md-nav__title" for="__nav_2_10">
1761
- <span class="md-nav__icon md-icon"></span>
1762
- GraphQL API
1763
- </label>
1764
- <ul class="md-nav__list" data-md-scrollfix>
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
+
1765
1798
 
1766
1799
 
1767
1800
 
@@ -1769,79 +1802,36 @@
1769
1802
 
1770
1803
 
1771
1804
  <li class="md-nav__item">
1772
- <a href="../../../additional-features/graphql.html" class="md-nav__link">
1773
- Overview
1805
+ <a href="../../../models/dcim/powerpanel.html" class="md-nav__link">
1806
+ Power Panel
1774
1807
  </a>
1775
1808
  </li>
1776
1809
 
1777
1810
 
1778
1811
 
1779
1812
 
1780
- </ul>
1781
- </nav>
1782
- </li>
1783
-
1784
-
1785
-
1786
-
1787
1813
 
1788
1814
 
1789
1815
 
1790
1816
 
1791
1817
 
1792
1818
  <li class="md-nav__item">
1793
- <a href="../../../plugins/index.html" class="md-nav__link">
1794
- Installing and Using Plugins
1819
+ <a href="../../../models/dcim/powerport.html" class="md-nav__link">
1820
+ Power Port
1795
1821
  </a>
1796
1822
  </li>
1797
1823
 
1798
1824
 
1799
1825
 
1800
1826
 
1801
- </ul>
1802
- </nav>
1803
- </li>
1804
-
1805
-
1806
-
1807
-
1808
-
1809
-
1810
-
1811
-
1812
-
1813
-
1814
-
1815
-
1816
-
1817
- <li class="md-nav__item md-nav__item--active md-nav__item--nested">
1818
-
1819
-
1820
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3" type="checkbox" id="__nav_3" checked>
1821
-
1822
-
1823
-
1824
-
1825
- <label class="md-nav__link" for="__nav_3">
1826
- App Developer Guide
1827
- <span class="md-nav__icon md-icon"></span>
1828
- </label>
1829
-
1830
- <nav class="md-nav" aria-label="App Developer Guide" data-md-level="1">
1831
- <label class="md-nav__title" for="__nav_3">
1832
- <span class="md-nav__icon md-icon"></span>
1833
- App Developer Guide
1834
- </label>
1835
- <ul class="md-nav__list" data-md-scrollfix>
1836
-
1837
1827
 
1838
1828
 
1839
1829
 
1840
1830
 
1841
1831
 
1842
1832
  <li class="md-nav__item">
1843
- <a href="../../../plugins/development.html" class="md-nav__link">
1844
- Developing Apps
1833
+ <a href="../../../models/dcim/powerporttemplate.html" class="md-nav__link">
1834
+ Power Port Template
1845
1835
  </a>
1846
1836
  </li>
1847
1837
 
@@ -1854,8 +1844,8 @@
1854
1844
 
1855
1845
 
1856
1846
  <li class="md-nav__item">
1857
- <a href="../../../plugins/porting-from-netbox.html" class="md-nav__link">
1858
- Porting NetBox Plugins to Nautobot
1847
+ <a href="../../../models/dcim/rack.html" class="md-nav__link">
1848
+ Rack
1859
1849
  </a>
1860
1850
  </li>
1861
1851
 
@@ -1866,29 +1856,15 @@
1866
1856
 
1867
1857
 
1868
1858
 
1869
-
1870
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>
1871
1865
 
1872
-
1873
- <li class="md-nav__item md-nav__item--active md-nav__item--nested">
1874
-
1875
-
1876
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_3" type="checkbox" id="__nav_3_3" checked>
1877
-
1878
-
1879
-
1880
-
1881
- <label class="md-nav__link" for="__nav_3_3">
1882
- Code Reference
1883
- <span class="md-nav__icon md-icon"></span>
1884
- </label>
1885
-
1886
- <nav class="md-nav" aria-label="Code Reference" data-md-level="2">
1887
- <label class="md-nav__title" for="__nav_3_3">
1888
- <span class="md-nav__icon md-icon"></span>
1889
- Code Reference
1890
- </label>
1891
- <ul class="md-nav__list" data-md-scrollfix>
1866
+
1867
+
1892
1868
 
1893
1869
 
1894
1870
 
@@ -1896,8 +1872,8 @@
1896
1872
 
1897
1873
 
1898
1874
  <li class="md-nav__item">
1899
- <a href="__init__.html" class="md-nav__link">
1900
- nautobot.apps
1875
+ <a href="../../../models/dcim/rackreservation.html" class="md-nav__link">
1876
+ Rack Reservation
1901
1877
  </a>
1902
1878
  </li>
1903
1879
 
@@ -1910,8 +1886,8 @@
1910
1886
 
1911
1887
 
1912
1888
  <li class="md-nav__item">
1913
- <a href="admin.html" class="md-nav__link">
1914
- nautobot.apps.admin
1889
+ <a href="../../../models/dcim/rearport.html" class="md-nav__link">
1890
+ Rear Port
1915
1891
  </a>
1916
1892
  </li>
1917
1893
 
@@ -1924,8 +1900,1214 @@
1924
1900
 
1925
1901
 
1926
1902
  <li class="md-nav__item">
1927
- <a href="api.html" class="md-nav__link">
1928
- nautobot.apps.api
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" >
2264
+
2265
+
2266
+
2267
+ <label class="md-nav__link" for="__nav_2_8_5" id="__nav_2_8_5_label" tabindex="0">
2268
+ Tenancy
2269
+ <span class="md-nav__icon md-icon"></span>
2270
+ </label>
2271
+
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">
2274
+ <span class="md-nav__icon md-icon"></span>
2275
+ Tenancy
2276
+ </label>
2277
+ <ul class="md-nav__list" data-md-scrollfix>
2278
+
2279
+
2280
+
2281
+
2282
+
2283
+
2284
+ <li class="md-nav__item">
2285
+ <a href="../../../models/tenancy/tenant.html" class="md-nav__link">
2286
+ Tenant
2287
+ </a>
2288
+ </li>
2289
+
2290
+
2291
+
2292
+
2293
+
2294
+
2295
+
2296
+
2297
+
2298
+ <li class="md-nav__item">
2299
+ <a href="../../../models/tenancy/tenantgroup.html" class="md-nav__link">
2300
+ Tenant Group
2301
+ </a>
2302
+ </li>
2303
+
2304
+
2305
+
2306
+
2307
+ </ul>
2308
+ </nav>
2309
+ </li>
2310
+
2311
+
2312
+
2313
+
2314
+
2315
+
2316
+
2317
+
2318
+
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>
2340
+
2341
+
2342
+
2343
+
2344
+
2345
+
2346
+ <li class="md-nav__item">
2347
+ <a href="../../../models/users/objectpermission.html" class="md-nav__link">
2348
+ Object Permission
2349
+ </a>
2350
+ </li>
2351
+
2352
+
2353
+
2354
+
2355
+
2356
+
2357
+
2358
+
2359
+
2360
+ <li class="md-nav__item">
2361
+ <a href="../../../models/users/token.html" class="md-nav__link">
2362
+ Token
2363
+ </a>
2364
+ </li>
2365
+
2366
+
2367
+
2368
+
2369
+ </ul>
2370
+ </nav>
2371
+ </li>
2372
+
2373
+
2374
+
2375
+
2376
+
2377
+
2378
+
2379
+
2380
+
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>
2402
+
2403
+
2404
+
2405
+
2406
+
2407
+
2408
+ <li class="md-nav__item">
2409
+ <a href="../../../models/virtualization/cluster.html" class="md-nav__link">
2410
+ Cluster
2411
+ </a>
2412
+ </li>
2413
+
2414
+
2415
+
2416
+
2417
+
2418
+
2419
+
2420
+
2421
+
2422
+ <li class="md-nav__item">
2423
+ <a href="../../../models/virtualization/clustergroup.html" class="md-nav__link">
2424
+ Cluster Group
2425
+ </a>
2426
+ </li>
2427
+
2428
+
2429
+
2430
+
2431
+
2432
+
2433
+
2434
+
2435
+
2436
+ <li class="md-nav__item">
2437
+ <a href="../../../models/virtualization/clustertype.html" class="md-nav__link">
2438
+ Cluster Type
2439
+ </a>
2440
+ </li>
2441
+
2442
+
2443
+
2444
+
2445
+
2446
+
2447
+
2448
+
2449
+
2450
+ <li class="md-nav__item">
2451
+ <a href="../../../models/virtualization/virtualmachine.html" class="md-nav__link">
2452
+ Virtual Machine
2453
+ </a>
2454
+ </li>
2455
+
2456
+
2457
+
2458
+
2459
+
2460
+
2461
+
2462
+
2463
+
2464
+ <li class="md-nav__item">
2465
+ <a href="../../../models/virtualization/vminterface.html" class="md-nav__link">
2466
+ VM Interface
2467
+ </a>
2468
+ </li>
2469
+
2470
+
2471
+
2472
+
2473
+ </ul>
2474
+ </nav>
2475
+ </li>
2476
+
2477
+
2478
+
2479
+
2480
+ </ul>
2481
+ </nav>
2482
+ </li>
2483
+
2484
+
2485
+
2486
+
2487
+
2488
+
2489
+
2490
+
2491
+
2492
+
2493
+ <li class="md-nav__item md-nav__item--nested">
2494
+
2495
+
2496
+
2497
+
2498
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_9" >
2499
+
2500
+
2501
+
2502
+ <label class="md-nav__link" for="__nav_2_9" id="__nav_2_9_label" tabindex="0">
2503
+ Additional Features
2504
+ <span class="md-nav__icon md-icon"></span>
2505
+ </label>
2506
+
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">
2509
+ <span class="md-nav__icon md-icon"></span>
2510
+ Additional Features
2511
+ </label>
2512
+ <ul class="md-nav__list" data-md-scrollfix>
2513
+
2514
+
2515
+
2516
+
2517
+
2518
+
2519
+ <li class="md-nav__item">
2520
+ <a href="../../../additional-features/caching.html" class="md-nav__link">
2521
+ Caching
2522
+ </a>
2523
+ </li>
2524
+
2525
+
2526
+
2527
+
2528
+
2529
+
2530
+
2531
+
2532
+
2533
+ <li class="md-nav__item">
2534
+ <a href="../../../additional-features/change-logging.html" class="md-nav__link">
2535
+ Change Logging
2536
+ </a>
2537
+ </li>
2538
+
2539
+
2540
+
2541
+
2542
+
2543
+
2544
+
2545
+
2546
+
2547
+ <li class="md-nav__item">
2548
+ <a href="../../../models/extras/computedfield.html" class="md-nav__link">
2549
+ Computed Fields
2550
+ </a>
2551
+ </li>
2552
+
2553
+
2554
+
2555
+
2556
+
2557
+
2558
+
2559
+
2560
+
2561
+ <li class="md-nav__item">
2562
+ <a href="../../../additional-features/config-contexts.html" class="md-nav__link">
2563
+ Context Data
2564
+ </a>
2565
+ </li>
2566
+
2567
+
2568
+
2569
+
2570
+
2571
+
2572
+
2573
+
2574
+
2575
+ <li class="md-nav__item">
2576
+ <a href="../../../models/extras/customfield.html" class="md-nav__link">
2577
+ Custom Fields
2578
+ </a>
2579
+ </li>
2580
+
2581
+
2582
+
2583
+
2584
+
2585
+
2586
+
2587
+
2588
+
2589
+ <li class="md-nav__item">
2590
+ <a href="../../../models/extras/customlink.html" class="md-nav__link">
2591
+ Custom Links
2592
+ </a>
2593
+ </li>
2594
+
2595
+
2596
+
2597
+
2598
+
2599
+
2600
+
2601
+
2602
+
2603
+ <li class="md-nav__item">
2604
+ <a href="../../../models/extras/dynamicgroup.html" class="md-nav__link">
2605
+ Dynamic Groups
2606
+ </a>
2607
+ </li>
2608
+
2609
+
2610
+
2611
+
2612
+
2613
+
2614
+
2615
+
2616
+
2617
+ <li class="md-nav__item">
2618
+ <a href="../../../models/extras/exporttemplate.html" class="md-nav__link">
2619
+ Export Templates
2620
+ </a>
2621
+ </li>
2622
+
2623
+
2624
+
2625
+
2626
+
2627
+
2628
+
2629
+
2630
+
2631
+ <li class="md-nav__item">
2632
+ <a href="../../../models/extras/gitrepository.html" class="md-nav__link">
2633
+ Git Repositories
2634
+ </a>
2635
+ </li>
2636
+
2637
+
2638
+
2639
+
2640
+
2641
+
2642
+
2643
+
2644
+
2645
+ <li class="md-nav__item">
2646
+ <a href="../../../additional-features/healthcheck.html" class="md-nav__link">
2647
+ Health Check
2648
+ </a>
2649
+ </li>
2650
+
2651
+
2652
+
2653
+
2654
+
2655
+
2656
+
2657
+
2658
+
2659
+ <li class="md-nav__item">
2660
+ <a href="../../../additional-features/jobs.html" class="md-nav__link">
2661
+ Jobs
2662
+ </a>
2663
+ </li>
2664
+
2665
+
2666
+
2667
+
2668
+
2669
+
2670
+
2671
+
2672
+
2673
+ <li class="md-nav__item">
2674
+ <a href="../../../models/extras/jobbutton.html" class="md-nav__link">
2675
+ Job Buttons
2676
+ </a>
2677
+ </li>
2678
+
2679
+
2680
+
2681
+
2682
+
2683
+
2684
+
2685
+
2686
+
2687
+ <li class="md-nav__item">
2688
+ <a href="../../../models/extras/jobhook.html" class="md-nav__link">
2689
+ Job Hooks
2690
+ </a>
2691
+ </li>
2692
+
2693
+
2694
+
2695
+
2696
+
2697
+
2698
+
2699
+
2700
+
2701
+ <li class="md-nav__item">
2702
+ <a href="../../../additional-features/job-scheduling-and-approvals.html" class="md-nav__link">
2703
+ Job Scheduling and Approvals
2704
+ </a>
2705
+ </li>
2706
+
2707
+
2708
+
2709
+
2710
+
2711
+
2712
+
2713
+
2714
+
2715
+ <li class="md-nav__item">
2716
+ <a href="../../../additional-features/napalm.html" class="md-nav__link">
2717
+ NAPALM
2718
+ </a>
2719
+ </li>
2720
+
2721
+
2722
+
2723
+
2724
+
2725
+
2726
+
2727
+
2728
+
2729
+ <li class="md-nav__item">
2730
+ <a href="../../../models/extras/note.html" class="md-nav__link">
2731
+ Notes
2732
+ </a>
2733
+ </li>
2734
+
2735
+
2736
+
2737
+
2738
+
2739
+
2740
+
2741
+
2742
+
2743
+ <li class="md-nav__item">
2744
+ <a href="../../../additional-features/prometheus-metrics.html" class="md-nav__link">
2745
+ Prometheus Metrics
2746
+ </a>
2747
+ </li>
2748
+
2749
+
2750
+
2751
+
2752
+
2753
+
2754
+
2755
+
2756
+
2757
+ <li class="md-nav__item">
2758
+ <a href="../../../models/extras/relationship.html" class="md-nav__link">
2759
+ Relationships
2760
+ </a>
2761
+ </li>
2762
+
2763
+
2764
+
2765
+
2766
+
2767
+
2768
+
2769
+
2770
+
2771
+ <li class="md-nav__item">
2772
+ <a href="../../../models/extras/status.html" class="md-nav__link">
2773
+ Statuses
2774
+ </a>
2775
+ </li>
2776
+
2777
+
2778
+
2779
+
2780
+
2781
+
2782
+
2783
+
2784
+
2785
+ <li class="md-nav__item">
2786
+ <a href="../../../models/extras/tag.html" class="md-nav__link">
2787
+ Tags
2788
+ </a>
2789
+ </li>
2790
+
2791
+
2792
+
2793
+
2794
+
2795
+
2796
+
2797
+
2798
+
2799
+ <li class="md-nav__item">
2800
+ <a href="../../../additional-features/template-filters.html" class="md-nav__link">
2801
+ Template Filters
2802
+ </a>
2803
+ </li>
2804
+
2805
+
2806
+
2807
+
2808
+
2809
+
2810
+
2811
+
2812
+
2813
+ <li class="md-nav__item">
2814
+ <a href="../../../models/extras/webhook.html" class="md-nav__link">
2815
+ Webhooks
2816
+ </a>
2817
+ </li>
2818
+
2819
+
2820
+
2821
+
2822
+ </ul>
2823
+ </nav>
2824
+ </li>
2825
+
2826
+
2827
+
2828
+
2829
+
2830
+
2831
+
2832
+
2833
+
2834
+
2835
+ <li class="md-nav__item md-nav__item--nested">
2836
+
2837
+
2838
+
2839
+
2840
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_10" >
2841
+
2842
+
2843
+
2844
+ <label class="md-nav__link" for="__nav_2_10" id="__nav_2_10_label" tabindex="0">
2845
+ REST API
2846
+ <span class="md-nav__icon md-icon"></span>
2847
+ </label>
2848
+
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">
2851
+ <span class="md-nav__icon md-icon"></span>
2852
+ REST API
2853
+ </label>
2854
+ <ul class="md-nav__list" data-md-scrollfix>
2855
+
2856
+
2857
+
2858
+
2859
+
2860
+
2861
+ <li class="md-nav__item">
2862
+ <a href="../../../rest-api/overview.html" class="md-nav__link">
2863
+ Overview
2864
+ </a>
2865
+ </li>
2866
+
2867
+
2868
+
2869
+
2870
+
2871
+
2872
+
2873
+
2874
+
2875
+ <li class="md-nav__item">
2876
+ <a href="../../../rest-api/filtering.html" class="md-nav__link">
2877
+ Filtering
2878
+ </a>
2879
+ </li>
2880
+
2881
+
2882
+
2883
+
2884
+
2885
+
2886
+
2887
+
2888
+
2889
+ <li class="md-nav__item">
2890
+ <a href="../../../rest-api/authentication.html" class="md-nav__link">
2891
+ Authentication
2892
+ </a>
2893
+ </li>
2894
+
2895
+
2896
+
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
+
2912
+ </ul>
2913
+ </nav>
2914
+ </li>
2915
+
2916
+
2917
+
2918
+
2919
+
2920
+
2921
+
2922
+
2923
+
2924
+
2925
+ <li class="md-nav__item md-nav__item--nested">
2926
+
2927
+
2928
+
2929
+
2930
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_11" >
2931
+
2932
+
2933
+
2934
+ <label class="md-nav__link" for="__nav_2_11" id="__nav_2_11_label" tabindex="0">
2935
+ GraphQL API
2936
+ <span class="md-nav__icon md-icon"></span>
2937
+ </label>
2938
+
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">
2941
+ <span class="md-nav__icon md-icon"></span>
2942
+ GraphQL API
2943
+ </label>
2944
+ <ul class="md-nav__list" data-md-scrollfix>
2945
+
2946
+
2947
+
2948
+
2949
+
2950
+
2951
+ <li class="md-nav__item">
2952
+ <a href="../../../additional-features/graphql.html" class="md-nav__link">
2953
+ Overview
2954
+ </a>
2955
+ </li>
2956
+
2957
+
2958
+
2959
+
2960
+ </ul>
2961
+ </nav>
2962
+ </li>
2963
+
2964
+
2965
+
2966
+
2967
+
2968
+
2969
+
2970
+
2971
+
2972
+ <li class="md-nav__item">
2973
+ <a href="../../../plugins/index.html" class="md-nav__link">
2974
+ Installing and Using Plugins
2975
+ </a>
2976
+ </li>
2977
+
2978
+
2979
+
2980
+
2981
+ </ul>
2982
+ </nav>
2983
+ </li>
2984
+
2985
+
2986
+
2987
+
2988
+
2989
+
2990
+
2991
+
2992
+
2993
+
2994
+
2995
+
2996
+
2997
+ <li class="md-nav__item md-nav__item--active md-nav__item--nested">
2998
+
2999
+
3000
+
3001
+
3002
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" checked>
3003
+
3004
+
3005
+
3006
+ <label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
3007
+ App Developer Guide
3008
+ <span class="md-nav__icon md-icon"></span>
3009
+ </label>
3010
+
3011
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="true">
3012
+ <label class="md-nav__title" for="__nav_3">
3013
+ <span class="md-nav__icon md-icon"></span>
3014
+ App Developer Guide
3015
+ </label>
3016
+ <ul class="md-nav__list" data-md-scrollfix>
3017
+
3018
+
3019
+
3020
+
3021
+
3022
+
3023
+ <li class="md-nav__item">
3024
+ <a href="../../../plugins/development.html" class="md-nav__link">
3025
+ Developing Apps
3026
+ </a>
3027
+ </li>
3028
+
3029
+
3030
+
3031
+
3032
+
3033
+
3034
+
3035
+
3036
+
3037
+ <li class="md-nav__item">
3038
+ <a href="../../../plugins/porting-from-netbox.html" class="md-nav__link">
3039
+ Porting NetBox Plugins to Nautobot
3040
+ </a>
3041
+ </li>
3042
+
3043
+
3044
+
3045
+
3046
+
3047
+
3048
+
3049
+
3050
+
3051
+
3052
+
3053
+
3054
+ <li class="md-nav__item md-nav__item--active md-nav__item--nested">
3055
+
3056
+
3057
+
3058
+
3059
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_3" checked>
3060
+
3061
+
3062
+
3063
+ <label class="md-nav__link" for="__nav_3_3" id="__nav_3_3_label" tabindex="0">
3064
+ Code Reference
3065
+ <span class="md-nav__icon md-icon"></span>
3066
+ </label>
3067
+
3068
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_3_label" aria-expanded="true">
3069
+ <label class="md-nav__title" for="__nav_3_3">
3070
+ <span class="md-nav__icon md-icon"></span>
3071
+ Code Reference
3072
+ </label>
3073
+ <ul class="md-nav__list" data-md-scrollfix>
3074
+
3075
+
3076
+
3077
+
3078
+
3079
+
3080
+ <li class="md-nav__item">
3081
+ <a href="__init__.html" class="md-nav__link">
3082
+ nautobot.apps
3083
+ </a>
3084
+ </li>
3085
+
3086
+
3087
+
3088
+
3089
+
3090
+
3091
+
3092
+
3093
+
3094
+ <li class="md-nav__item">
3095
+ <a href="admin.html" class="md-nav__link">
3096
+ nautobot.apps.admin
3097
+ </a>
3098
+ </li>
3099
+
3100
+
3101
+
3102
+
3103
+
3104
+
3105
+
3106
+
3107
+
3108
+ <li class="md-nav__item">
3109
+ <a href="api.html" class="md-nav__link">
3110
+ nautobot.apps.api
1929
3111
  </a>
1930
3112
  </li>
1931
3113
 
@@ -1997,7 +3179,7 @@
1997
3179
 
1998
3180
  <li class="md-nav__item md-nav__item--active">
1999
3181
 
2000
- <input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
3182
+ <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
2001
3183
 
2002
3184
 
2003
3185
 
@@ -2047,6 +3229,13 @@
2047
3229
  present_in_database
2048
3230
  </a>
2049
3231
 
3232
+ </li>
3233
+
3234
+ <li class="md-nav__item">
3235
+ <a href="#nautobot.core.models.BaseModel.get_absolute_url" class="md-nav__link">
3236
+ get_absolute_url()
3237
+ </a>
3238
+
2050
3239
  </li>
2051
3240
 
2052
3241
  <li class="md-nav__item">
@@ -2315,17 +3504,18 @@
2315
3504
  <li class="md-nav__item md-nav__item--nested">
2316
3505
 
2317
3506
 
2318
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4" type="checkbox" id="__nav_4" >
2319
3507
 
2320
3508
 
3509
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
2321
3510
 
2322
3511
 
2323
- <label class="md-nav__link" for="__nav_4">
3512
+
3513
+ <label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
2324
3514
  Core Developer Guide
2325
3515
  <span class="md-nav__icon md-icon"></span>
2326
3516
  </label>
2327
3517
 
2328
- <nav class="md-nav" aria-label="Core Developer Guide" data-md-level="1">
3518
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
2329
3519
  <label class="md-nav__title" for="__nav_4">
2330
3520
  <span class="md-nav__icon md-icon"></span>
2331
3521
  Core Developer Guide
@@ -2559,17 +3749,18 @@
2559
3749
  <li class="md-nav__item md-nav__item--nested">
2560
3750
 
2561
3751
 
2562
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" type="checkbox" id="__nav_5" >
2563
3752
 
2564
3753
 
3754
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
3755
+
2565
3756
 
2566
3757
 
2567
- <label class="md-nav__link" for="__nav_5">
3758
+ <label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
2568
3759
  Release Notes
2569
3760
  <span class="md-nav__icon md-icon"></span>
2570
3761
  </label>
2571
3762
 
2572
- <nav class="md-nav" aria-label="Release Notes" data-md-level="1">
3763
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
2573
3764
  <label class="md-nav__title" for="__nav_5">
2574
3765
  <span class="md-nav__icon md-icon"></span>
2575
3766
  Release Notes
@@ -2705,17 +3896,18 @@
2705
3896
  <li class="md-nav__item md-nav__item--nested">
2706
3897
 
2707
3898
 
2708
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" type="checkbox" id="__nav_6" >
2709
3899
 
2710
3900
 
3901
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
2711
3902
 
2712
3903
 
2713
- <label class="md-nav__link" for="__nav_6">
3904
+
3905
+ <label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
2714
3906
  Nautobot Apps
2715
3907
  <span class="md-nav__icon md-icon"></span>
2716
3908
  </label>
2717
3909
 
2718
- <nav class="md-nav" aria-label="Nautobot Apps" data-md-level="1">
3910
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
2719
3911
  <label class="md-nav__title" for="__nav_6">
2720
3912
  <span class="md-nav__icon md-icon"></span>
2721
3913
  Nautobot Apps
@@ -2745,17 +3937,18 @@
2745
3937
  <li class="md-nav__item md-nav__item--nested">
2746
3938
 
2747
3939
 
2748
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6_2" type="checkbox" id="__nav_6_2" >
2749
3940
 
2750
3941
 
3942
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_2" >
3943
+
2751
3944
 
2752
3945
 
2753
- <label class="md-nav__link" for="__nav_6_2">
3946
+ <label class="md-nav__link" for="__nav_6_2" id="__nav_6_2_label" tabindex="0">
2754
3947
  Network to Code App Docs
2755
3948
  <span class="md-nav__icon md-icon"></span>
2756
3949
  </label>
2757
3950
 
2758
- <nav class="md-nav" aria-label="Network to Code App Docs" data-md-level="2">
3951
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_6_2_label" aria-expanded="false">
2759
3952
  <label class="md-nav__title" for="__nav_6_2">
2760
3953
  <span class="md-nav__icon md-icon"></span>
2761
3954
  Network to Code App Docs
@@ -2782,8 +3975,8 @@
2782
3975
 
2783
3976
 
2784
3977
  <li class="md-nav__item">
2785
- <a href="https://nautobot-plugin-firewall-models.readthedocs.io/en/latest/" class="md-nav__link">
2786
- Nautobot Firewall Models
3978
+ <a href="https://docs.nautobot.com/projects/circuit-maintenance/en/latest/" class="md-nav__link">
3979
+ Nautobot Circuit Maintenance
2787
3980
  </a>
2788
3981
  </li>
2789
3982
 
@@ -2796,8 +3989,36 @@
2796
3989
 
2797
3990
 
2798
3991
  <li class="md-nav__item">
2799
- <a href="https://docs.nautobot.com/projects/plugin-nornir/en/latest/" class="md-nav__link">
2800
- Nautobot Plugin Nornir
3992
+ <a href="https://docs.nautobot.com/projects/device-lifecycle/en/latest/" class="md-nav__link">
3993
+ Nautobot Device LifeCycle Management
3994
+ </a>
3995
+ </li>
3996
+
3997
+
3998
+
3999
+
4000
+
4001
+
4002
+
4003
+
4004
+
4005
+ <li class="md-nav__item">
4006
+ <a href="https://docs.nautobot.com/projects/device-onboarding/en/latest/" class="md-nav__link">
4007
+ Nautobot Device Onboarding
4008
+ </a>
4009
+ </li>
4010
+
4011
+
4012
+
4013
+
4014
+
4015
+
4016
+
4017
+
4018
+
4019
+ <li class="md-nav__item">
4020
+ <a href="https://nautobot-plugin-firewall-models.readthedocs.io/en/latest/" class="md-nav__link">
4021
+ Nautobot Firewall Models
2801
4022
  </a>
2802
4023
  </li>
2803
4024
 
@@ -2824,7 +4045,21 @@
2824
4045
 
2825
4046
 
2826
4047
  <li class="md-nav__item">
2827
- <a href="https://nautobot-plugin-ssot.readthedocs.io/en/latest/" class="md-nav__link">
4048
+ <a href="https://docs.nautobot.com/projects/plugin-nornir/en/latest/" class="md-nav__link">
4049
+ Nautobot Plugin Nornir
4050
+ </a>
4051
+ </li>
4052
+
4053
+
4054
+
4055
+
4056
+
4057
+
4058
+
4059
+
4060
+
4061
+ <li class="md-nav__item">
4062
+ <a href="https://docs.nautobot.com/projects/ssot/en/latest/" class="md-nav__link">
2828
4063
  Nautobot Single Source of Truth
2829
4064
  </a>
2830
4065
  </li>
@@ -2920,6 +4155,13 @@
2920
4155
  present_in_database
2921
4156
  </a>
2922
4157
 
4158
+ </li>
4159
+
4160
+ <li class="md-nav__item">
4161
+ <a href="#nautobot.core.models.BaseModel.get_absolute_url" class="md-nav__link">
4162
+ get_absolute_url()
4163
+ </a>
4164
+
2923
4165
  </li>
2924
4166
 
2925
4167
  <li class="md-nav__item">
@@ -3085,10 +4327,8 @@
3085
4327
 
3086
4328
 
3087
4329
 
3088
- <a href="https://github.com/nautobot/nautobot/edit/main/nautobot/docs/nautobot/apps/models.py" title="Edit this page" class="md-content__button md-icon">
3089
-
3090
- <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>
3091
- </a>
4330
+
4331
+
3092
4332
 
3093
4333
 
3094
4334
  <div class="doc doc-object doc-module">
@@ -3148,9 +4388,7 @@ can be used for the same purpose in most cases.</p>
3148
4388
 
3149
4389
  <details class="quote">
3150
4390
  <summary>Source code in <code>nautobot/core/models/__init__.py</code></summary>
3151
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-11"> 11</a></span>
3152
- <span class="normal"><a href="#__codelineno-0-12"> 12</a></span>
3153
- <span class="normal"><a href="#__codelineno-0-13"> 13</a></span>
4391
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-13"> 13</a></span>
3154
4392
  <span class="normal"><a href="#__codelineno-0-14"> 14</a></span>
3155
4393
  <span class="normal"><a href="#__codelineno-0-15"> 15</a></span>
3156
4394
  <span class="normal"><a href="#__codelineno-0-16"> 16</a></span>
@@ -3319,178 +4557,226 @@ can be used for the same purpose in most cases.</p>
3319
4557
  <span class="normal"><a href="#__codelineno-0-179">179</a></span>
3320
4558
  <span class="normal"><a href="#__codelineno-0-180">180</a></span>
3321
4559
  <span class="normal"><a href="#__codelineno-0-181">181</a></span>
3322
- <span class="normal"><a href="#__codelineno-0-182">182</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-11" name="__codelineno-0-11"></a><span class="k">class</span> <span class="nc">BaseModel</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
3323
- <a id="__codelineno-0-12" name="__codelineno-0-12"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3324
- <a id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="sd"> Base model class that all models should inherit from.</span>
3325
- <a id="__codelineno-0-14" name="__codelineno-0-14"></a>
3326
- <a id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="sd"> This abstract base provides globally common fields and functionality.</span>
4560
+ <span class="normal"><a href="#__codelineno-0-182">182</a></span>
4561
+ <span class="normal"><a href="#__codelineno-0-183">183</a></span>
4562
+ <span class="normal"><a href="#__codelineno-0-184">184</a></span>
4563
+ <span class="normal"><a href="#__codelineno-0-185">185</a></span>
4564
+ <span class="normal"><a href="#__codelineno-0-186">186</a></span>
4565
+ <span class="normal"><a href="#__codelineno-0-187">187</a></span>
4566
+ <span class="normal"><a href="#__codelineno-0-188">188</a></span>
4567
+ <span class="normal"><a href="#__codelineno-0-189">189</a></span>
4568
+ <span class="normal"><a href="#__codelineno-0-190">190</a></span>
4569
+ <span class="normal"><a href="#__codelineno-0-191">191</a></span>
4570
+ <span class="normal"><a href="#__codelineno-0-192">192</a></span>
4571
+ <span class="normal"><a href="#__codelineno-0-193">193</a></span>
4572
+ <span class="normal"><a href="#__codelineno-0-194">194</a></span>
4573
+ <span class="normal"><a href="#__codelineno-0-195">195</a></span>
4574
+ <span class="normal"><a href="#__codelineno-0-196">196</a></span>
4575
+ <span class="normal"><a href="#__codelineno-0-197">197</a></span>
4576
+ <span class="normal"><a href="#__codelineno-0-198">198</a></span>
4577
+ <span class="normal"><a href="#__codelineno-0-199">199</a></span>
4578
+ <span class="normal"><a href="#__codelineno-0-200">200</a></span>
4579
+ <span class="normal"><a href="#__codelineno-0-201">201</a></span>
4580
+ <span class="normal"><a href="#__codelineno-0-202">202</a></span>
4581
+ <span class="normal"><a href="#__codelineno-0-203">203</a></span>
4582
+ <span class="normal"><a href="#__codelineno-0-204">204</a></span>
4583
+ <span class="normal"><a href="#__codelineno-0-205">205</a></span>
4584
+ <span class="normal"><a href="#__codelineno-0-206">206</a></span>
4585
+ <span class="normal"><a href="#__codelineno-0-207">207</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-13" name="__codelineno-0-13"></a><span class="k">class</span> <span class="nc">BaseModel</span><span class="p">(</span><span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
4586
+ <a id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4587
+ <a id="__codelineno-0-15" name="__codelineno-0-15"></a><span class="sd"> Base model class that all models should inherit from.</span>
3327
4588
  <a id="__codelineno-0-16" name="__codelineno-0-16"></a>
3328
- <a id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="sd"> Here we define the primary key to be a UUID field and set its default to</span>
3329
- <a id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="sd"> automatically generate a random UUID value. Note however, this does not</span>
3330
- <a id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="sd"> operate in the same way as a traditional auto incrementing field for which</span>
3331
- <a id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="sd"> the value is issued by the database upon initial insert. In the case of</span>
3332
- <a id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="sd"> the UUID field, Django creates the value upon object instantiation. This</span>
3333
- <a id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="sd"> means the canonical pattern in Django of checking `self.pk is None` to tell</span>
3334
- <a id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="sd"> if an object has been created in the actual database does not work because</span>
3335
- <a id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="sd"> the object will always have the value populated prior to being saved to the</span>
3336
- <a id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="sd"> database for the first time. An alternate pattern of checking `not self.present_in_database`</span>
3337
- <a id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="sd"> can be used for the same purpose in most cases.</span>
3338
- <a id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="sd"> &quot;&quot;&quot;</span>
3339
- <a id="__codelineno-0-28" name="__codelineno-0-28"></a>
3340
- <a id="__codelineno-0-29" name="__codelineno-0-29"></a> <span class="nb">id</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">UUIDField</span><span class="p">(</span><span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
4589
+ <a id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="sd"> This abstract base provides globally common fields and functionality.</span>
4590
+ <a id="__codelineno-0-18" name="__codelineno-0-18"></a>
4591
+ <a id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="sd"> Here we define the primary key to be a UUID field and set its default to</span>
4592
+ <a id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="sd"> automatically generate a random UUID value. Note however, this does not</span>
4593
+ <a id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="sd"> operate in the same way as a traditional auto incrementing field for which</span>
4594
+ <a id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="sd"> the value is issued by the database upon initial insert. In the case of</span>
4595
+ <a id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="sd"> the UUID field, Django creates the value upon object instantiation. This</span>
4596
+ <a id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="sd"> means the canonical pattern in Django of checking `self.pk is None` to tell</span>
4597
+ <a id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="sd"> if an object has been created in the actual database does not work because</span>
4598
+ <a id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="sd"> the object will always have the value populated prior to being saved to the</span>
4599
+ <a id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="sd"> database for the first time. An alternate pattern of checking `not self.present_in_database`</span>
4600
+ <a id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="sd"> can be used for the same purpose in most cases.</span>
4601
+ <a id="__codelineno-0-29" name="__codelineno-0-29"></a><span class="sd"> &quot;&quot;&quot;</span>
3341
4602
  <a id="__codelineno-0-30" name="__codelineno-0-30"></a>
3342
- <a id="__codelineno-0-31" name="__codelineno-0-31"></a> <span class="n">objects</span> <span class="o">=</span> <span class="n">BaseManager</span><span class="o">.</span><span class="n">from_queryset</span><span class="p">(</span><span class="n">RestrictedQuerySet</span><span class="p">)()</span>
4603
+ <a id="__codelineno-0-31" name="__codelineno-0-31"></a> <span class="nb">id</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">UUIDField</span><span class="p">(</span><span class="n">primary_key</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="n">uuid</span><span class="o">.</span><span class="n">uuid4</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="n">editable</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
3343
4604
  <a id="__codelineno-0-32" name="__codelineno-0-32"></a>
3344
- <a id="__codelineno-0-33" name="__codelineno-0-33"></a> <span class="nd">@property</span>
3345
- <a id="__codelineno-0-34" name="__codelineno-0-34"></a> <span class="k">def</span> <span class="nf">present_in_database</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3346
- <a id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3347
- <a id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="sd"> True if the record exists in the database, False if it does not.</span>
3348
- <a id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="sd"> &quot;&quot;&quot;</span>
3349
- <a id="__codelineno-0-38" name="__codelineno-0-38"></a> <span class="k">return</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_state</span><span class="o">.</span><span class="n">adding</span>
3350
- <a id="__codelineno-0-39" name="__codelineno-0-39"></a>
3351
- <a id="__codelineno-0-40" name="__codelineno-0-40"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
3352
- <a id="__codelineno-0-41" name="__codelineno-0-41"></a> <span class="n">abstract</span> <span class="o">=</span> <span class="kc">True</span>
3353
- <a id="__codelineno-0-42" name="__codelineno-0-42"></a>
3354
- <a id="__codelineno-0-43" name="__codelineno-0-43"></a> <span class="k">def</span> <span class="nf">validated_save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3355
- <a id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3356
- <a id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="sd"> Perform model validation during instance save.</span>
4605
+ <a id="__codelineno-0-33" name="__codelineno-0-33"></a> <span class="n">objects</span> <span class="o">=</span> <span class="n">BaseManager</span><span class="o">.</span><span class="n">from_queryset</span><span class="p">(</span><span class="n">RestrictedQuerySet</span><span class="p">)()</span>
4606
+ <a id="__codelineno-0-34" name="__codelineno-0-34"></a>
4607
+ <a id="__codelineno-0-35" name="__codelineno-0-35"></a> <span class="nd">@property</span>
4608
+ <a id="__codelineno-0-36" name="__codelineno-0-36"></a> <span class="k">def</span> <span class="nf">present_in_database</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4609
+ <a id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4610
+ <a id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="sd"> True if the record exists in the database, False if it does not.</span>
4611
+ <a id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="sd"> &quot;&quot;&quot;</span>
4612
+ <a id="__codelineno-0-40" name="__codelineno-0-40"></a> <span class="k">return</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">_state</span><span class="o">.</span><span class="n">adding</span>
4613
+ <a id="__codelineno-0-41" name="__codelineno-0-41"></a>
4614
+ <a id="__codelineno-0-42" name="__codelineno-0-42"></a> <span class="k">def</span> <span class="nf">get_absolute_url</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">api</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
4615
+ <a id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4616
+ <a id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="sd"> Return the canonical URL for this object in either the UI or the REST API.</span>
4617
+ <a id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="sd"> &quot;&quot;&quot;</span>
3357
4618
  <a id="__codelineno-0-46" name="__codelineno-0-46"></a>
3358
- <a id="__codelineno-0-47" name="__codelineno-0-47"></a><span class="sd"> This is a convenience method that first calls `self.full_clean()` and then `self.save()`</span>
3359
- <a id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="sd"> which in effect enforces model validation prior to saving the instance, without having</span>
3360
- <a id="__codelineno-0-49" name="__codelineno-0-49"></a><span class="sd"> to manually make these calls seperately. This is a slight departure from Django norms,</span>
3361
- <a id="__codelineno-0-50" name="__codelineno-0-50"></a><span class="sd"> but is intended to offer an optional, simplified interface for performing this common</span>
3362
- <a id="__codelineno-0-51" name="__codelineno-0-51"></a><span class="sd"> workflow. The intended use is for user defined Jobs and scripts run via the `nautobot-server nbshell`</span>
3363
- <a id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="sd"> command.</span>
3364
- <a id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="sd"> &quot;&quot;&quot;</span>
3365
- <a id="__codelineno-0-54" name="__codelineno-0-54"></a> <span class="bp">self</span><span class="o">.</span><span class="n">full_clean</span><span class="p">()</span>
3366
- <a id="__codelineno-0-55" name="__codelineno-0-55"></a> <span class="bp">self</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
3367
- <a id="__codelineno-0-56" name="__codelineno-0-56"></a>
3368
- <a id="__codelineno-0-57" name="__codelineno-0-57"></a> <span class="k">def</span> <span class="nf">natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">:</span>
3369
- <a id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3370
- <a id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="sd"> Smarter default implementation of natural key construction.</span>
3371
- <a id="__codelineno-0-60" name="__codelineno-0-60"></a>
3372
- <a id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="sd"> 1. Handles nullable foreign keys (https://github.com/wq/django-natural-keys/issues/18)</span>
3373
- <a id="__codelineno-0-62" name="__codelineno-0-62"></a><span class="sd"> 2. Handles variadic natural-keys (e.g. Location model - [name, parent__name, parent__parent__name, ...].)</span>
3374
- <a id="__codelineno-0-63" name="__codelineno-0-63"></a><span class="sd"> &quot;&quot;&quot;</span>
3375
- <a id="__codelineno-0-64" name="__codelineno-0-64"></a> <span class="n">vals</span> <span class="o">=</span> <span class="p">[]</span>
3376
- <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="k">for</span> <span class="n">lookups</span> <span class="ow">in</span> <span class="p">[</span><span class="n">lookup</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;__&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">natural_key_field_lookups</span><span class="p">]:</span>
3377
- <a id="__codelineno-0-66" name="__codelineno-0-66"></a> <span class="n">val</span> <span class="o">=</span> <span class="bp">self</span>
3378
- <a id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="n">lookups</span><span class="p">:</span>
3379
- <a id="__codelineno-0-68" name="__codelineno-0-68"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">lookup</span><span class="p">)</span>
3380
- <a id="__codelineno-0-69" name="__codelineno-0-69"></a> <span class="k">if</span> <span class="n">val</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3381
- <a id="__codelineno-0-70" name="__codelineno-0-70"></a> <span class="k">break</span>
3382
- <a id="__codelineno-0-71" name="__codelineno-0-71"></a> <span class="n">vals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
3383
- <a id="__codelineno-0-72" name="__codelineno-0-72"></a> <span class="c1"># Strip trailing Nones from vals</span>
3384
- <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="k">while</span> <span class="n">vals</span> <span class="ow">and</span> <span class="n">vals</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3385
- <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="n">vals</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
3386
- <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="k">return</span> <span class="n">vals</span>
3387
- <a id="__codelineno-0-76" name="__codelineno-0-76"></a>
3388
- <a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="nd">@property</span>
3389
- <a id="__codelineno-0-78" name="__codelineno-0-78"></a> <span class="k">def</span> <span class="nf">natural_key_slug</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
3390
- <a id="__codelineno-0-79" name="__codelineno-0-79"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3391
- <a id="__codelineno-0-80" name="__codelineno-0-80"></a><span class="sd"> Automatic &quot;slug&quot; string derived from this model&#39;s natural key, suitable for use in URLs etc.</span>
4619
+ <a id="__codelineno-0-47" name="__codelineno-0-47"></a> <span class="c1"># Iterate the pk-like fields and try to get a URL, or return None.</span>
4620
+ <a id="__codelineno-0-48" name="__codelineno-0-48"></a> <span class="n">fields</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;pk&quot;</span><span class="p">,</span> <span class="s2">&quot;slug&quot;</span><span class="p">]</span> <span class="c1"># TODO: Eventually all PKs</span>
4621
+ <a id="__codelineno-0-49" name="__codelineno-0-49"></a> <span class="n">actions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;retrieve&quot;</span><span class="p">,</span> <span class="s2">&quot;detail&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">]</span> <span class="c1"># TODO: Eventually all retrieve</span>
4622
+ <a id="__codelineno-0-50" name="__codelineno-0-50"></a>
4623
+ <a id="__codelineno-0-51" name="__codelineno-0-51"></a> <span class="k">for</span> <span class="n">field</span> <span class="ow">in</span> <span class="n">fields</span><span class="p">:</span>
4624
+ <a id="__codelineno-0-52" name="__codelineno-0-52"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
4625
+ <a id="__codelineno-0-53" name="__codelineno-0-53"></a> <span class="k">continue</span>
4626
+ <a id="__codelineno-0-54" name="__codelineno-0-54"></a>
4627
+ <a id="__codelineno-0-55" name="__codelineno-0-55"></a> <span class="k">for</span> <span class="n">action</span> <span class="ow">in</span> <span class="n">actions</span><span class="p">:</span>
4628
+ <a id="__codelineno-0-56" name="__codelineno-0-56"></a> <span class="n">route</span> <span class="o">=</span> <span class="n">get_route_for_model</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">action</span><span class="p">,</span> <span class="n">api</span><span class="o">=</span><span class="n">api</span><span class="p">)</span>
4629
+ <a id="__codelineno-0-57" name="__codelineno-0-57"></a>
4630
+ <a id="__codelineno-0-58" name="__codelineno-0-58"></a> <span class="k">try</span><span class="p">:</span>
4631
+ <a id="__codelineno-0-59" name="__codelineno-0-59"></a> <span class="k">return</span> <span class="n">reverse</span><span class="p">(</span><span class="n">route</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="n">field</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">)})</span>
4632
+ <a id="__codelineno-0-60" name="__codelineno-0-60"></a> <span class="k">except</span> <span class="n">NoReverseMatch</span><span class="p">:</span>
4633
+ <a id="__codelineno-0-61" name="__codelineno-0-61"></a> <span class="k">continue</span>
4634
+ <a id="__codelineno-0-62" name="__codelineno-0-62"></a>
4635
+ <a id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="k">return</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Cannot find a URL for </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">app_label</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model_name</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
4636
+ <a id="__codelineno-0-64" name="__codelineno-0-64"></a>
4637
+ <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
4638
+ <a id="__codelineno-0-66" name="__codelineno-0-66"></a> <span class="n">abstract</span> <span class="o">=</span> <span class="kc">True</span>
4639
+ <a id="__codelineno-0-67" name="__codelineno-0-67"></a>
4640
+ <a id="__codelineno-0-68" name="__codelineno-0-68"></a> <span class="k">def</span> <span class="nf">validated_save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4641
+ <a id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4642
+ <a id="__codelineno-0-70" name="__codelineno-0-70"></a><span class="sd"> Perform model validation during instance save.</span>
4643
+ <a id="__codelineno-0-71" name="__codelineno-0-71"></a>
4644
+ <a id="__codelineno-0-72" name="__codelineno-0-72"></a><span class="sd"> This is a convenience method that first calls `self.full_clean()` and then `self.save()`</span>
4645
+ <a id="__codelineno-0-73" name="__codelineno-0-73"></a><span class="sd"> which in effect enforces model validation prior to saving the instance, without having</span>
4646
+ <a id="__codelineno-0-74" name="__codelineno-0-74"></a><span class="sd"> to manually make these calls seperately. This is a slight departure from Django norms,</span>
4647
+ <a id="__codelineno-0-75" name="__codelineno-0-75"></a><span class="sd"> but is intended to offer an optional, simplified interface for performing this common</span>
4648
+ <a id="__codelineno-0-76" name="__codelineno-0-76"></a><span class="sd"> workflow. The intended use is for user defined Jobs run via the `nautobot-server nbshell`</span>
4649
+ <a id="__codelineno-0-77" name="__codelineno-0-77"></a><span class="sd"> command.</span>
4650
+ <a id="__codelineno-0-78" name="__codelineno-0-78"></a><span class="sd"> &quot;&quot;&quot;</span>
4651
+ <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="bp">self</span><span class="o">.</span><span class="n">full_clean</span><span class="p">()</span>
4652
+ <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="bp">self</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
3392
4653
  <a id="__codelineno-0-81" name="__codelineno-0-81"></a>
3393
- <a id="__codelineno-0-82" name="__codelineno-0-82"></a><span class="sd"> A less naïve implementation than django-natural-keys provides by default, based around URL percent-encoding.</span>
3394
- <a id="__codelineno-0-83" name="__codelineno-0-83"></a><span class="sd"> &quot;&quot;&quot;</span>
3395
- <a id="__codelineno-0-84" name="__codelineno-0-84"></a> <span class="k">return</span> <span class="n">construct_natural_key_slug</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">natural_key</span><span class="p">())</span>
4654
+ <a id="__codelineno-0-82" name="__codelineno-0-82"></a> <span class="k">def</span> <span class="nf">natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">:</span>
4655
+ <a id="__codelineno-0-83" name="__codelineno-0-83"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4656
+ <a id="__codelineno-0-84" name="__codelineno-0-84"></a><span class="sd"> Smarter default implementation of natural key construction.</span>
3396
4657
  <a id="__codelineno-0-85" name="__codelineno-0-85"></a>
3397
- <a id="__codelineno-0-86" name="__codelineno-0-86"></a> <span class="nd">@classproperty</span> <span class="c1"># https://github.com/PyCQA/pylint-django/issues/240</span>
3398
- <a id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="k">def</span> <span class="nf">natural_key_field_lookups</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span> <span class="c1"># pylint: disable=no-self-argument</span>
3399
- <a id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3400
- <a id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="sd"> List of lookups (possibly including nested lookups for related models) that make up this model&#39;s natural key.</span>
3401
- <a id="__codelineno-0-90" name="__codelineno-0-90"></a>
3402
- <a id="__codelineno-0-91" name="__codelineno-0-91"></a><span class="sd"> BaseModel provides a &quot;smart&quot; implementation that tries to determine this automatically,</span>
3403
- <a id="__codelineno-0-92" name="__codelineno-0-92"></a><span class="sd"> but you can also explicitly set `natural_key_field_names` on a given model subclass if desired.</span>
3404
- <a id="__codelineno-0-93" name="__codelineno-0-93"></a>
3405
- <a id="__codelineno-0-94" name="__codelineno-0-94"></a><span class="sd"> This property is based on a consolidation of `django-natural-keys` `ForeignKeyModel.get_natural_key_info()`,</span>
3406
- <a id="__codelineno-0-95" name="__codelineno-0-95"></a><span class="sd"> `ForeignKeyModel.get_natural_key_def()`, and `ForeignKeyModel.get_natural_key_fields()`.</span>
3407
- <a id="__codelineno-0-96" name="__codelineno-0-96"></a>
3408
- <a id="__codelineno-0-97" name="__codelineno-0-97"></a><span class="sd"> Unlike `get_natural_key_def()`, this doesn&#39;t auto-exclude all AutoField and BigAutoField fields,</span>
3409
- <a id="__codelineno-0-98" name="__codelineno-0-98"></a><span class="sd"> but instead explicitly discounts the `id` field (only) as a candidate.</span>
3410
- <a id="__codelineno-0-99" name="__codelineno-0-99"></a><span class="sd"> &quot;&quot;&quot;</span>
3411
- <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="c1"># First, figure out which local fields comprise the natural key:</span>
3412
- <a id="__codelineno-0-101" name="__codelineno-0-101"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">[]</span>
3413
- <a id="__codelineno-0-102" name="__codelineno-0-102"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_names&quot;</span><span class="p">):</span>
3414
- <a id="__codelineno-0-103" name="__codelineno-0-103"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_names</span>
3415
- <a id="__codelineno-0-104" name="__codelineno-0-104"></a> <span class="k">else</span><span class="p">:</span>
3416
- <a id="__codelineno-0-105" name="__codelineno-0-105"></a> <span class="c1"># Does this model have any new-style UniqueConstraints? If so, pick the first one</span>
3417
- <a id="__codelineno-0-106" name="__codelineno-0-106"></a> <span class="k">for</span> <span class="n">constraint</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">constraints</span><span class="p">:</span>
3418
- <a id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">constraint</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">UniqueConstraint</span><span class="p">):</span>
3419
- <a id="__codelineno-0-108" name="__codelineno-0-108"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="n">constraint</span><span class="o">.</span><span class="n">fields</span>
3420
- <a id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="k">break</span>
3421
- <a id="__codelineno-0-110" name="__codelineno-0-110"></a> <span class="k">else</span><span class="p">:</span>
3422
- <a id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="c1"># Else, does this model have any old-style unique_together? If so, pick the first one.</span>
3423
- <a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">:</span>
3424
- <a id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
3425
- <a id="__codelineno-0-114" name="__codelineno-0-114"></a> <span class="k">else</span><span class="p">:</span>
3426
- <a id="__codelineno-0-115" name="__codelineno-0-115"></a> <span class="c1"># Else, do we have any individual unique=True fields? If so, pick the first one.</span>
3427
- <a id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="n">unique_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">field</span> <span class="k">for</span> <span class="n">field</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">fields</span> <span class="k">if</span> <span class="n">field</span><span class="o">.</span><span class="n">unique</span> <span class="ow">and</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span> <span class="o">!=</span> <span class="s2">&quot;id&quot;</span><span class="p">]</span>
3428
- <a id="__codelineno-0-117" name="__codelineno-0-117"></a> <span class="k">if</span> <span class="n">unique_fields</span><span class="p">:</span>
3429
- <a id="__codelineno-0-118" name="__codelineno-0-118"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">(</span><span class="n">unique_fields</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">name</span><span class="p">,)</span>
3430
- <a id="__codelineno-0-119" name="__codelineno-0-119"></a>
3431
- <a id="__codelineno-0-120" name="__codelineno-0-120"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
3432
- <a id="__codelineno-0-121" name="__codelineno-0-121"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3433
- <a id="__codelineno-0-122" name="__codelineno-0-122"></a> <span class="sa">f</span><span class="s2">&quot;Unable to identify an intrinsic natural-key definition for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">. &quot;</span>
3434
- <a id="__codelineno-0-123" name="__codelineno-0-123"></a> <span class="s2">&quot;If there isn&#39;t at least one UniqueConstraint, unique_together, or field with unique=True, &quot;</span>
3435
- <a id="__codelineno-0-124" name="__codelineno-0-124"></a> <span class="s2">&quot;you probably need to explicitly declare the &#39;natural_key_field_names&#39; for this model, &quot;</span>
3436
- <a id="__codelineno-0-125" name="__codelineno-0-125"></a> <span class="s2">&quot;or potentially override the default &#39;natural_key_field_lookups&#39; implementation for this model.&quot;</span>
3437
- <a id="__codelineno-0-126" name="__codelineno-0-126"></a> <span class="p">)</span>
3438
- <a id="__codelineno-0-127" name="__codelineno-0-127"></a>
3439
- <a id="__codelineno-0-128" name="__codelineno-0-128"></a> <span class="c1"># Next, for any natural key fields that have related models, get the natural key for the related model if known</span>
3440
- <a id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[]</span>
3441
- <a id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
3442
- <a id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="n">field</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">get_field</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
3443
- <a id="__codelineno-0-132" name="__codelineno-0-132"></a> <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;remote_field&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3444
- <a id="__codelineno-0-133" name="__codelineno-0-133"></a> <span class="c1"># Not a related field, so the field name is the field lookup</span>
3445
- <a id="__codelineno-0-134" name="__codelineno-0-134"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
3446
- <a id="__codelineno-0-135" name="__codelineno-0-135"></a> <span class="k">continue</span>
3447
- <a id="__codelineno-0-136" name="__codelineno-0-136"></a>
3448
- <a id="__codelineno-0-137" name="__codelineno-0-137"></a> <span class="n">related_model</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">remote_field</span><span class="o">.</span><span class="n">model</span>
3449
- <a id="__codelineno-0-138" name="__codelineno-0-138"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="kc">None</span>
3450
- <a id="__codelineno-0-139" name="__codelineno-0-139"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">related_model</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_lookups&quot;</span><span class="p">):</span>
3451
- <a id="__codelineno-0-140" name="__codelineno-0-140"></a> <span class="c1"># TODO: generic handling for self-referential case, as seen in Location</span>
3452
- <a id="__codelineno-0-141" name="__codelineno-0-141"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="n">related_model</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
3453
- <a id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="k">else</span><span class="p">:</span>
3454
- <a id="__codelineno-0-143" name="__codelineno-0-143"></a> <span class="c1"># Related model isn&#39;t a Nautobot model and so doesn&#39;t have a `natural_key_field_lookups`.</span>
3455
- <a id="__codelineno-0-144" name="__codelineno-0-144"></a> <span class="c1"># The common case we&#39;ve encountered so far is the contenttypes.ContentType model:</span>
3456
- <a id="__codelineno-0-145" name="__codelineno-0-145"></a> <span class="k">if</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">app_label</span> <span class="o">==</span> <span class="s2">&quot;contenttypes&quot;</span> <span class="ow">and</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model_name</span> <span class="o">==</span> <span class="s2">&quot;contenttype&quot;</span><span class="p">:</span>
3457
- <a id="__codelineno-0-146" name="__codelineno-0-146"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;app_label&quot;</span><span class="p">,</span> <span class="s2">&quot;model&quot;</span><span class="p">]</span>
3458
- <a id="__codelineno-0-147" name="__codelineno-0-147"></a> <span class="c1"># Additional special cases can be added here</span>
3459
- <a id="__codelineno-0-148" name="__codelineno-0-148"></a>
3460
- <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
3461
- <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3462
- <a id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="sa">f</span><span class="s2">&quot;Unable to determine the related natural-key fields for </span><span class="si">{</span><span class="n">related_model</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> &quot;</span>
3463
- <a id="__codelineno-0-152" name="__codelineno-0-152"></a> <span class="sa">f</span><span class="s2">&quot;(as referenced from </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">). If the related model is a non-Nautobot &quot;</span>
3464
- <a id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="s2">&quot;model (such as ContentType) then it may be appropriate to add special-case handling for this &quot;</span>
3465
- <a id="__codelineno-0-154" name="__codelineno-0-154"></a> <span class="s2">&quot;model in BaseModel.natural_key_field_lookups; alternately you may be able to solve this for &quot;</span>
3466
- <a id="__codelineno-0-155" name="__codelineno-0-155"></a> <span class="sa">f</span><span class="s2">&quot;a single special case by explicitly defining </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_field_lookups.&quot;</span>
3467
- <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="p">)</span>
3468
- <a id="__codelineno-0-157" name="__codelineno-0-157"></a>
3469
- <a id="__codelineno-0-158" name="__codelineno-0-158"></a> <span class="k">for</span> <span class="n">field_lookup</span> <span class="ow">in</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
3470
- <a id="__codelineno-0-159" name="__codelineno-0-159"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">field_lookup</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
3471
- <a id="__codelineno-0-160" name="__codelineno-0-160"></a>
3472
- <a id="__codelineno-0-161" name="__codelineno-0-161"></a> <span class="k">return</span> <span class="n">natural_key_field_lookups</span>
3473
- <a id="__codelineno-0-162" name="__codelineno-0-162"></a>
3474
- <a id="__codelineno-0-163" name="__codelineno-0-163"></a> <span class="nd">@classmethod</span>
3475
- <a id="__codelineno-0-164" name="__codelineno-0-164"></a> <span class="k">def</span> <span class="nf">natural_key_args_to_kwargs</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
3476
- <a id="__codelineno-0-165" name="__codelineno-0-165"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3477
- <a id="__codelineno-0-166" name="__codelineno-0-166"></a><span class="sd"> Helper function to map a list of natural key field values to actual kwargs suitable for lookup and filtering.</span>
3478
- <a id="__codelineno-0-167" name="__codelineno-0-167"></a>
3479
- <a id="__codelineno-0-168" name="__codelineno-0-168"></a><span class="sd"> Based on `django-natural-keys` `NaturalKeyQuerySet.natural_key_kwargs()` method.</span>
3480
- <a id="__codelineno-0-169" name="__codelineno-0-169"></a><span class="sd"> &quot;&quot;&quot;</span>
3481
- <a id="__codelineno-0-170" name="__codelineno-0-170"></a> <span class="n">args</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
3482
- <a id="__codelineno-0-171" name="__codelineno-0-171"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
3483
- <a id="__codelineno-0-172" name="__codelineno-0-172"></a> <span class="c1"># Because `natural_key` strips trailing `None` from the natural key to handle the variadic-natural-key case,</span>
3484
- <a id="__codelineno-0-173" name="__codelineno-0-173"></a> <span class="c1"># we may need to add trailing `None` back on to make the number of args match back up.</span>
3485
- <a id="__codelineno-0-174" name="__codelineno-0-174"></a> <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
3486
- <a id="__codelineno-0-175" name="__codelineno-0-175"></a> <span class="n">args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
3487
- <a id="__codelineno-0-176" name="__codelineno-0-176"></a> <span class="c1"># However, if we have *too many* args, that&#39;s just incorrect usage:</span>
3488
- <a id="__codelineno-0-177" name="__codelineno-0-177"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
3489
- <a id="__codelineno-0-178" name="__codelineno-0-178"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
3490
- <a id="__codelineno-0-179" name="__codelineno-0-179"></a> <span class="sa">f</span><span class="s2">&quot;Wrong number of natural-key args for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_args_to_kwargs() -- &quot;</span>
3491
- <a id="__codelineno-0-180" name="__codelineno-0-180"></a> <span class="sa">f</span><span class="s2">&quot;expected no more than </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">)</span><span class="si">}</span><span class="s2"> but got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">.&quot;</span>
3492
- <a id="__codelineno-0-181" name="__codelineno-0-181"></a> <span class="p">)</span>
3493
- <a id="__codelineno-0-182" name="__codelineno-0-182"></a> <span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">,</span> <span class="n">args</span><span class="p">))</span>
4658
+ <a id="__codelineno-0-86" name="__codelineno-0-86"></a><span class="sd"> 1. Handles nullable foreign keys (https://github.com/wq/django-natural-keys/issues/18)</span>
4659
+ <a id="__codelineno-0-87" name="__codelineno-0-87"></a><span class="sd"> 2. Handles variadic natural-keys (e.g. Location model - [name, parent__name, parent__parent__name, ...].)</span>
4660
+ <a id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="sd"> &quot;&quot;&quot;</span>
4661
+ <a id="__codelineno-0-89" name="__codelineno-0-89"></a> <span class="n">vals</span> <span class="o">=</span> <span class="p">[]</span>
4662
+ <a id="__codelineno-0-90" name="__codelineno-0-90"></a> <span class="k">for</span> <span class="n">lookups</span> <span class="ow">in</span> <span class="p">[</span><span class="n">lookup</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;__&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">natural_key_field_lookups</span><span class="p">]:</span>
4663
+ <a id="__codelineno-0-91" name="__codelineno-0-91"></a> <span class="n">val</span> <span class="o">=</span> <span class="bp">self</span>
4664
+ <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="n">lookups</span><span class="p">:</span>
4665
+ <a id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">lookup</span><span class="p">)</span>
4666
+ <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="k">if</span> <span class="n">val</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4667
+ <a id="__codelineno-0-95" name="__codelineno-0-95"></a> <span class="k">break</span>
4668
+ <a id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="n">vals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
4669
+ <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="c1"># Strip trailing Nones from vals</span>
4670
+ <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="k">while</span> <span class="n">vals</span> <span class="ow">and</span> <span class="n">vals</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4671
+ <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="n">vals</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
4672
+ <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="k">return</span> <span class="n">vals</span>
4673
+ <a id="__codelineno-0-101" name="__codelineno-0-101"></a>
4674
+ <a id="__codelineno-0-102" name="__codelineno-0-102"></a> <span class="nd">@property</span>
4675
+ <a id="__codelineno-0-103" name="__codelineno-0-103"></a> <span class="k">def</span> <span class="nf">natural_key_slug</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
4676
+ <a id="__codelineno-0-104" name="__codelineno-0-104"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4677
+ <a id="__codelineno-0-105" name="__codelineno-0-105"></a><span class="sd"> Automatic &quot;slug&quot; string derived from this model&#39;s natural key, suitable for use in URLs etc.</span>
4678
+ <a id="__codelineno-0-106" name="__codelineno-0-106"></a>
4679
+ <a id="__codelineno-0-107" name="__codelineno-0-107"></a><span class="sd"> A less naïve implementation than django-natural-keys provides by default, based around URL percent-encoding.</span>
4680
+ <a id="__codelineno-0-108" name="__codelineno-0-108"></a><span class="sd"> &quot;&quot;&quot;</span>
4681
+ <a id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="k">return</span> <span class="n">construct_natural_key_slug</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">natural_key</span><span class="p">())</span>
4682
+ <a id="__codelineno-0-110" name="__codelineno-0-110"></a>
4683
+ <a id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="nd">@classproperty</span> <span class="c1"># https://github.com/PyCQA/pylint-django/issues/240</span>
4684
+ <a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="k">def</span> <span class="nf">natural_key_field_lookups</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span> <span class="c1"># pylint: disable=no-self-argument</span>
4685
+ <a id="__codelineno-0-113" name="__codelineno-0-113"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4686
+ <a id="__codelineno-0-114" name="__codelineno-0-114"></a><span class="sd"> List of lookups (possibly including nested lookups for related models) that make up this model&#39;s natural key.</span>
4687
+ <a id="__codelineno-0-115" name="__codelineno-0-115"></a>
4688
+ <a id="__codelineno-0-116" name="__codelineno-0-116"></a><span class="sd"> BaseModel provides a &quot;smart&quot; implementation that tries to determine this automatically,</span>
4689
+ <a id="__codelineno-0-117" name="__codelineno-0-117"></a><span class="sd"> but you can also explicitly set `natural_key_field_names` on a given model subclass if desired.</span>
4690
+ <a id="__codelineno-0-118" name="__codelineno-0-118"></a>
4691
+ <a id="__codelineno-0-119" name="__codelineno-0-119"></a><span class="sd"> This property is based on a consolidation of `django-natural-keys` `ForeignKeyModel.get_natural_key_info()`,</span>
4692
+ <a id="__codelineno-0-120" name="__codelineno-0-120"></a><span class="sd"> `ForeignKeyModel.get_natural_key_def()`, and `ForeignKeyModel.get_natural_key_fields()`.</span>
4693
+ <a id="__codelineno-0-121" name="__codelineno-0-121"></a>
4694
+ <a id="__codelineno-0-122" name="__codelineno-0-122"></a><span class="sd"> Unlike `get_natural_key_def()`, this doesn&#39;t auto-exclude all AutoField and BigAutoField fields,</span>
4695
+ <a id="__codelineno-0-123" name="__codelineno-0-123"></a><span class="sd"> but instead explicitly discounts the `id` field (only) as a candidate.</span>
4696
+ <a id="__codelineno-0-124" name="__codelineno-0-124"></a><span class="sd"> &quot;&quot;&quot;</span>
4697
+ <a id="__codelineno-0-125" name="__codelineno-0-125"></a> <span class="c1"># First, figure out which local fields comprise the natural key:</span>
4698
+ <a id="__codelineno-0-126" name="__codelineno-0-126"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">[]</span>
4699
+ <a id="__codelineno-0-127" name="__codelineno-0-127"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_names&quot;</span><span class="p">):</span>
4700
+ <a id="__codelineno-0-128" name="__codelineno-0-128"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_names</span>
4701
+ <a id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="k">else</span><span class="p">:</span>
4702
+ <a id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="c1"># Does this model have any new-style UniqueConstraints? If so, pick the first one</span>
4703
+ <a id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="k">for</span> <span class="n">constraint</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">constraints</span><span class="p">:</span>
4704
+ <a id="__codelineno-0-132" name="__codelineno-0-132"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">constraint</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">UniqueConstraint</span><span class="p">):</span>
4705
+ <a id="__codelineno-0-133" name="__codelineno-0-133"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="n">constraint</span><span class="o">.</span><span class="n">fields</span>
4706
+ <a id="__codelineno-0-134" name="__codelineno-0-134"></a> <span class="k">break</span>
4707
+ <a id="__codelineno-0-135" name="__codelineno-0-135"></a> <span class="k">else</span><span class="p">:</span>
4708
+ <a id="__codelineno-0-136" name="__codelineno-0-136"></a> <span class="c1"># Else, does this model have any old-style unique_together? If so, pick the first one.</span>
4709
+ <a id="__codelineno-0-137" name="__codelineno-0-137"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">:</span>
4710
+ <a id="__codelineno-0-138" name="__codelineno-0-138"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
4711
+ <a id="__codelineno-0-139" name="__codelineno-0-139"></a> <span class="k">else</span><span class="p">:</span>
4712
+ <a id="__codelineno-0-140" name="__codelineno-0-140"></a> <span class="c1"># Else, do we have any individual unique=True fields? If so, pick the first one.</span>
4713
+ <a id="__codelineno-0-141" name="__codelineno-0-141"></a> <span class="n">unique_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">field</span> <span class="k">for</span> <span class="n">field</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">fields</span> <span class="k">if</span> <span class="n">field</span><span class="o">.</span><span class="n">unique</span> <span class="ow">and</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span> <span class="o">!=</span> <span class="s2">&quot;id&quot;</span><span class="p">]</span>
4714
+ <a id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="k">if</span> <span class="n">unique_fields</span><span class="p">:</span>
4715
+ <a id="__codelineno-0-143" name="__codelineno-0-143"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">(</span><span class="n">unique_fields</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">name</span><span class="p">,)</span>
4716
+ <a id="__codelineno-0-144" name="__codelineno-0-144"></a>
4717
+ <a id="__codelineno-0-145" name="__codelineno-0-145"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
4718
+ <a id="__codelineno-0-146" name="__codelineno-0-146"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
4719
+ <a id="__codelineno-0-147" name="__codelineno-0-147"></a> <span class="sa">f</span><span class="s2">&quot;Unable to identify an intrinsic natural-key definition for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">. &quot;</span>
4720
+ <a id="__codelineno-0-148" name="__codelineno-0-148"></a> <span class="s2">&quot;If there isn&#39;t at least one UniqueConstraint, unique_together, or field with unique=True, &quot;</span>
4721
+ <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="s2">&quot;you probably need to explicitly declare the &#39;natural_key_field_names&#39; for this model, &quot;</span>
4722
+ <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="s2">&quot;or potentially override the default &#39;natural_key_field_lookups&#39; implementation for this model.&quot;</span>
4723
+ <a id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="p">)</span>
4724
+ <a id="__codelineno-0-152" name="__codelineno-0-152"></a>
4725
+ <a id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="c1"># Next, for any natural key fields that have related models, get the natural key for the related model if known</span>
4726
+ <a id="__codelineno-0-154" name="__codelineno-0-154"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[]</span>
4727
+ <a id="__codelineno-0-155" name="__codelineno-0-155"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
4728
+ <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="n">field</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">get_field</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4729
+ <a id="__codelineno-0-157" name="__codelineno-0-157"></a> <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;remote_field&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4730
+ <a id="__codelineno-0-158" name="__codelineno-0-158"></a> <span class="c1"># Not a related field, so the field name is the field lookup</span>
4731
+ <a id="__codelineno-0-159" name="__codelineno-0-159"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4732
+ <a id="__codelineno-0-160" name="__codelineno-0-160"></a> <span class="k">continue</span>
4733
+ <a id="__codelineno-0-161" name="__codelineno-0-161"></a>
4734
+ <a id="__codelineno-0-162" name="__codelineno-0-162"></a> <span class="n">related_model</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">remote_field</span><span class="o">.</span><span class="n">model</span>
4735
+ <a id="__codelineno-0-163" name="__codelineno-0-163"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="kc">None</span>
4736
+ <a id="__codelineno-0-164" name="__codelineno-0-164"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">related_model</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_lookups&quot;</span><span class="p">):</span>
4737
+ <a id="__codelineno-0-165" name="__codelineno-0-165"></a> <span class="c1"># TODO: generic handling for self-referential case, as seen in Location</span>
4738
+ <a id="__codelineno-0-166" name="__codelineno-0-166"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="n">related_model</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
4739
+ <a id="__codelineno-0-167" name="__codelineno-0-167"></a> <span class="k">else</span><span class="p">:</span>
4740
+ <a id="__codelineno-0-168" name="__codelineno-0-168"></a> <span class="c1"># Related model isn&#39;t a Nautobot model and so doesn&#39;t have a `natural_key_field_lookups`.</span>
4741
+ <a id="__codelineno-0-169" name="__codelineno-0-169"></a> <span class="c1"># The common case we&#39;ve encountered so far is the contenttypes.ContentType model:</span>
4742
+ <a id="__codelineno-0-170" name="__codelineno-0-170"></a> <span class="k">if</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">app_label</span> <span class="o">==</span> <span class="s2">&quot;contenttypes&quot;</span> <span class="ow">and</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model_name</span> <span class="o">==</span> <span class="s2">&quot;contenttype&quot;</span><span class="p">:</span>
4743
+ <a id="__codelineno-0-171" name="__codelineno-0-171"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;app_label&quot;</span><span class="p">,</span> <span class="s2">&quot;model&quot;</span><span class="p">]</span>
4744
+ <a id="__codelineno-0-172" name="__codelineno-0-172"></a> <span class="c1"># Additional special cases can be added here</span>
4745
+ <a id="__codelineno-0-173" name="__codelineno-0-173"></a>
4746
+ <a id="__codelineno-0-174" name="__codelineno-0-174"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
4747
+ <a id="__codelineno-0-175" name="__codelineno-0-175"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
4748
+ <a id="__codelineno-0-176" name="__codelineno-0-176"></a> <span class="sa">f</span><span class="s2">&quot;Unable to determine the related natural-key fields for </span><span class="si">{</span><span class="n">related_model</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> &quot;</span>
4749
+ <a id="__codelineno-0-177" name="__codelineno-0-177"></a> <span class="sa">f</span><span class="s2">&quot;(as referenced from </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">). If the related model is a non-Nautobot &quot;</span>
4750
+ <a id="__codelineno-0-178" name="__codelineno-0-178"></a> <span class="s2">&quot;model (such as ContentType) then it may be appropriate to add special-case handling for this &quot;</span>
4751
+ <a id="__codelineno-0-179" name="__codelineno-0-179"></a> <span class="s2">&quot;model in BaseModel.natural_key_field_lookups; alternately you may be able to solve this for &quot;</span>
4752
+ <a id="__codelineno-0-180" name="__codelineno-0-180"></a> <span class="sa">f</span><span class="s2">&quot;a single special case by explicitly defining </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_field_lookups.&quot;</span>
4753
+ <a id="__codelineno-0-181" name="__codelineno-0-181"></a> <span class="p">)</span>
4754
+ <a id="__codelineno-0-182" name="__codelineno-0-182"></a>
4755
+ <a id="__codelineno-0-183" name="__codelineno-0-183"></a> <span class="k">for</span> <span class="n">field_lookup</span> <span class="ow">in</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
4756
+ <a id="__codelineno-0-184" name="__codelineno-0-184"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">field_lookup</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4757
+ <a id="__codelineno-0-185" name="__codelineno-0-185"></a>
4758
+ <a id="__codelineno-0-186" name="__codelineno-0-186"></a> <span class="k">return</span> <span class="n">natural_key_field_lookups</span>
4759
+ <a id="__codelineno-0-187" name="__codelineno-0-187"></a>
4760
+ <a id="__codelineno-0-188" name="__codelineno-0-188"></a> <span class="nd">@classmethod</span>
4761
+ <a id="__codelineno-0-189" name="__codelineno-0-189"></a> <span class="k">def</span> <span class="nf">natural_key_args_to_kwargs</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
4762
+ <a id="__codelineno-0-190" name="__codelineno-0-190"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4763
+ <a id="__codelineno-0-191" name="__codelineno-0-191"></a><span class="sd"> Helper function to map a list of natural key field values to actual kwargs suitable for lookup and filtering.</span>
4764
+ <a id="__codelineno-0-192" name="__codelineno-0-192"></a>
4765
+ <a id="__codelineno-0-193" name="__codelineno-0-193"></a><span class="sd"> Based on `django-natural-keys` `NaturalKeyQuerySet.natural_key_kwargs()` method.</span>
4766
+ <a id="__codelineno-0-194" name="__codelineno-0-194"></a><span class="sd"> &quot;&quot;&quot;</span>
4767
+ <a id="__codelineno-0-195" name="__codelineno-0-195"></a> <span class="n">args</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
4768
+ <a id="__codelineno-0-196" name="__codelineno-0-196"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
4769
+ <a id="__codelineno-0-197" name="__codelineno-0-197"></a> <span class="c1"># Because `natural_key` strips trailing `None` from the natural key to handle the variadic-natural-key case,</span>
4770
+ <a id="__codelineno-0-198" name="__codelineno-0-198"></a> <span class="c1"># we may need to add trailing `None` back on to make the number of args match back up.</span>
4771
+ <a id="__codelineno-0-199" name="__codelineno-0-199"></a> <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
4772
+ <a id="__codelineno-0-200" name="__codelineno-0-200"></a> <span class="n">args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
4773
+ <a id="__codelineno-0-201" name="__codelineno-0-201"></a> <span class="c1"># However, if we have *too many* args, that&#39;s just incorrect usage:</span>
4774
+ <a id="__codelineno-0-202" name="__codelineno-0-202"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
4775
+ <a id="__codelineno-0-203" name="__codelineno-0-203"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
4776
+ <a id="__codelineno-0-204" name="__codelineno-0-204"></a> <span class="sa">f</span><span class="s2">&quot;Wrong number of natural-key args for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_args_to_kwargs() -- &quot;</span>
4777
+ <a id="__codelineno-0-205" name="__codelineno-0-205"></a> <span class="sa">f</span><span class="s2">&quot;expected no more than </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">)</span><span class="si">}</span><span class="s2"> but got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">.&quot;</span>
4778
+ <a id="__codelineno-0-206" name="__codelineno-0-206"></a> <span class="p">)</span>
4779
+ <a id="__codelineno-0-207" name="__codelineno-0-207"></a> <span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">,</span> <span class="n">args</span><span class="p">))</span>
3494
4780
  </code></pre></div></td></tr></table></div>
3495
4781
  </details>
3496
4782
 
@@ -3553,6 +4839,71 @@ can be used for the same purpose in most cases.</p>
3553
4839
 
3554
4840
 
3555
4841
 
4842
+ <h3 id="nautobot.core.models.BaseModel.get_absolute_url" class="doc doc-heading">
4843
+ <code class="highlight language-python"><span class="n">get_absolute_url</span><span class="p">(</span><span class="n">api</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span></code>
4844
+
4845
+ <a href="#nautobot.core.models.BaseModel.get_absolute_url" class="headerlink" title="Permanent link">&para;</a></h3>
4846
+
4847
+
4848
+ <div class="doc doc-contents ">
4849
+
4850
+ <p>Return the canonical URL for this object in either the UI or the REST API.</p>
4851
+
4852
+ <details class="quote">
4853
+ <summary>Source code in <code>nautobot/core/models/__init__.py</code></summary>
4854
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-42">42</a></span>
4855
+ <span class="normal"><a href="#__codelineno-0-43">43</a></span>
4856
+ <span class="normal"><a href="#__codelineno-0-44">44</a></span>
4857
+ <span class="normal"><a href="#__codelineno-0-45">45</a></span>
4858
+ <span class="normal"><a href="#__codelineno-0-46">46</a></span>
4859
+ <span class="normal"><a href="#__codelineno-0-47">47</a></span>
4860
+ <span class="normal"><a href="#__codelineno-0-48">48</a></span>
4861
+ <span class="normal"><a href="#__codelineno-0-49">49</a></span>
4862
+ <span class="normal"><a href="#__codelineno-0-50">50</a></span>
4863
+ <span class="normal"><a href="#__codelineno-0-51">51</a></span>
4864
+ <span class="normal"><a href="#__codelineno-0-52">52</a></span>
4865
+ <span class="normal"><a href="#__codelineno-0-53">53</a></span>
4866
+ <span class="normal"><a href="#__codelineno-0-54">54</a></span>
4867
+ <span class="normal"><a href="#__codelineno-0-55">55</a></span>
4868
+ <span class="normal"><a href="#__codelineno-0-56">56</a></span>
4869
+ <span class="normal"><a href="#__codelineno-0-57">57</a></span>
4870
+ <span class="normal"><a href="#__codelineno-0-58">58</a></span>
4871
+ <span class="normal"><a href="#__codelineno-0-59">59</a></span>
4872
+ <span class="normal"><a href="#__codelineno-0-60">60</a></span>
4873
+ <span class="normal"><a href="#__codelineno-0-61">61</a></span>
4874
+ <span class="normal"><a href="#__codelineno-0-62">62</a></span>
4875
+ <span class="normal"><a href="#__codelineno-0-63">63</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-42" name="__codelineno-0-42"></a><span class="k">def</span> <span class="nf">get_absolute_url</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">api</span><span class="o">=</span><span class="kc">False</span><span class="p">):</span>
4876
+ <a id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4877
+ <a id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="sd"> Return the canonical URL for this object in either the UI or the REST API.</span>
4878
+ <a id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="sd"> &quot;&quot;&quot;</span>
4879
+ <a id="__codelineno-0-46" name="__codelineno-0-46"></a>
4880
+ <a id="__codelineno-0-47" name="__codelineno-0-47"></a> <span class="c1"># Iterate the pk-like fields and try to get a URL, or return None.</span>
4881
+ <a id="__codelineno-0-48" name="__codelineno-0-48"></a> <span class="n">fields</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;pk&quot;</span><span class="p">,</span> <span class="s2">&quot;slug&quot;</span><span class="p">]</span> <span class="c1"># TODO: Eventually all PKs</span>
4882
+ <a id="__codelineno-0-49" name="__codelineno-0-49"></a> <span class="n">actions</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;retrieve&quot;</span><span class="p">,</span> <span class="s2">&quot;detail&quot;</span><span class="p">,</span> <span class="s2">&quot;&quot;</span><span class="p">]</span> <span class="c1"># TODO: Eventually all retrieve</span>
4883
+ <a id="__codelineno-0-50" name="__codelineno-0-50"></a>
4884
+ <a id="__codelineno-0-51" name="__codelineno-0-51"></a> <span class="k">for</span> <span class="n">field</span> <span class="ow">in</span> <span class="n">fields</span><span class="p">:</span>
4885
+ <a id="__codelineno-0-52" name="__codelineno-0-52"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
4886
+ <a id="__codelineno-0-53" name="__codelineno-0-53"></a> <span class="k">continue</span>
4887
+ <a id="__codelineno-0-54" name="__codelineno-0-54"></a>
4888
+ <a id="__codelineno-0-55" name="__codelineno-0-55"></a> <span class="k">for</span> <span class="n">action</span> <span class="ow">in</span> <span class="n">actions</span><span class="p">:</span>
4889
+ <a id="__codelineno-0-56" name="__codelineno-0-56"></a> <span class="n">route</span> <span class="o">=</span> <span class="n">get_route_for_model</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">action</span><span class="p">,</span> <span class="n">api</span><span class="o">=</span><span class="n">api</span><span class="p">)</span>
4890
+ <a id="__codelineno-0-57" name="__codelineno-0-57"></a>
4891
+ <a id="__codelineno-0-58" name="__codelineno-0-58"></a> <span class="k">try</span><span class="p">:</span>
4892
+ <a id="__codelineno-0-59" name="__codelineno-0-59"></a> <span class="k">return</span> <span class="n">reverse</span><span class="p">(</span><span class="n">route</span><span class="p">,</span> <span class="n">kwargs</span><span class="o">=</span><span class="p">{</span><span class="n">field</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">)})</span>
4893
+ <a id="__codelineno-0-60" name="__codelineno-0-60"></a> <span class="k">except</span> <span class="n">NoReverseMatch</span><span class="p">:</span>
4894
+ <a id="__codelineno-0-61" name="__codelineno-0-61"></a> <span class="k">continue</span>
4895
+ <a id="__codelineno-0-62" name="__codelineno-0-62"></a>
4896
+ <a id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="k">return</span> <span class="ne">AttributeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Cannot find a URL for </span><span class="si">{</span><span class="bp">self</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">app_label</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model_name</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span>
4897
+ </code></pre></div></td></tr></table></div>
4898
+ </details>
4899
+ </div>
4900
+
4901
+ </div>
4902
+
4903
+ <div class="doc doc-object doc-function">
4904
+
4905
+
4906
+
3556
4907
  <h3 id="nautobot.core.models.BaseModel.natural_key" class="doc doc-heading">
3557
4908
  <code class="highlight language-python"><span class="n">natural_key</span><span class="p">()</span></code>
3558
4909
 
@@ -3569,43 +4920,43 @@ can be used for the same purpose in most cases.</p>
3569
4920
 
3570
4921
  <details class="quote">
3571
4922
  <summary>Source code in <code>nautobot/core/models/__init__.py</code></summary>
3572
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-57">57</a></span>
3573
- <span class="normal"><a href="#__codelineno-0-58">58</a></span>
3574
- <span class="normal"><a href="#__codelineno-0-59">59</a></span>
3575
- <span class="normal"><a href="#__codelineno-0-60">60</a></span>
3576
- <span class="normal"><a href="#__codelineno-0-61">61</a></span>
3577
- <span class="normal"><a href="#__codelineno-0-62">62</a></span>
3578
- <span class="normal"><a href="#__codelineno-0-63">63</a></span>
3579
- <span class="normal"><a href="#__codelineno-0-64">64</a></span>
3580
- <span class="normal"><a href="#__codelineno-0-65">65</a></span>
3581
- <span class="normal"><a href="#__codelineno-0-66">66</a></span>
3582
- <span class="normal"><a href="#__codelineno-0-67">67</a></span>
3583
- <span class="normal"><a href="#__codelineno-0-68">68</a></span>
3584
- <span class="normal"><a href="#__codelineno-0-69">69</a></span>
3585
- <span class="normal"><a href="#__codelineno-0-70">70</a></span>
3586
- <span class="normal"><a href="#__codelineno-0-71">71</a></span>
3587
- <span class="normal"><a href="#__codelineno-0-72">72</a></span>
3588
- <span class="normal"><a href="#__codelineno-0-73">73</a></span>
3589
- <span class="normal"><a href="#__codelineno-0-74">74</a></span>
3590
- <span class="normal"><a href="#__codelineno-0-75">75</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="k">def</span> <span class="nf">natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">:</span>
3591
- <a id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3592
- <a id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="sd"> Smarter default implementation of natural key construction.</span>
3593
- <a id="__codelineno-0-60" name="__codelineno-0-60"></a>
3594
- <a id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="sd"> 1. Handles nullable foreign keys (https://github.com/wq/django-natural-keys/issues/18)</span>
3595
- <a id="__codelineno-0-62" name="__codelineno-0-62"></a><span class="sd"> 2. Handles variadic natural-keys (e.g. Location model - [name, parent__name, parent__parent__name, ...].)</span>
3596
- <a id="__codelineno-0-63" name="__codelineno-0-63"></a><span class="sd"> &quot;&quot;&quot;</span>
3597
- <a id="__codelineno-0-64" name="__codelineno-0-64"></a> <span class="n">vals</span> <span class="o">=</span> <span class="p">[]</span>
3598
- <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="k">for</span> <span class="n">lookups</span> <span class="ow">in</span> <span class="p">[</span><span class="n">lookup</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;__&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">natural_key_field_lookups</span><span class="p">]:</span>
3599
- <a id="__codelineno-0-66" name="__codelineno-0-66"></a> <span class="n">val</span> <span class="o">=</span> <span class="bp">self</span>
3600
- <a id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="n">lookups</span><span class="p">:</span>
3601
- <a id="__codelineno-0-68" name="__codelineno-0-68"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">lookup</span><span class="p">)</span>
3602
- <a id="__codelineno-0-69" name="__codelineno-0-69"></a> <span class="k">if</span> <span class="n">val</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3603
- <a id="__codelineno-0-70" name="__codelineno-0-70"></a> <span class="k">break</span>
3604
- <a id="__codelineno-0-71" name="__codelineno-0-71"></a> <span class="n">vals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
3605
- <a id="__codelineno-0-72" name="__codelineno-0-72"></a> <span class="c1"># Strip trailing Nones from vals</span>
3606
- <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="k">while</span> <span class="n">vals</span> <span class="ow">and</span> <span class="n">vals</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3607
- <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="n">vals</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
3608
- <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="k">return</span> <span class="n">vals</span>
4923
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-82"> 82</a></span>
4924
+ <span class="normal"><a href="#__codelineno-0-83"> 83</a></span>
4925
+ <span class="normal"><a href="#__codelineno-0-84"> 84</a></span>
4926
+ <span class="normal"><a href="#__codelineno-0-85"> 85</a></span>
4927
+ <span class="normal"><a href="#__codelineno-0-86"> 86</a></span>
4928
+ <span class="normal"><a href="#__codelineno-0-87"> 87</a></span>
4929
+ <span class="normal"><a href="#__codelineno-0-88"> 88</a></span>
4930
+ <span class="normal"><a href="#__codelineno-0-89"> 89</a></span>
4931
+ <span class="normal"><a href="#__codelineno-0-90"> 90</a></span>
4932
+ <span class="normal"><a href="#__codelineno-0-91"> 91</a></span>
4933
+ <span class="normal"><a href="#__codelineno-0-92"> 92</a></span>
4934
+ <span class="normal"><a href="#__codelineno-0-93"> 93</a></span>
4935
+ <span class="normal"><a href="#__codelineno-0-94"> 94</a></span>
4936
+ <span class="normal"><a href="#__codelineno-0-95"> 95</a></span>
4937
+ <span class="normal"><a href="#__codelineno-0-96"> 96</a></span>
4938
+ <span class="normal"><a href="#__codelineno-0-97"> 97</a></span>
4939
+ <span class="normal"><a href="#__codelineno-0-98"> 98</a></span>
4940
+ <span class="normal"><a href="#__codelineno-0-99"> 99</a></span>
4941
+ <span class="normal"><a href="#__codelineno-0-100">100</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-82" name="__codelineno-0-82"></a><span class="k">def</span> <span class="nf">natural_key</span><span class="p">(</span><span class="bp">self</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">list</span><span class="p">:</span>
4942
+ <a id="__codelineno-0-83" name="__codelineno-0-83"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4943
+ <a id="__codelineno-0-84" name="__codelineno-0-84"></a><span class="sd"> Smarter default implementation of natural key construction.</span>
4944
+ <a id="__codelineno-0-85" name="__codelineno-0-85"></a>
4945
+ <a id="__codelineno-0-86" name="__codelineno-0-86"></a><span class="sd"> 1. Handles nullable foreign keys (https://github.com/wq/django-natural-keys/issues/18)</span>
4946
+ <a id="__codelineno-0-87" name="__codelineno-0-87"></a><span class="sd"> 2. Handles variadic natural-keys (e.g. Location model - [name, parent__name, parent__parent__name, ...].)</span>
4947
+ <a id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="sd"> &quot;&quot;&quot;</span>
4948
+ <a id="__codelineno-0-89" name="__codelineno-0-89"></a> <span class="n">vals</span> <span class="o">=</span> <span class="p">[]</span>
4949
+ <a id="__codelineno-0-90" name="__codelineno-0-90"></a> <span class="k">for</span> <span class="n">lookups</span> <span class="ow">in</span> <span class="p">[</span><span class="n">lookup</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;__&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">natural_key_field_lookups</span><span class="p">]:</span>
4950
+ <a id="__codelineno-0-91" name="__codelineno-0-91"></a> <span class="n">val</span> <span class="o">=</span> <span class="bp">self</span>
4951
+ <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="k">for</span> <span class="n">lookup</span> <span class="ow">in</span> <span class="n">lookups</span><span class="p">:</span>
4952
+ <a id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">val</span><span class="p">,</span> <span class="n">lookup</span><span class="p">)</span>
4953
+ <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="k">if</span> <span class="n">val</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4954
+ <a id="__codelineno-0-95" name="__codelineno-0-95"></a> <span class="k">break</span>
4955
+ <a id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="n">vals</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">val</span><span class="p">)</span>
4956
+ <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="c1"># Strip trailing Nones from vals</span>
4957
+ <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="k">while</span> <span class="n">vals</span> <span class="ow">and</span> <span class="n">vals</span><span class="p">[</span><span class="o">-</span><span class="mi">1</span><span class="p">]</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4958
+ <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="n">vals</span><span class="o">.</span><span class="n">pop</span><span class="p">()</span>
4959
+ <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="k">return</span> <span class="n">vals</span>
3609
4960
  </code></pre></div></td></tr></table></div>
3610
4961
  </details>
3611
4962
  </div>
@@ -3633,45 +4984,45 @@ can be used for the same purpose in most cases.</p>
3633
4984
 
3634
4985
  <details class="quote">
3635
4986
  <summary>Source code in <code>nautobot/core/models/__init__.py</code></summary>
3636
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-163">163</a></span>
3637
- <span class="normal"><a href="#__codelineno-0-164">164</a></span>
3638
- <span class="normal"><a href="#__codelineno-0-165">165</a></span>
3639
- <span class="normal"><a href="#__codelineno-0-166">166</a></span>
3640
- <span class="normal"><a href="#__codelineno-0-167">167</a></span>
3641
- <span class="normal"><a href="#__codelineno-0-168">168</a></span>
3642
- <span class="normal"><a href="#__codelineno-0-169">169</a></span>
3643
- <span class="normal"><a href="#__codelineno-0-170">170</a></span>
3644
- <span class="normal"><a href="#__codelineno-0-171">171</a></span>
3645
- <span class="normal"><a href="#__codelineno-0-172">172</a></span>
3646
- <span class="normal"><a href="#__codelineno-0-173">173</a></span>
3647
- <span class="normal"><a href="#__codelineno-0-174">174</a></span>
3648
- <span class="normal"><a href="#__codelineno-0-175">175</a></span>
3649
- <span class="normal"><a href="#__codelineno-0-176">176</a></span>
3650
- <span class="normal"><a href="#__codelineno-0-177">177</a></span>
3651
- <span class="normal"><a href="#__codelineno-0-178">178</a></span>
3652
- <span class="normal"><a href="#__codelineno-0-179">179</a></span>
3653
- <span class="normal"><a href="#__codelineno-0-180">180</a></span>
3654
- <span class="normal"><a href="#__codelineno-0-181">181</a></span>
3655
- <span class="normal"><a href="#__codelineno-0-182">182</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-163" name="__codelineno-0-163"></a><span class="nd">@classmethod</span>
3656
- <a id="__codelineno-0-164" name="__codelineno-0-164"></a><span class="k">def</span> <span class="nf">natural_key_args_to_kwargs</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
3657
- <a id="__codelineno-0-165" name="__codelineno-0-165"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3658
- <a id="__codelineno-0-166" name="__codelineno-0-166"></a><span class="sd"> Helper function to map a list of natural key field values to actual kwargs suitable for lookup and filtering.</span>
3659
- <a id="__codelineno-0-167" name="__codelineno-0-167"></a>
3660
- <a id="__codelineno-0-168" name="__codelineno-0-168"></a><span class="sd"> Based on `django-natural-keys` `NaturalKeyQuerySet.natural_key_kwargs()` method.</span>
3661
- <a id="__codelineno-0-169" name="__codelineno-0-169"></a><span class="sd"> &quot;&quot;&quot;</span>
3662
- <a id="__codelineno-0-170" name="__codelineno-0-170"></a> <span class="n">args</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
3663
- <a id="__codelineno-0-171" name="__codelineno-0-171"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
3664
- <a id="__codelineno-0-172" name="__codelineno-0-172"></a> <span class="c1"># Because `natural_key` strips trailing `None` from the natural key to handle the variadic-natural-key case,</span>
3665
- <a id="__codelineno-0-173" name="__codelineno-0-173"></a> <span class="c1"># we may need to add trailing `None` back on to make the number of args match back up.</span>
3666
- <a id="__codelineno-0-174" name="__codelineno-0-174"></a> <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
3667
- <a id="__codelineno-0-175" name="__codelineno-0-175"></a> <span class="n">args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
3668
- <a id="__codelineno-0-176" name="__codelineno-0-176"></a> <span class="c1"># However, if we have *too many* args, that&#39;s just incorrect usage:</span>
3669
- <a id="__codelineno-0-177" name="__codelineno-0-177"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
3670
- <a id="__codelineno-0-178" name="__codelineno-0-178"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
3671
- <a id="__codelineno-0-179" name="__codelineno-0-179"></a> <span class="sa">f</span><span class="s2">&quot;Wrong number of natural-key args for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_args_to_kwargs() -- &quot;</span>
3672
- <a id="__codelineno-0-180" name="__codelineno-0-180"></a> <span class="sa">f</span><span class="s2">&quot;expected no more than </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">)</span><span class="si">}</span><span class="s2"> but got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">.&quot;</span>
3673
- <a id="__codelineno-0-181" name="__codelineno-0-181"></a> <span class="p">)</span>
3674
- <a id="__codelineno-0-182" name="__codelineno-0-182"></a> <span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">,</span> <span class="n">args</span><span class="p">))</span>
4987
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-188">188</a></span>
4988
+ <span class="normal"><a href="#__codelineno-0-189">189</a></span>
4989
+ <span class="normal"><a href="#__codelineno-0-190">190</a></span>
4990
+ <span class="normal"><a href="#__codelineno-0-191">191</a></span>
4991
+ <span class="normal"><a href="#__codelineno-0-192">192</a></span>
4992
+ <span class="normal"><a href="#__codelineno-0-193">193</a></span>
4993
+ <span class="normal"><a href="#__codelineno-0-194">194</a></span>
4994
+ <span class="normal"><a href="#__codelineno-0-195">195</a></span>
4995
+ <span class="normal"><a href="#__codelineno-0-196">196</a></span>
4996
+ <span class="normal"><a href="#__codelineno-0-197">197</a></span>
4997
+ <span class="normal"><a href="#__codelineno-0-198">198</a></span>
4998
+ <span class="normal"><a href="#__codelineno-0-199">199</a></span>
4999
+ <span class="normal"><a href="#__codelineno-0-200">200</a></span>
5000
+ <span class="normal"><a href="#__codelineno-0-201">201</a></span>
5001
+ <span class="normal"><a href="#__codelineno-0-202">202</a></span>
5002
+ <span class="normal"><a href="#__codelineno-0-203">203</a></span>
5003
+ <span class="normal"><a href="#__codelineno-0-204">204</a></span>
5004
+ <span class="normal"><a href="#__codelineno-0-205">205</a></span>
5005
+ <span class="normal"><a href="#__codelineno-0-206">206</a></span>
5006
+ <span class="normal"><a href="#__codelineno-0-207">207</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-188" name="__codelineno-0-188"></a><span class="nd">@classmethod</span>
5007
+ <a id="__codelineno-0-189" name="__codelineno-0-189"></a><span class="k">def</span> <span class="nf">natural_key_args_to_kwargs</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">args</span><span class="p">):</span>
5008
+ <a id="__codelineno-0-190" name="__codelineno-0-190"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5009
+ <a id="__codelineno-0-191" name="__codelineno-0-191"></a><span class="sd"> Helper function to map a list of natural key field values to actual kwargs suitable for lookup and filtering.</span>
5010
+ <a id="__codelineno-0-192" name="__codelineno-0-192"></a>
5011
+ <a id="__codelineno-0-193" name="__codelineno-0-193"></a><span class="sd"> Based on `django-natural-keys` `NaturalKeyQuerySet.natural_key_kwargs()` method.</span>
5012
+ <a id="__codelineno-0-194" name="__codelineno-0-194"></a><span class="sd"> &quot;&quot;&quot;</span>
5013
+ <a id="__codelineno-0-195" name="__codelineno-0-195"></a> <span class="n">args</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">args</span><span class="p">)</span>
5014
+ <a id="__codelineno-0-196" name="__codelineno-0-196"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
5015
+ <a id="__codelineno-0-197" name="__codelineno-0-197"></a> <span class="c1"># Because `natural_key` strips trailing `None` from the natural key to handle the variadic-natural-key case,</span>
5016
+ <a id="__codelineno-0-198" name="__codelineno-0-198"></a> <span class="c1"># we may need to add trailing `None` back on to make the number of args match back up.</span>
5017
+ <a id="__codelineno-0-199" name="__codelineno-0-199"></a> <span class="k">while</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&lt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
5018
+ <a id="__codelineno-0-200" name="__codelineno-0-200"></a> <span class="n">args</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="kc">None</span><span class="p">)</span>
5019
+ <a id="__codelineno-0-201" name="__codelineno-0-201"></a> <span class="c1"># However, if we have *too many* args, that&#39;s just incorrect usage:</span>
5020
+ <a id="__codelineno-0-202" name="__codelineno-0-202"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span> <span class="o">&gt;</span> <span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">):</span>
5021
+ <a id="__codelineno-0-203" name="__codelineno-0-203"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span>
5022
+ <a id="__codelineno-0-204" name="__codelineno-0-204"></a> <span class="sa">f</span><span class="s2">&quot;Wrong number of natural-key args for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_args_to_kwargs() -- &quot;</span>
5023
+ <a id="__codelineno-0-205" name="__codelineno-0-205"></a> <span class="sa">f</span><span class="s2">&quot;expected no more than </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">)</span><span class="si">}</span><span class="s2"> but got </span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">args</span><span class="p">)</span><span class="si">}</span><span class="s2">.&quot;</span>
5024
+ <a id="__codelineno-0-206" name="__codelineno-0-206"></a> <span class="p">)</span>
5025
+ <a id="__codelineno-0-207" name="__codelineno-0-207"></a> <span class="k">return</span> <span class="nb">dict</span><span class="p">(</span><span class="nb">zip</span><span class="p">(</span><span class="n">natural_key_field_lookups</span><span class="p">,</span> <span class="n">args</span><span class="p">))</span>
3675
5026
  </code></pre></div></td></tr></table></div>
3676
5027
  </details>
3677
5028
  </div>
@@ -3700,32 +5051,7 @@ but instead explicitly discounts the <code>id</code> field (only) as a candidate
3700
5051
 
3701
5052
  <details class="quote">
3702
5053
  <summary>Source code in <code>nautobot/core/models/__init__.py</code></summary>
3703
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-86"> 86</a></span>
3704
- <span class="normal"><a href="#__codelineno-0-87"> 87</a></span>
3705
- <span class="normal"><a href="#__codelineno-0-88"> 88</a></span>
3706
- <span class="normal"><a href="#__codelineno-0-89"> 89</a></span>
3707
- <span class="normal"><a href="#__codelineno-0-90"> 90</a></span>
3708
- <span class="normal"><a href="#__codelineno-0-91"> 91</a></span>
3709
- <span class="normal"><a href="#__codelineno-0-92"> 92</a></span>
3710
- <span class="normal"><a href="#__codelineno-0-93"> 93</a></span>
3711
- <span class="normal"><a href="#__codelineno-0-94"> 94</a></span>
3712
- <span class="normal"><a href="#__codelineno-0-95"> 95</a></span>
3713
- <span class="normal"><a href="#__codelineno-0-96"> 96</a></span>
3714
- <span class="normal"><a href="#__codelineno-0-97"> 97</a></span>
3715
- <span class="normal"><a href="#__codelineno-0-98"> 98</a></span>
3716
- <span class="normal"><a href="#__codelineno-0-99"> 99</a></span>
3717
- <span class="normal"><a href="#__codelineno-0-100">100</a></span>
3718
- <span class="normal"><a href="#__codelineno-0-101">101</a></span>
3719
- <span class="normal"><a href="#__codelineno-0-102">102</a></span>
3720
- <span class="normal"><a href="#__codelineno-0-103">103</a></span>
3721
- <span class="normal"><a href="#__codelineno-0-104">104</a></span>
3722
- <span class="normal"><a href="#__codelineno-0-105">105</a></span>
3723
- <span class="normal"><a href="#__codelineno-0-106">106</a></span>
3724
- <span class="normal"><a href="#__codelineno-0-107">107</a></span>
3725
- <span class="normal"><a href="#__codelineno-0-108">108</a></span>
3726
- <span class="normal"><a href="#__codelineno-0-109">109</a></span>
3727
- <span class="normal"><a href="#__codelineno-0-110">110</a></span>
3728
- <span class="normal"><a href="#__codelineno-0-111">111</a></span>
5054
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-111">111</a></span>
3729
5055
  <span class="normal"><a href="#__codelineno-0-112">112</a></span>
3730
5056
  <span class="normal"><a href="#__codelineno-0-113">113</a></span>
3731
5057
  <span class="normal"><a href="#__codelineno-0-114">114</a></span>
@@ -3775,82 +5101,107 @@ but instead explicitly discounts the <code>id</code> field (only) as a candidate
3775
5101
  <span class="normal"><a href="#__codelineno-0-158">158</a></span>
3776
5102
  <span class="normal"><a href="#__codelineno-0-159">159</a></span>
3777
5103
  <span class="normal"><a href="#__codelineno-0-160">160</a></span>
3778
- <span class="normal"><a href="#__codelineno-0-161">161</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-86" name="__codelineno-0-86"></a><span class="nd">@classproperty</span> <span class="c1"># https://github.com/PyCQA/pylint-django/issues/240</span>
3779
- <a id="__codelineno-0-87" name="__codelineno-0-87"></a><span class="k">def</span> <span class="nf">natural_key_field_lookups</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span> <span class="c1"># pylint: disable=no-self-argument</span>
3780
- <a id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3781
- <a id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="sd"> List of lookups (possibly including nested lookups for related models) that make up this model&#39;s natural key.</span>
3782
- <a id="__codelineno-0-90" name="__codelineno-0-90"></a>
3783
- <a id="__codelineno-0-91" name="__codelineno-0-91"></a><span class="sd"> BaseModel provides a &quot;smart&quot; implementation that tries to determine this automatically,</span>
3784
- <a id="__codelineno-0-92" name="__codelineno-0-92"></a><span class="sd"> but you can also explicitly set `natural_key_field_names` on a given model subclass if desired.</span>
3785
- <a id="__codelineno-0-93" name="__codelineno-0-93"></a>
3786
- <a id="__codelineno-0-94" name="__codelineno-0-94"></a><span class="sd"> This property is based on a consolidation of `django-natural-keys` `ForeignKeyModel.get_natural_key_info()`,</span>
3787
- <a id="__codelineno-0-95" name="__codelineno-0-95"></a><span class="sd"> `ForeignKeyModel.get_natural_key_def()`, and `ForeignKeyModel.get_natural_key_fields()`.</span>
3788
- <a id="__codelineno-0-96" name="__codelineno-0-96"></a>
3789
- <a id="__codelineno-0-97" name="__codelineno-0-97"></a><span class="sd"> Unlike `get_natural_key_def()`, this doesn&#39;t auto-exclude all AutoField and BigAutoField fields,</span>
3790
- <a id="__codelineno-0-98" name="__codelineno-0-98"></a><span class="sd"> but instead explicitly discounts the `id` field (only) as a candidate.</span>
3791
- <a id="__codelineno-0-99" name="__codelineno-0-99"></a><span class="sd"> &quot;&quot;&quot;</span>
3792
- <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="c1"># First, figure out which local fields comprise the natural key:</span>
3793
- <a id="__codelineno-0-101" name="__codelineno-0-101"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">[]</span>
3794
- <a id="__codelineno-0-102" name="__codelineno-0-102"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_names&quot;</span><span class="p">):</span>
3795
- <a id="__codelineno-0-103" name="__codelineno-0-103"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_names</span>
3796
- <a id="__codelineno-0-104" name="__codelineno-0-104"></a> <span class="k">else</span><span class="p">:</span>
3797
- <a id="__codelineno-0-105" name="__codelineno-0-105"></a> <span class="c1"># Does this model have any new-style UniqueConstraints? If so, pick the first one</span>
3798
- <a id="__codelineno-0-106" name="__codelineno-0-106"></a> <span class="k">for</span> <span class="n">constraint</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">constraints</span><span class="p">:</span>
3799
- <a id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">constraint</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">UniqueConstraint</span><span class="p">):</span>
3800
- <a id="__codelineno-0-108" name="__codelineno-0-108"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="n">constraint</span><span class="o">.</span><span class="n">fields</span>
3801
- <a id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="k">break</span>
3802
- <a id="__codelineno-0-110" name="__codelineno-0-110"></a> <span class="k">else</span><span class="p">:</span>
3803
- <a id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="c1"># Else, does this model have any old-style unique_together? If so, pick the first one.</span>
3804
- <a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">:</span>
3805
- <a id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
3806
- <a id="__codelineno-0-114" name="__codelineno-0-114"></a> <span class="k">else</span><span class="p">:</span>
3807
- <a id="__codelineno-0-115" name="__codelineno-0-115"></a> <span class="c1"># Else, do we have any individual unique=True fields? If so, pick the first one.</span>
3808
- <a id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="n">unique_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">field</span> <span class="k">for</span> <span class="n">field</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">fields</span> <span class="k">if</span> <span class="n">field</span><span class="o">.</span><span class="n">unique</span> <span class="ow">and</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span> <span class="o">!=</span> <span class="s2">&quot;id&quot;</span><span class="p">]</span>
3809
- <a id="__codelineno-0-117" name="__codelineno-0-117"></a> <span class="k">if</span> <span class="n">unique_fields</span><span class="p">:</span>
3810
- <a id="__codelineno-0-118" name="__codelineno-0-118"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">(</span><span class="n">unique_fields</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">name</span><span class="p">,)</span>
3811
- <a id="__codelineno-0-119" name="__codelineno-0-119"></a>
3812
- <a id="__codelineno-0-120" name="__codelineno-0-120"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
3813
- <a id="__codelineno-0-121" name="__codelineno-0-121"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3814
- <a id="__codelineno-0-122" name="__codelineno-0-122"></a> <span class="sa">f</span><span class="s2">&quot;Unable to identify an intrinsic natural-key definition for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">. &quot;</span>
3815
- <a id="__codelineno-0-123" name="__codelineno-0-123"></a> <span class="s2">&quot;If there isn&#39;t at least one UniqueConstraint, unique_together, or field with unique=True, &quot;</span>
3816
- <a id="__codelineno-0-124" name="__codelineno-0-124"></a> <span class="s2">&quot;you probably need to explicitly declare the &#39;natural_key_field_names&#39; for this model, &quot;</span>
3817
- <a id="__codelineno-0-125" name="__codelineno-0-125"></a> <span class="s2">&quot;or potentially override the default &#39;natural_key_field_lookups&#39; implementation for this model.&quot;</span>
3818
- <a id="__codelineno-0-126" name="__codelineno-0-126"></a> <span class="p">)</span>
3819
- <a id="__codelineno-0-127" name="__codelineno-0-127"></a>
3820
- <a id="__codelineno-0-128" name="__codelineno-0-128"></a> <span class="c1"># Next, for any natural key fields that have related models, get the natural key for the related model if known</span>
3821
- <a id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[]</span>
3822
- <a id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
3823
- <a id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="n">field</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">get_field</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
3824
- <a id="__codelineno-0-132" name="__codelineno-0-132"></a> <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;remote_field&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3825
- <a id="__codelineno-0-133" name="__codelineno-0-133"></a> <span class="c1"># Not a related field, so the field name is the field lookup</span>
3826
- <a id="__codelineno-0-134" name="__codelineno-0-134"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
3827
- <a id="__codelineno-0-135" name="__codelineno-0-135"></a> <span class="k">continue</span>
3828
- <a id="__codelineno-0-136" name="__codelineno-0-136"></a>
3829
- <a id="__codelineno-0-137" name="__codelineno-0-137"></a> <span class="n">related_model</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">remote_field</span><span class="o">.</span><span class="n">model</span>
3830
- <a id="__codelineno-0-138" name="__codelineno-0-138"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="kc">None</span>
3831
- <a id="__codelineno-0-139" name="__codelineno-0-139"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">related_model</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_lookups&quot;</span><span class="p">):</span>
3832
- <a id="__codelineno-0-140" name="__codelineno-0-140"></a> <span class="c1"># TODO: generic handling for self-referential case, as seen in Location</span>
3833
- <a id="__codelineno-0-141" name="__codelineno-0-141"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="n">related_model</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
3834
- <a id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="k">else</span><span class="p">:</span>
3835
- <a id="__codelineno-0-143" name="__codelineno-0-143"></a> <span class="c1"># Related model isn&#39;t a Nautobot model and so doesn&#39;t have a `natural_key_field_lookups`.</span>
3836
- <a id="__codelineno-0-144" name="__codelineno-0-144"></a> <span class="c1"># The common case we&#39;ve encountered so far is the contenttypes.ContentType model:</span>
3837
- <a id="__codelineno-0-145" name="__codelineno-0-145"></a> <span class="k">if</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">app_label</span> <span class="o">==</span> <span class="s2">&quot;contenttypes&quot;</span> <span class="ow">and</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model_name</span> <span class="o">==</span> <span class="s2">&quot;contenttype&quot;</span><span class="p">:</span>
3838
- <a id="__codelineno-0-146" name="__codelineno-0-146"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;app_label&quot;</span><span class="p">,</span> <span class="s2">&quot;model&quot;</span><span class="p">]</span>
3839
- <a id="__codelineno-0-147" name="__codelineno-0-147"></a> <span class="c1"># Additional special cases can be added here</span>
3840
- <a id="__codelineno-0-148" name="__codelineno-0-148"></a>
3841
- <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
3842
- <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3843
- <a id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="sa">f</span><span class="s2">&quot;Unable to determine the related natural-key fields for </span><span class="si">{</span><span class="n">related_model</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> &quot;</span>
3844
- <a id="__codelineno-0-152" name="__codelineno-0-152"></a> <span class="sa">f</span><span class="s2">&quot;(as referenced from </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">). If the related model is a non-Nautobot &quot;</span>
3845
- <a id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="s2">&quot;model (such as ContentType) then it may be appropriate to add special-case handling for this &quot;</span>
3846
- <a id="__codelineno-0-154" name="__codelineno-0-154"></a> <span class="s2">&quot;model in BaseModel.natural_key_field_lookups; alternately you may be able to solve this for &quot;</span>
3847
- <a id="__codelineno-0-155" name="__codelineno-0-155"></a> <span class="sa">f</span><span class="s2">&quot;a single special case by explicitly defining </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_field_lookups.&quot;</span>
3848
- <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="p">)</span>
3849
- <a id="__codelineno-0-157" name="__codelineno-0-157"></a>
3850
- <a id="__codelineno-0-158" name="__codelineno-0-158"></a> <span class="k">for</span> <span class="n">field_lookup</span> <span class="ow">in</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
3851
- <a id="__codelineno-0-159" name="__codelineno-0-159"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">field_lookup</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
3852
- <a id="__codelineno-0-160" name="__codelineno-0-160"></a>
3853
- <a id="__codelineno-0-161" name="__codelineno-0-161"></a> <span class="k">return</span> <span class="n">natural_key_field_lookups</span>
5104
+ <span class="normal"><a href="#__codelineno-0-161">161</a></span>
5105
+ <span class="normal"><a href="#__codelineno-0-162">162</a></span>
5106
+ <span class="normal"><a href="#__codelineno-0-163">163</a></span>
5107
+ <span class="normal"><a href="#__codelineno-0-164">164</a></span>
5108
+ <span class="normal"><a href="#__codelineno-0-165">165</a></span>
5109
+ <span class="normal"><a href="#__codelineno-0-166">166</a></span>
5110
+ <span class="normal"><a href="#__codelineno-0-167">167</a></span>
5111
+ <span class="normal"><a href="#__codelineno-0-168">168</a></span>
5112
+ <span class="normal"><a href="#__codelineno-0-169">169</a></span>
5113
+ <span class="normal"><a href="#__codelineno-0-170">170</a></span>
5114
+ <span class="normal"><a href="#__codelineno-0-171">171</a></span>
5115
+ <span class="normal"><a href="#__codelineno-0-172">172</a></span>
5116
+ <span class="normal"><a href="#__codelineno-0-173">173</a></span>
5117
+ <span class="normal"><a href="#__codelineno-0-174">174</a></span>
5118
+ <span class="normal"><a href="#__codelineno-0-175">175</a></span>
5119
+ <span class="normal"><a href="#__codelineno-0-176">176</a></span>
5120
+ <span class="normal"><a href="#__codelineno-0-177">177</a></span>
5121
+ <span class="normal"><a href="#__codelineno-0-178">178</a></span>
5122
+ <span class="normal"><a href="#__codelineno-0-179">179</a></span>
5123
+ <span class="normal"><a href="#__codelineno-0-180">180</a></span>
5124
+ <span class="normal"><a href="#__codelineno-0-181">181</a></span>
5125
+ <span class="normal"><a href="#__codelineno-0-182">182</a></span>
5126
+ <span class="normal"><a href="#__codelineno-0-183">183</a></span>
5127
+ <span class="normal"><a href="#__codelineno-0-184">184</a></span>
5128
+ <span class="normal"><a href="#__codelineno-0-185">185</a></span>
5129
+ <span class="normal"><a href="#__codelineno-0-186">186</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-111" name="__codelineno-0-111"></a><span class="nd">@classproperty</span> <span class="c1"># https://github.com/PyCQA/pylint-django/issues/240</span>
5130
+ <a id="__codelineno-0-112" name="__codelineno-0-112"></a><span class="k">def</span> <span class="nf">natural_key_field_lookups</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span> <span class="c1"># pylint: disable=no-self-argument</span>
5131
+ <a id="__codelineno-0-113" name="__codelineno-0-113"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5132
+ <a id="__codelineno-0-114" name="__codelineno-0-114"></a><span class="sd"> List of lookups (possibly including nested lookups for related models) that make up this model&#39;s natural key.</span>
5133
+ <a id="__codelineno-0-115" name="__codelineno-0-115"></a>
5134
+ <a id="__codelineno-0-116" name="__codelineno-0-116"></a><span class="sd"> BaseModel provides a &quot;smart&quot; implementation that tries to determine this automatically,</span>
5135
+ <a id="__codelineno-0-117" name="__codelineno-0-117"></a><span class="sd"> but you can also explicitly set `natural_key_field_names` on a given model subclass if desired.</span>
5136
+ <a id="__codelineno-0-118" name="__codelineno-0-118"></a>
5137
+ <a id="__codelineno-0-119" name="__codelineno-0-119"></a><span class="sd"> This property is based on a consolidation of `django-natural-keys` `ForeignKeyModel.get_natural_key_info()`,</span>
5138
+ <a id="__codelineno-0-120" name="__codelineno-0-120"></a><span class="sd"> `ForeignKeyModel.get_natural_key_def()`, and `ForeignKeyModel.get_natural_key_fields()`.</span>
5139
+ <a id="__codelineno-0-121" name="__codelineno-0-121"></a>
5140
+ <a id="__codelineno-0-122" name="__codelineno-0-122"></a><span class="sd"> Unlike `get_natural_key_def()`, this doesn&#39;t auto-exclude all AutoField and BigAutoField fields,</span>
5141
+ <a id="__codelineno-0-123" name="__codelineno-0-123"></a><span class="sd"> but instead explicitly discounts the `id` field (only) as a candidate.</span>
5142
+ <a id="__codelineno-0-124" name="__codelineno-0-124"></a><span class="sd"> &quot;&quot;&quot;</span>
5143
+ <a id="__codelineno-0-125" name="__codelineno-0-125"></a> <span class="c1"># First, figure out which local fields comprise the natural key:</span>
5144
+ <a id="__codelineno-0-126" name="__codelineno-0-126"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">[]</span>
5145
+ <a id="__codelineno-0-127" name="__codelineno-0-127"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_names&quot;</span><span class="p">):</span>
5146
+ <a id="__codelineno-0-128" name="__codelineno-0-128"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">natural_key_field_names</span>
5147
+ <a id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="k">else</span><span class="p">:</span>
5148
+ <a id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="c1"># Does this model have any new-style UniqueConstraints? If so, pick the first one</span>
5149
+ <a id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="k">for</span> <span class="n">constraint</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">constraints</span><span class="p">:</span>
5150
+ <a id="__codelineno-0-132" name="__codelineno-0-132"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">constraint</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">UniqueConstraint</span><span class="p">):</span>
5151
+ <a id="__codelineno-0-133" name="__codelineno-0-133"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="n">constraint</span><span class="o">.</span><span class="n">fields</span>
5152
+ <a id="__codelineno-0-134" name="__codelineno-0-134"></a> <span class="k">break</span>
5153
+ <a id="__codelineno-0-135" name="__codelineno-0-135"></a> <span class="k">else</span><span class="p">:</span>
5154
+ <a id="__codelineno-0-136" name="__codelineno-0-136"></a> <span class="c1"># Else, does this model have any old-style unique_together? If so, pick the first one.</span>
5155
+ <a id="__codelineno-0-137" name="__codelineno-0-137"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">:</span>
5156
+ <a id="__codelineno-0-138" name="__codelineno-0-138"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">unique_together</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
5157
+ <a id="__codelineno-0-139" name="__codelineno-0-139"></a> <span class="k">else</span><span class="p">:</span>
5158
+ <a id="__codelineno-0-140" name="__codelineno-0-140"></a> <span class="c1"># Else, do we have any individual unique=True fields? If so, pick the first one.</span>
5159
+ <a id="__codelineno-0-141" name="__codelineno-0-141"></a> <span class="n">unique_fields</span> <span class="o">=</span> <span class="p">[</span><span class="n">field</span> <span class="k">for</span> <span class="n">field</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">fields</span> <span class="k">if</span> <span class="n">field</span><span class="o">.</span><span class="n">unique</span> <span class="ow">and</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span> <span class="o">!=</span> <span class="s2">&quot;id&quot;</span><span class="p">]</span>
5160
+ <a id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="k">if</span> <span class="n">unique_fields</span><span class="p">:</span>
5161
+ <a id="__codelineno-0-143" name="__codelineno-0-143"></a> <span class="n">natural_key_field_names</span> <span class="o">=</span> <span class="p">(</span><span class="n">unique_fields</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span><span class="o">.</span><span class="n">name</span><span class="p">,)</span>
5162
+ <a id="__codelineno-0-144" name="__codelineno-0-144"></a>
5163
+ <a id="__codelineno-0-145" name="__codelineno-0-145"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
5164
+ <a id="__codelineno-0-146" name="__codelineno-0-146"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
5165
+ <a id="__codelineno-0-147" name="__codelineno-0-147"></a> <span class="sa">f</span><span class="s2">&quot;Unable to identify an intrinsic natural-key definition for </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">. &quot;</span>
5166
+ <a id="__codelineno-0-148" name="__codelineno-0-148"></a> <span class="s2">&quot;If there isn&#39;t at least one UniqueConstraint, unique_together, or field with unique=True, &quot;</span>
5167
+ <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="s2">&quot;you probably need to explicitly declare the &#39;natural_key_field_names&#39; for this model, &quot;</span>
5168
+ <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="s2">&quot;or potentially override the default &#39;natural_key_field_lookups&#39; implementation for this model.&quot;</span>
5169
+ <a id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="p">)</span>
5170
+ <a id="__codelineno-0-152" name="__codelineno-0-152"></a>
5171
+ <a id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="c1"># Next, for any natural key fields that have related models, get the natural key for the related model if known</span>
5172
+ <a id="__codelineno-0-154" name="__codelineno-0-154"></a> <span class="n">natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[]</span>
5173
+ <a id="__codelineno-0-155" name="__codelineno-0-155"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">natural_key_field_names</span><span class="p">:</span>
5174
+ <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="n">field</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">get_field</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5175
+ <a id="__codelineno-0-157" name="__codelineno-0-157"></a> <span class="k">if</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;remote_field&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
5176
+ <a id="__codelineno-0-158" name="__codelineno-0-158"></a> <span class="c1"># Not a related field, so the field name is the field lookup</span>
5177
+ <a id="__codelineno-0-159" name="__codelineno-0-159"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5178
+ <a id="__codelineno-0-160" name="__codelineno-0-160"></a> <span class="k">continue</span>
5179
+ <a id="__codelineno-0-161" name="__codelineno-0-161"></a>
5180
+ <a id="__codelineno-0-162" name="__codelineno-0-162"></a> <span class="n">related_model</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">remote_field</span><span class="o">.</span><span class="n">model</span>
5181
+ <a id="__codelineno-0-163" name="__codelineno-0-163"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="kc">None</span>
5182
+ <a id="__codelineno-0-164" name="__codelineno-0-164"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="n">related_model</span><span class="p">,</span> <span class="s2">&quot;natural_key_field_lookups&quot;</span><span class="p">):</span>
5183
+ <a id="__codelineno-0-165" name="__codelineno-0-165"></a> <span class="c1"># TODO: generic handling for self-referential case, as seen in Location</span>
5184
+ <a id="__codelineno-0-166" name="__codelineno-0-166"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="n">related_model</span><span class="o">.</span><span class="n">natural_key_field_lookups</span>
5185
+ <a id="__codelineno-0-167" name="__codelineno-0-167"></a> <span class="k">else</span><span class="p">:</span>
5186
+ <a id="__codelineno-0-168" name="__codelineno-0-168"></a> <span class="c1"># Related model isn&#39;t a Nautobot model and so doesn&#39;t have a `natural_key_field_lookups`.</span>
5187
+ <a id="__codelineno-0-169" name="__codelineno-0-169"></a> <span class="c1"># The common case we&#39;ve encountered so far is the contenttypes.ContentType model:</span>
5188
+ <a id="__codelineno-0-170" name="__codelineno-0-170"></a> <span class="k">if</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">app_label</span> <span class="o">==</span> <span class="s2">&quot;contenttypes&quot;</span> <span class="ow">and</span> <span class="n">related_model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model_name</span> <span class="o">==</span> <span class="s2">&quot;contenttype&quot;</span><span class="p">:</span>
5189
+ <a id="__codelineno-0-171" name="__codelineno-0-171"></a> <span class="n">related_natural_key_field_lookups</span> <span class="o">=</span> <span class="p">[</span><span class="s2">&quot;app_label&quot;</span><span class="p">,</span> <span class="s2">&quot;model&quot;</span><span class="p">]</span>
5190
+ <a id="__codelineno-0-172" name="__codelineno-0-172"></a> <span class="c1"># Additional special cases can be added here</span>
5191
+ <a id="__codelineno-0-173" name="__codelineno-0-173"></a>
5192
+ <a id="__codelineno-0-174" name="__codelineno-0-174"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
5193
+ <a id="__codelineno-0-175" name="__codelineno-0-175"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
5194
+ <a id="__codelineno-0-176" name="__codelineno-0-176"></a> <span class="sa">f</span><span class="s2">&quot;Unable to determine the related natural-key fields for </span><span class="si">{</span><span class="n">related_model</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2"> &quot;</span>
5195
+ <a id="__codelineno-0-177" name="__codelineno-0-177"></a> <span class="sa">f</span><span class="s2">&quot;(as referenced from </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">). If the related model is a non-Nautobot &quot;</span>
5196
+ <a id="__codelineno-0-178" name="__codelineno-0-178"></a> <span class="s2">&quot;model (such as ContentType) then it may be appropriate to add special-case handling for this &quot;</span>
5197
+ <a id="__codelineno-0-179" name="__codelineno-0-179"></a> <span class="s2">&quot;model in BaseModel.natural_key_field_lookups; alternately you may be able to solve this for &quot;</span>
5198
+ <a id="__codelineno-0-180" name="__codelineno-0-180"></a> <span class="sa">f</span><span class="s2">&quot;a single special case by explicitly defining </span><span class="si">{</span><span class="bp">cls</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">.natural_key_field_lookups.&quot;</span>
5199
+ <a id="__codelineno-0-181" name="__codelineno-0-181"></a> <span class="p">)</span>
5200
+ <a id="__codelineno-0-182" name="__codelineno-0-182"></a>
5201
+ <a id="__codelineno-0-183" name="__codelineno-0-183"></a> <span class="k">for</span> <span class="n">field_lookup</span> <span class="ow">in</span> <span class="n">related_natural_key_field_lookups</span><span class="p">:</span>
5202
+ <a id="__codelineno-0-184" name="__codelineno-0-184"></a> <span class="n">natural_key_field_lookups</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">field_lookup</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5203
+ <a id="__codelineno-0-185" name="__codelineno-0-185"></a>
5204
+ <a id="__codelineno-0-186" name="__codelineno-0-186"></a> <span class="k">return</span> <span class="n">natural_key_field_lookups</span>
3854
5205
  </code></pre></div></td></tr></table></div>
3855
5206
  </details>
3856
5207
  </div>
@@ -3874,36 +5225,36 @@ but instead explicitly discounts the <code>id</code> field (only) as a candidate
3874
5225
  which in effect enforces model validation prior to saving the instance, without having
3875
5226
  to manually make these calls seperately. This is a slight departure from Django norms,
3876
5227
  but is intended to offer an optional, simplified interface for performing this common
3877
- workflow. The intended use is for user defined Jobs and scripts run via the <code>nautobot-server nbshell</code>
5228
+ workflow. The intended use is for user defined Jobs run via the <code>nautobot-server nbshell</code>
3878
5229
  command.</p>
3879
5230
 
3880
5231
  <details class="quote">
3881
5232
  <summary>Source code in <code>nautobot/core/models/__init__.py</code></summary>
3882
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-43">43</a></span>
3883
- <span class="normal"><a href="#__codelineno-0-44">44</a></span>
3884
- <span class="normal"><a href="#__codelineno-0-45">45</a></span>
3885
- <span class="normal"><a href="#__codelineno-0-46">46</a></span>
3886
- <span class="normal"><a href="#__codelineno-0-47">47</a></span>
3887
- <span class="normal"><a href="#__codelineno-0-48">48</a></span>
3888
- <span class="normal"><a href="#__codelineno-0-49">49</a></span>
3889
- <span class="normal"><a href="#__codelineno-0-50">50</a></span>
3890
- <span class="normal"><a href="#__codelineno-0-51">51</a></span>
3891
- <span class="normal"><a href="#__codelineno-0-52">52</a></span>
3892
- <span class="normal"><a href="#__codelineno-0-53">53</a></span>
3893
- <span class="normal"><a href="#__codelineno-0-54">54</a></span>
3894
- <span class="normal"><a href="#__codelineno-0-55">55</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="k">def</span> <span class="nf">validated_save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3895
- <a id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3896
- <a id="__codelineno-0-45" name="__codelineno-0-45"></a><span class="sd"> Perform model validation during instance save.</span>
3897
- <a id="__codelineno-0-46" name="__codelineno-0-46"></a>
3898
- <a id="__codelineno-0-47" name="__codelineno-0-47"></a><span class="sd"> This is a convenience method that first calls `self.full_clean()` and then `self.save()`</span>
3899
- <a id="__codelineno-0-48" name="__codelineno-0-48"></a><span class="sd"> which in effect enforces model validation prior to saving the instance, without having</span>
3900
- <a id="__codelineno-0-49" name="__codelineno-0-49"></a><span class="sd"> to manually make these calls seperately. This is a slight departure from Django norms,</span>
3901
- <a id="__codelineno-0-50" name="__codelineno-0-50"></a><span class="sd"> but is intended to offer an optional, simplified interface for performing this common</span>
3902
- <a id="__codelineno-0-51" name="__codelineno-0-51"></a><span class="sd"> workflow. The intended use is for user defined Jobs and scripts run via the `nautobot-server nbshell`</span>
3903
- <a id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="sd"> command.</span>
3904
- <a id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="sd"> &quot;&quot;&quot;</span>
3905
- <a id="__codelineno-0-54" name="__codelineno-0-54"></a> <span class="bp">self</span><span class="o">.</span><span class="n">full_clean</span><span class="p">()</span>
3906
- <a id="__codelineno-0-55" name="__codelineno-0-55"></a> <span class="bp">self</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
5233
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-68">68</a></span>
5234
+ <span class="normal"><a href="#__codelineno-0-69">69</a></span>
5235
+ <span class="normal"><a href="#__codelineno-0-70">70</a></span>
5236
+ <span class="normal"><a href="#__codelineno-0-71">71</a></span>
5237
+ <span class="normal"><a href="#__codelineno-0-72">72</a></span>
5238
+ <span class="normal"><a href="#__codelineno-0-73">73</a></span>
5239
+ <span class="normal"><a href="#__codelineno-0-74">74</a></span>
5240
+ <span class="normal"><a href="#__codelineno-0-75">75</a></span>
5241
+ <span class="normal"><a href="#__codelineno-0-76">76</a></span>
5242
+ <span class="normal"><a href="#__codelineno-0-77">77</a></span>
5243
+ <span class="normal"><a href="#__codelineno-0-78">78</a></span>
5244
+ <span class="normal"><a href="#__codelineno-0-79">79</a></span>
5245
+ <span class="normal"><a href="#__codelineno-0-80">80</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-68" name="__codelineno-0-68"></a><span class="k">def</span> <span class="nf">validated_save</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5246
+ <a id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5247
+ <a id="__codelineno-0-70" name="__codelineno-0-70"></a><span class="sd"> Perform model validation during instance save.</span>
5248
+ <a id="__codelineno-0-71" name="__codelineno-0-71"></a>
5249
+ <a id="__codelineno-0-72" name="__codelineno-0-72"></a><span class="sd"> This is a convenience method that first calls `self.full_clean()` and then `self.save()`</span>
5250
+ <a id="__codelineno-0-73" name="__codelineno-0-73"></a><span class="sd"> which in effect enforces model validation prior to saving the instance, without having</span>
5251
+ <a id="__codelineno-0-74" name="__codelineno-0-74"></a><span class="sd"> to manually make these calls seperately. This is a slight departure from Django norms,</span>
5252
+ <a id="__codelineno-0-75" name="__codelineno-0-75"></a><span class="sd"> but is intended to offer an optional, simplified interface for performing this common</span>
5253
+ <a id="__codelineno-0-76" name="__codelineno-0-76"></a><span class="sd"> workflow. The intended use is for user defined Jobs run via the `nautobot-server nbshell`</span>
5254
+ <a id="__codelineno-0-77" name="__codelineno-0-77"></a><span class="sd"> command.</span>
5255
+ <a id="__codelineno-0-78" name="__codelineno-0-78"></a><span class="sd"> &quot;&quot;&quot;</span>
5256
+ <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="bp">self</span><span class="o">.</span><span class="n">full_clean</span><span class="p">()</span>
5257
+ <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="bp">self</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
3907
5258
  </code></pre></div></td></tr></table></div>
3908
5259
  </details>
3909
5260
  </div>
@@ -3942,67 +5293,67 @@ should be set as a string in the form <code>&lt;app_label&gt;.&lt;model_name&gt;
3942
5293
 
3943
5294
  <details class="quote">
3944
5295
  <summary>Source code in <code>nautobot/extras/plugins/__init__.py</code></summary>
3945
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-645">645</a></span>
3946
- <span class="normal"><a href="#__codelineno-0-646">646</a></span>
3947
- <span class="normal"><a href="#__codelineno-0-647">647</a></span>
3948
- <span class="normal"><a href="#__codelineno-0-648">648</a></span>
3949
- <span class="normal"><a href="#__codelineno-0-649">649</a></span>
3950
- <span class="normal"><a href="#__codelineno-0-650">650</a></span>
3951
- <span class="normal"><a href="#__codelineno-0-651">651</a></span>
3952
- <span class="normal"><a href="#__codelineno-0-652">652</a></span>
3953
- <span class="normal"><a href="#__codelineno-0-653">653</a></span>
3954
- <span class="normal"><a href="#__codelineno-0-654">654</a></span>
3955
- <span class="normal"><a href="#__codelineno-0-655">655</a></span>
3956
- <span class="normal"><a href="#__codelineno-0-656">656</a></span>
3957
- <span class="normal"><a href="#__codelineno-0-657">657</a></span>
3958
- <span class="normal"><a href="#__codelineno-0-658">658</a></span>
3959
- <span class="normal"><a href="#__codelineno-0-659">659</a></span>
3960
- <span class="normal"><a href="#__codelineno-0-660">660</a></span>
3961
- <span class="normal"><a href="#__codelineno-0-661">661</a></span>
3962
- <span class="normal"><a href="#__codelineno-0-662">662</a></span>
3963
- <span class="normal"><a href="#__codelineno-0-663">663</a></span>
3964
- <span class="normal"><a href="#__codelineno-0-664">664</a></span>
3965
- <span class="normal"><a href="#__codelineno-0-665">665</a></span>
3966
- <span class="normal"><a href="#__codelineno-0-666">666</a></span>
3967
- <span class="normal"><a href="#__codelineno-0-667">667</a></span>
3968
- <span class="normal"><a href="#__codelineno-0-668">668</a></span>
3969
- <span class="normal"><a href="#__codelineno-0-669">669</a></span>
3970
- <span class="normal"><a href="#__codelineno-0-670">670</a></span>
3971
- <span class="normal"><a href="#__codelineno-0-671">671</a></span>
3972
- <span class="normal"><a href="#__codelineno-0-672">672</a></span>
3973
- <span class="normal"><a href="#__codelineno-0-673">673</a></span>
3974
- <span class="normal"><a href="#__codelineno-0-674">674</a></span>
3975
- <span class="normal"><a href="#__codelineno-0-675">675</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-645" name="__codelineno-0-645"></a><span class="k">class</span> <span class="nc">CustomValidator</span><span class="p">:</span>
3976
- <a id="__codelineno-0-646" name="__codelineno-0-646"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3977
- <a id="__codelineno-0-647" name="__codelineno-0-647"></a><span class="sd"> This class is used to register plugin custom model validators which act on specified models. It contains the clean</span>
3978
- <a id="__codelineno-0-648" name="__codelineno-0-648"></a><span class="sd"> method which is overridden by plugin authors to execute custom validation logic. Plugin authors must raise</span>
3979
- <a id="__codelineno-0-649" name="__codelineno-0-649"></a><span class="sd"> ValidationError within this method to trigger validation error messages which are propagated to the user.</span>
3980
- <a id="__codelineno-0-650" name="__codelineno-0-650"></a><span class="sd"> A convenience method `validation_error(&lt;message&gt;)` may be used for this purpose.</span>
3981
- <a id="__codelineno-0-651" name="__codelineno-0-651"></a>
3982
- <a id="__codelineno-0-652" name="__codelineno-0-652"></a><span class="sd"> The `model` attribute on the class defines the model to which this validator is registered. It</span>
3983
- <a id="__codelineno-0-653" name="__codelineno-0-653"></a><span class="sd"> should be set as a string in the form `&lt;app_label&gt;.&lt;model_name&gt;`.</span>
3984
- <a id="__codelineno-0-654" name="__codelineno-0-654"></a><span class="sd"> &quot;&quot;&quot;</span>
3985
- <a id="__codelineno-0-655" name="__codelineno-0-655"></a>
3986
- <a id="__codelineno-0-656" name="__codelineno-0-656"></a> <span class="n">model</span> <span class="o">=</span> <span class="kc">None</span>
3987
- <a id="__codelineno-0-657" name="__codelineno-0-657"></a>
3988
- <a id="__codelineno-0-658" name="__codelineno-0-658"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
3989
- <a id="__codelineno-0-659" name="__codelineno-0-659"></a> <span class="bp">self</span><span class="o">.</span><span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">obj</span><span class="p">}</span>
3990
- <a id="__codelineno-0-660" name="__codelineno-0-660"></a>
3991
- <a id="__codelineno-0-661" name="__codelineno-0-661"></a> <span class="k">def</span> <span class="nf">validation_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
3992
- <a id="__codelineno-0-662" name="__codelineno-0-662"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3993
- <a id="__codelineno-0-663" name="__codelineno-0-663"></a><span class="sd"> Convenience method for raising `django.core.exceptions.ValidationError` which is required in order to</span>
3994
- <a id="__codelineno-0-664" name="__codelineno-0-664"></a><span class="sd"> trigger validation error messages which are propagated to the user.</span>
3995
- <a id="__codelineno-0-665" name="__codelineno-0-665"></a><span class="sd"> &quot;&quot;&quot;</span>
3996
- <a id="__codelineno-0-666" name="__codelineno-0-666"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
3997
- <a id="__codelineno-0-667" name="__codelineno-0-667"></a>
3998
- <a id="__codelineno-0-668" name="__codelineno-0-668"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3999
- <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4000
- <a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="sd"> Implement custom model validation in the standard Django clean method pattern. The model instance is accessed</span>
4001
- <a id="__codelineno-0-671" name="__codelineno-0-671"></a><span class="sd"> with the `object` key within `self.context`, e.g. `self.context[&#39;object&#39;]`. ValidationError must be raised to</span>
4002
- <a id="__codelineno-0-672" name="__codelineno-0-672"></a><span class="sd"> prevent saving model instance changes, and propagate messages to the user. For convenience,</span>
4003
- <a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> `self.validation_error(&lt;message&gt;)` may be called to raise a ValidationError.</span>
4004
- <a id="__codelineno-0-674" name="__codelineno-0-674"></a><span class="sd"> &quot;&quot;&quot;</span>
4005
- <a id="__codelineno-0-675" name="__codelineno-0-675"></a> <span class="k">raise</span> <span class="ne">NotImplementedError</span>
5296
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-528">528</a></span>
5297
+ <span class="normal"><a href="#__codelineno-0-529">529</a></span>
5298
+ <span class="normal"><a href="#__codelineno-0-530">530</a></span>
5299
+ <span class="normal"><a href="#__codelineno-0-531">531</a></span>
5300
+ <span class="normal"><a href="#__codelineno-0-532">532</a></span>
5301
+ <span class="normal"><a href="#__codelineno-0-533">533</a></span>
5302
+ <span class="normal"><a href="#__codelineno-0-534">534</a></span>
5303
+ <span class="normal"><a href="#__codelineno-0-535">535</a></span>
5304
+ <span class="normal"><a href="#__codelineno-0-536">536</a></span>
5305
+ <span class="normal"><a href="#__codelineno-0-537">537</a></span>
5306
+ <span class="normal"><a href="#__codelineno-0-538">538</a></span>
5307
+ <span class="normal"><a href="#__codelineno-0-539">539</a></span>
5308
+ <span class="normal"><a href="#__codelineno-0-540">540</a></span>
5309
+ <span class="normal"><a href="#__codelineno-0-541">541</a></span>
5310
+ <span class="normal"><a href="#__codelineno-0-542">542</a></span>
5311
+ <span class="normal"><a href="#__codelineno-0-543">543</a></span>
5312
+ <span class="normal"><a href="#__codelineno-0-544">544</a></span>
5313
+ <span class="normal"><a href="#__codelineno-0-545">545</a></span>
5314
+ <span class="normal"><a href="#__codelineno-0-546">546</a></span>
5315
+ <span class="normal"><a href="#__codelineno-0-547">547</a></span>
5316
+ <span class="normal"><a href="#__codelineno-0-548">548</a></span>
5317
+ <span class="normal"><a href="#__codelineno-0-549">549</a></span>
5318
+ <span class="normal"><a href="#__codelineno-0-550">550</a></span>
5319
+ <span class="normal"><a href="#__codelineno-0-551">551</a></span>
5320
+ <span class="normal"><a href="#__codelineno-0-552">552</a></span>
5321
+ <span class="normal"><a href="#__codelineno-0-553">553</a></span>
5322
+ <span class="normal"><a href="#__codelineno-0-554">554</a></span>
5323
+ <span class="normal"><a href="#__codelineno-0-555">555</a></span>
5324
+ <span class="normal"><a href="#__codelineno-0-556">556</a></span>
5325
+ <span class="normal"><a href="#__codelineno-0-557">557</a></span>
5326
+ <span class="normal"><a href="#__codelineno-0-558">558</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-528" name="__codelineno-0-528"></a><span class="k">class</span> <span class="nc">CustomValidator</span><span class="p">:</span>
5327
+ <a id="__codelineno-0-529" name="__codelineno-0-529"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5328
+ <a id="__codelineno-0-530" name="__codelineno-0-530"></a><span class="sd"> This class is used to register plugin custom model validators which act on specified models. It contains the clean</span>
5329
+ <a id="__codelineno-0-531" name="__codelineno-0-531"></a><span class="sd"> method which is overridden by plugin authors to execute custom validation logic. Plugin authors must raise</span>
5330
+ <a id="__codelineno-0-532" name="__codelineno-0-532"></a><span class="sd"> ValidationError within this method to trigger validation error messages which are propagated to the user.</span>
5331
+ <a id="__codelineno-0-533" name="__codelineno-0-533"></a><span class="sd"> A convenience method `validation_error(&lt;message&gt;)` may be used for this purpose.</span>
5332
+ <a id="__codelineno-0-534" name="__codelineno-0-534"></a>
5333
+ <a id="__codelineno-0-535" name="__codelineno-0-535"></a><span class="sd"> The `model` attribute on the class defines the model to which this validator is registered. It</span>
5334
+ <a id="__codelineno-0-536" name="__codelineno-0-536"></a><span class="sd"> should be set as a string in the form `&lt;app_label&gt;.&lt;model_name&gt;`.</span>
5335
+ <a id="__codelineno-0-537" name="__codelineno-0-537"></a><span class="sd"> &quot;&quot;&quot;</span>
5336
+ <a id="__codelineno-0-538" name="__codelineno-0-538"></a>
5337
+ <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="n">model</span> <span class="o">=</span> <span class="kc">None</span>
5338
+ <a id="__codelineno-0-540" name="__codelineno-0-540"></a>
5339
+ <a id="__codelineno-0-541" name="__codelineno-0-541"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">obj</span><span class="p">):</span>
5340
+ <a id="__codelineno-0-542" name="__codelineno-0-542"></a> <span class="bp">self</span><span class="o">.</span><span class="n">context</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&quot;object&quot;</span><span class="p">:</span> <span class="n">obj</span><span class="p">}</span>
5341
+ <a id="__codelineno-0-543" name="__codelineno-0-543"></a>
5342
+ <a id="__codelineno-0-544" name="__codelineno-0-544"></a> <span class="k">def</span> <span class="nf">validation_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
5343
+ <a id="__codelineno-0-545" name="__codelineno-0-545"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5344
+ <a id="__codelineno-0-546" name="__codelineno-0-546"></a><span class="sd"> Convenience method for raising `django.core.exceptions.ValidationError` which is required in order to</span>
5345
+ <a id="__codelineno-0-547" name="__codelineno-0-547"></a><span class="sd"> trigger validation error messages which are propagated to the user.</span>
5346
+ <a id="__codelineno-0-548" name="__codelineno-0-548"></a><span class="sd"> &quot;&quot;&quot;</span>
5347
+ <a id="__codelineno-0-549" name="__codelineno-0-549"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
5348
+ <a id="__codelineno-0-550" name="__codelineno-0-550"></a>
5349
+ <a id="__codelineno-0-551" name="__codelineno-0-551"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5350
+ <a id="__codelineno-0-552" name="__codelineno-0-552"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5351
+ <a id="__codelineno-0-553" name="__codelineno-0-553"></a><span class="sd"> Implement custom model validation in the standard Django clean method pattern. The model instance is accessed</span>
5352
+ <a id="__codelineno-0-554" name="__codelineno-0-554"></a><span class="sd"> with the `object` key within `self.context`, e.g. `self.context[&#39;object&#39;]`. ValidationError must be raised to</span>
5353
+ <a id="__codelineno-0-555" name="__codelineno-0-555"></a><span class="sd"> prevent saving model instance changes, and propagate messages to the user. For convenience,</span>
5354
+ <a id="__codelineno-0-556" name="__codelineno-0-556"></a><span class="sd"> `self.validation_error(&lt;message&gt;)` may be called to raise a ValidationError.</span>
5355
+ <a id="__codelineno-0-557" name="__codelineno-0-557"></a><span class="sd"> &quot;&quot;&quot;</span>
5356
+ <a id="__codelineno-0-558" name="__codelineno-0-558"></a> <span class="k">raise</span> <span class="ne">NotImplementedError</span>
4006
5357
  </code></pre></div></td></tr></table></div>
4007
5358
  </details>
4008
5359
 
@@ -4037,21 +5388,21 @@ prevent saving model instance changes, and propagate messages to the user. For c
4037
5388
 
4038
5389
  <details class="quote">
4039
5390
  <summary>Source code in <code>nautobot/extras/plugins/__init__.py</code></summary>
4040
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-668">668</a></span>
4041
- <span class="normal"><a href="#__codelineno-0-669">669</a></span>
4042
- <span class="normal"><a href="#__codelineno-0-670">670</a></span>
4043
- <span class="normal"><a href="#__codelineno-0-671">671</a></span>
4044
- <span class="normal"><a href="#__codelineno-0-672">672</a></span>
4045
- <span class="normal"><a href="#__codelineno-0-673">673</a></span>
4046
- <span class="normal"><a href="#__codelineno-0-674">674</a></span>
4047
- <span class="normal"><a href="#__codelineno-0-675">675</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-668" name="__codelineno-0-668"></a><span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4048
- <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4049
- <a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="sd"> Implement custom model validation in the standard Django clean method pattern. The model instance is accessed</span>
4050
- <a id="__codelineno-0-671" name="__codelineno-0-671"></a><span class="sd"> with the `object` key within `self.context`, e.g. `self.context[&#39;object&#39;]`. ValidationError must be raised to</span>
4051
- <a id="__codelineno-0-672" name="__codelineno-0-672"></a><span class="sd"> prevent saving model instance changes, and propagate messages to the user. For convenience,</span>
4052
- <a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> `self.validation_error(&lt;message&gt;)` may be called to raise a ValidationError.</span>
4053
- <a id="__codelineno-0-674" name="__codelineno-0-674"></a><span class="sd"> &quot;&quot;&quot;</span>
4054
- <a id="__codelineno-0-675" name="__codelineno-0-675"></a> <span class="k">raise</span> <span class="ne">NotImplementedError</span>
5391
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-551">551</a></span>
5392
+ <span class="normal"><a href="#__codelineno-0-552">552</a></span>
5393
+ <span class="normal"><a href="#__codelineno-0-553">553</a></span>
5394
+ <span class="normal"><a href="#__codelineno-0-554">554</a></span>
5395
+ <span class="normal"><a href="#__codelineno-0-555">555</a></span>
5396
+ <span class="normal"><a href="#__codelineno-0-556">556</a></span>
5397
+ <span class="normal"><a href="#__codelineno-0-557">557</a></span>
5398
+ <span class="normal"><a href="#__codelineno-0-558">558</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-551" name="__codelineno-0-551"></a><span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5399
+ <a id="__codelineno-0-552" name="__codelineno-0-552"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5400
+ <a id="__codelineno-0-553" name="__codelineno-0-553"></a><span class="sd"> Implement custom model validation in the standard Django clean method pattern. The model instance is accessed</span>
5401
+ <a id="__codelineno-0-554" name="__codelineno-0-554"></a><span class="sd"> with the `object` key within `self.context`, e.g. `self.context[&#39;object&#39;]`. ValidationError must be raised to</span>
5402
+ <a id="__codelineno-0-555" name="__codelineno-0-555"></a><span class="sd"> prevent saving model instance changes, and propagate messages to the user. For convenience,</span>
5403
+ <a id="__codelineno-0-556" name="__codelineno-0-556"></a><span class="sd"> `self.validation_error(&lt;message&gt;)` may be called to raise a ValidationError.</span>
5404
+ <a id="__codelineno-0-557" name="__codelineno-0-557"></a><span class="sd"> &quot;&quot;&quot;</span>
5405
+ <a id="__codelineno-0-558" name="__codelineno-0-558"></a> <span class="k">raise</span> <span class="ne">NotImplementedError</span>
4055
5406
  </code></pre></div></td></tr></table></div>
4056
5407
  </details>
4057
5408
  </div>
@@ -4075,17 +5426,17 @@ trigger validation error messages which are propagated to the user.</p>
4075
5426
 
4076
5427
  <details class="quote">
4077
5428
  <summary>Source code in <code>nautobot/extras/plugins/__init__.py</code></summary>
4078
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-661">661</a></span>
4079
- <span class="normal"><a href="#__codelineno-0-662">662</a></span>
4080
- <span class="normal"><a href="#__codelineno-0-663">663</a></span>
4081
- <span class="normal"><a href="#__codelineno-0-664">664</a></span>
4082
- <span class="normal"><a href="#__codelineno-0-665">665</a></span>
4083
- <span class="normal"><a href="#__codelineno-0-666">666</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-661" name="__codelineno-0-661"></a><span class="k">def</span> <span class="nf">validation_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
4084
- <a id="__codelineno-0-662" name="__codelineno-0-662"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4085
- <a id="__codelineno-0-663" name="__codelineno-0-663"></a><span class="sd"> Convenience method for raising `django.core.exceptions.ValidationError` which is required in order to</span>
4086
- <a id="__codelineno-0-664" name="__codelineno-0-664"></a><span class="sd"> trigger validation error messages which are propagated to the user.</span>
4087
- <a id="__codelineno-0-665" name="__codelineno-0-665"></a><span class="sd"> &quot;&quot;&quot;</span>
4088
- <a id="__codelineno-0-666" name="__codelineno-0-666"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
5429
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-544">544</a></span>
5430
+ <span class="normal"><a href="#__codelineno-0-545">545</a></span>
5431
+ <span class="normal"><a href="#__codelineno-0-546">546</a></span>
5432
+ <span class="normal"><a href="#__codelineno-0-547">547</a></span>
5433
+ <span class="normal"><a href="#__codelineno-0-548">548</a></span>
5434
+ <span class="normal"><a href="#__codelineno-0-549">549</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-544" name="__codelineno-0-544"></a><span class="k">def</span> <span class="nf">validation_error</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
5435
+ <a id="__codelineno-0-545" name="__codelineno-0-545"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5436
+ <a id="__codelineno-0-546" name="__codelineno-0-546"></a><span class="sd"> Convenience method for raising `django.core.exceptions.ValidationError` which is required in order to</span>
5437
+ <a id="__codelineno-0-547" name="__codelineno-0-547"></a><span class="sd"> trigger validation error messages which are propagated to the user.</span>
5438
+ <a id="__codelineno-0-548" name="__codelineno-0-548"></a><span class="sd"> &quot;&quot;&quot;</span>
5439
+ <a id="__codelineno-0-549" name="__codelineno-0-549"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="n">message</span><span class="p">)</span>
4089
5440
  </code></pre></div></td></tr></table></div>
4090
5441
  </details>
4091
5442
  </div>
@@ -4126,7 +5477,10 @@ Device Role, Rack Group, Status, Manufacturer, and Platform.</p>
4126
5477
 
4127
5478
  <details class="quote">
4128
5479
  <summary>Source code in <code>nautobot/core/models/generics.py</code></summary>
4129
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-17">17</a></span>
5480
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-14">14</a></span>
5481
+ <span class="normal"><a href="#__codelineno-0-15">15</a></span>
5482
+ <span class="normal"><a href="#__codelineno-0-16">16</a></span>
5483
+ <span class="normal"><a href="#__codelineno-0-17">17</a></span>
4130
5484
  <span class="normal"><a href="#__codelineno-0-18">18</a></span>
4131
5485
  <span class="normal"><a href="#__codelineno-0-19">19</a></span>
4132
5486
  <span class="normal"><a href="#__codelineno-0-20">20</a></span>
@@ -4137,24 +5491,21 @@ Device Role, Rack Group, Status, Manufacturer, and Platform.</p>
4137
5491
  <span class="normal"><a href="#__codelineno-0-25">25</a></span>
4138
5492
  <span class="normal"><a href="#__codelineno-0-26">26</a></span>
4139
5493
  <span class="normal"><a href="#__codelineno-0-27">27</a></span>
4140
- <span class="normal"><a href="#__codelineno-0-28">28</a></span>
4141
- <span class="normal"><a href="#__codelineno-0-29">29</a></span>
4142
- <span class="normal"><a href="#__codelineno-0-30">30</a></span>
4143
- <span class="normal"><a href="#__codelineno-0-31">31</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="k">class</span> <span class="nc">OrganizationalModel</span><span class="p">(</span>
4144
- <a id="__codelineno-0-18" name="__codelineno-0-18"></a> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">ChangeLoggedModel</span><span class="p">,</span> <span class="n">CustomFieldModel</span><span class="p">,</span> <span class="n">RelationshipModel</span><span class="p">,</span> <span class="n">DynamicGroupMixin</span><span class="p">,</span> <span class="n">NotesMixin</span>
4145
- <a id="__codelineno-0-19" name="__codelineno-0-19"></a><span class="p">):</span>
4146
- <a id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4147
- <a id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="sd"> Base abstract model for all organizational models.</span>
4148
- <a id="__codelineno-0-22" name="__codelineno-0-22"></a>
4149
- <a id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="sd"> Organizational models aid the primary models by building structured relationships</span>
4150
- <a id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="sd"> and logical groups, or categorizations. Organizational models do not typically</span>
4151
- <a id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="sd"> represent concrete networking resources or assets, but rather they enable user</span>
4152
- <a id="__codelineno-0-26" name="__codelineno-0-26"></a><span class="sd"> specific use cases and metadata about network resources. Examples include</span>
4153
- <a id="__codelineno-0-27" name="__codelineno-0-27"></a><span class="sd"> Device Role, Rack Group, Status, Manufacturer, and Platform.</span>
4154
- <a id="__codelineno-0-28" name="__codelineno-0-28"></a><span class="sd"> &quot;&quot;&quot;</span>
4155
- <a id="__codelineno-0-29" name="__codelineno-0-29"></a>
4156
- <a id="__codelineno-0-30" name="__codelineno-0-30"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
4157
- <a id="__codelineno-0-31" name="__codelineno-0-31"></a> <span class="n">abstract</span> <span class="o">=</span> <span class="kc">True</span>
5494
+ <span class="normal"><a href="#__codelineno-0-28">28</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-14" name="__codelineno-0-14"></a><span class="k">class</span> <span class="nc">OrganizationalModel</span><span class="p">(</span>
5495
+ <a id="__codelineno-0-15" name="__codelineno-0-15"></a> <span class="n">BaseModel</span><span class="p">,</span> <span class="n">ChangeLoggedModel</span><span class="p">,</span> <span class="n">CustomFieldModel</span><span class="p">,</span> <span class="n">RelationshipModel</span><span class="p">,</span> <span class="n">DynamicGroupMixin</span><span class="p">,</span> <span class="n">NotesMixin</span>
5496
+ <a id="__codelineno-0-16" name="__codelineno-0-16"></a><span class="p">):</span>
5497
+ <a id="__codelineno-0-17" name="__codelineno-0-17"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5498
+ <a id="__codelineno-0-18" name="__codelineno-0-18"></a><span class="sd"> Base abstract model for all organizational models.</span>
5499
+ <a id="__codelineno-0-19" name="__codelineno-0-19"></a>
5500
+ <a id="__codelineno-0-20" name="__codelineno-0-20"></a><span class="sd"> Organizational models aid the primary models by building structured relationships</span>
5501
+ <a id="__codelineno-0-21" name="__codelineno-0-21"></a><span class="sd"> and logical groups, or categorizations. Organizational models do not typically</span>
5502
+ <a id="__codelineno-0-22" name="__codelineno-0-22"></a><span class="sd"> represent concrete networking resources or assets, but rather they enable user</span>
5503
+ <a id="__codelineno-0-23" name="__codelineno-0-23"></a><span class="sd"> specific use cases and metadata about network resources. Examples include</span>
5504
+ <a id="__codelineno-0-24" name="__codelineno-0-24"></a><span class="sd"> Device Role, Rack Group, Status, Manufacturer, and Platform.</span>
5505
+ <a id="__codelineno-0-25" name="__codelineno-0-25"></a><span class="sd"> &quot;&quot;&quot;</span>
5506
+ <a id="__codelineno-0-26" name="__codelineno-0-26"></a>
5507
+ <a id="__codelineno-0-27" name="__codelineno-0-27"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
5508
+ <a id="__codelineno-0-28" name="__codelineno-0-28"></a> <span class="n">abstract</span> <span class="o">=</span> <span class="kc">True</span>
4158
5509
  </code></pre></div></td></tr></table></div>
4159
5510
  </details>
4160
5511
 
@@ -4203,33 +5554,33 @@ tangible or logical resources on the network, or within the organization.</p>
4203
5554
 
4204
5555
  <details class="quote">
4205
5556
  <summary>Source code in <code>nautobot/core/models/generics.py</code></summary>
4206
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-75">75</a></span>
4207
- <span class="normal"><a href="#__codelineno-0-76">76</a></span>
4208
- <span class="normal"><a href="#__codelineno-0-77">77</a></span>
4209
- <span class="normal"><a href="#__codelineno-0-78">78</a></span>
4210
- <span class="normal"><a href="#__codelineno-0-79">79</a></span>
4211
- <span class="normal"><a href="#__codelineno-0-80">80</a></span>
4212
- <span class="normal"><a href="#__codelineno-0-81">81</a></span>
4213
- <span class="normal"><a href="#__codelineno-0-82">82</a></span>
4214
- <span class="normal"><a href="#__codelineno-0-83">83</a></span>
4215
- <span class="normal"><a href="#__codelineno-0-84">84</a></span>
4216
- <span class="normal"><a href="#__codelineno-0-85">85</a></span>
4217
- <span class="normal"><a href="#__codelineno-0-86">86</a></span>
4218
- <span class="normal"><a href="#__codelineno-0-87">87</a></span>
4219
- <span class="normal"><a href="#__codelineno-0-88">88</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-75" name="__codelineno-0-75"></a><span class="k">class</span> <span class="nc">PrimaryModel</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">,</span> <span class="n">ChangeLoggedModel</span><span class="p">,</span> <span class="n">CustomFieldModel</span><span class="p">,</span> <span class="n">RelationshipModel</span><span class="p">,</span> <span class="n">DynamicGroupMixin</span><span class="p">,</span> <span class="n">NotesMixin</span><span class="p">):</span>
4220
- <a id="__codelineno-0-76" name="__codelineno-0-76"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4221
- <a id="__codelineno-0-77" name="__codelineno-0-77"></a><span class="sd"> Base abstract model for all primary models.</span>
4222
- <a id="__codelineno-0-78" name="__codelineno-0-78"></a>
4223
- <a id="__codelineno-0-79" name="__codelineno-0-79"></a><span class="sd"> A primary model is one which is materialistically relevant to the network datamodel.</span>
4224
- <a id="__codelineno-0-80" name="__codelineno-0-80"></a><span class="sd"> Such models form the basis of major elements of the data model, like Device,</span>
4225
- <a id="__codelineno-0-81" name="__codelineno-0-81"></a><span class="sd"> IP Address, Site, VLAN, Virtual Machine, etc. Primary models usually represent</span>
4226
- <a id="__codelineno-0-82" name="__codelineno-0-82"></a><span class="sd"> tangible or logical resources on the network, or within the organization.</span>
4227
- <a id="__codelineno-0-83" name="__codelineno-0-83"></a><span class="sd"> &quot;&quot;&quot;</span>
4228
- <a id="__codelineno-0-84" name="__codelineno-0-84"></a>
4229
- <a id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="n">tags</span> <span class="o">=</span> <span class="n">TaggableManager</span><span class="p">(</span><span class="n">through</span><span class="o">=</span><span class="n">TaggedItem</span><span class="p">,</span> <span class="n">manager</span><span class="o">=</span><span class="n">_NautobotTaggableManager</span><span class="p">,</span> <span class="n">ordering</span><span class="o">=</span><span class="p">[</span><span class="s2">&quot;name&quot;</span><span class="p">])</span>
4230
- <a id="__codelineno-0-86" name="__codelineno-0-86"></a>
4231
- <a id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
4232
- <a id="__codelineno-0-88" name="__codelineno-0-88"></a> <span class="n">abstract</span> <span class="o">=</span> <span class="kc">True</span>
5557
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-31">31</a></span>
5558
+ <span class="normal"><a href="#__codelineno-0-32">32</a></span>
5559
+ <span class="normal"><a href="#__codelineno-0-33">33</a></span>
5560
+ <span class="normal"><a href="#__codelineno-0-34">34</a></span>
5561
+ <span class="normal"><a href="#__codelineno-0-35">35</a></span>
5562
+ <span class="normal"><a href="#__codelineno-0-36">36</a></span>
5563
+ <span class="normal"><a href="#__codelineno-0-37">37</a></span>
5564
+ <span class="normal"><a href="#__codelineno-0-38">38</a></span>
5565
+ <span class="normal"><a href="#__codelineno-0-39">39</a></span>
5566
+ <span class="normal"><a href="#__codelineno-0-40">40</a></span>
5567
+ <span class="normal"><a href="#__codelineno-0-41">41</a></span>
5568
+ <span class="normal"><a href="#__codelineno-0-42">42</a></span>
5569
+ <span class="normal"><a href="#__codelineno-0-43">43</a></span>
5570
+ <span class="normal"><a href="#__codelineno-0-44">44</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-31" name="__codelineno-0-31"></a><span class="k">class</span> <span class="nc">PrimaryModel</span><span class="p">(</span><span class="n">BaseModel</span><span class="p">,</span> <span class="n">ChangeLoggedModel</span><span class="p">,</span> <span class="n">CustomFieldModel</span><span class="p">,</span> <span class="n">RelationshipModel</span><span class="p">,</span> <span class="n">DynamicGroupMixin</span><span class="p">,</span> <span class="n">NotesMixin</span><span class="p">):</span>
5571
+ <a id="__codelineno-0-32" name="__codelineno-0-32"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5572
+ <a id="__codelineno-0-33" name="__codelineno-0-33"></a><span class="sd"> Base abstract model for all primary models.</span>
5573
+ <a id="__codelineno-0-34" name="__codelineno-0-34"></a>
5574
+ <a id="__codelineno-0-35" name="__codelineno-0-35"></a><span class="sd"> A primary model is one which is materialistically relevant to the network datamodel.</span>
5575
+ <a id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="sd"> Such models form the basis of major elements of the data model, like Device,</span>
5576
+ <a id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="sd"> IP Address, Site, VLAN, Virtual Machine, etc. Primary models usually represent</span>
5577
+ <a id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="sd"> tangible or logical resources on the network, or within the organization.</span>
5578
+ <a id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="sd"> &quot;&quot;&quot;</span>
5579
+ <a id="__codelineno-0-40" name="__codelineno-0-40"></a>
5580
+ <a id="__codelineno-0-41" name="__codelineno-0-41"></a> <span class="n">tags</span> <span class="o">=</span> <span class="n">TagsField</span><span class="p">()</span>
5581
+ <a id="__codelineno-0-42" name="__codelineno-0-42"></a>
5582
+ <a id="__codelineno-0-43" name="__codelineno-0-43"></a> <span class="k">class</span> <span class="nc">Meta</span><span class="p">:</span>
5583
+ <a id="__codelineno-0-44" name="__codelineno-0-44"></a> <span class="n">abstract</span> <span class="o">=</span> <span class="kc">True</span>
4233
5584
  </code></pre></div></td></tr></table></div>
4234
5585
  </details>
4235
5586
 
@@ -4280,8 +5631,7 @@ tangible or logical resources on the network, or within the organization.</p>
4280
5631
 
4281
5632
  <details class="quote">
4282
5633
  <summary>Source code in <code>nautobot/extras/models/statuses.py</code></summary>
4283
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-36"> 36</a></span>
4284
- <span class="normal"><a href="#__codelineno-0-37"> 37</a></span>
5634
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-37"> 37</a></span>
4285
5635
  <span class="normal"><a href="#__codelineno-0-38"> 38</a></span>
4286
5636
  <span class="normal"><a href="#__codelineno-0-39"> 39</a></span>
4287
5637
  <span class="normal"><a href="#__codelineno-0-40"> 40</a></span>
@@ -4344,75 +5694,70 @@ tangible or logical resources on the network, or within the organization.</p>
4344
5694
  <span class="normal"><a href="#__codelineno-0-97"> 97</a></span>
4345
5695
  <span class="normal"><a href="#__codelineno-0-98"> 98</a></span>
4346
5696
  <span class="normal"><a href="#__codelineno-0-99"> 99</a></span>
4347
- <span class="normal"><a href="#__codelineno-0-100">100</a></span>
4348
- <span class="normal"><a href="#__codelineno-0-101">101</a></span>
4349
- <span class="normal"><a href="#__codelineno-0-102">102</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-36" name="__codelineno-0-36"></a><span class="k">class</span> <span class="nc">StatusField</span><span class="p">(</span><span class="n">ForeignKeyLimitedByContentTypes</span><span class="p">):</span>
4350
- <a id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4351
- <a id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="sd"> Model database field that automatically limits custom choices.</span>
4352
- <a id="__codelineno-0-39" name="__codelineno-0-39"></a>
4353
- <a id="__codelineno-0-40" name="__codelineno-0-40"></a><span class="sd"> The limit_choices_to for the field are automatically derived from:</span>
4354
- <a id="__codelineno-0-41" name="__codelineno-0-41"></a>
4355
- <a id="__codelineno-0-42" name="__codelineno-0-42"></a><span class="sd"> - the content-type to which the field is attached (e.g. `dcim.device`)</span>
4356
- <a id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="sd"> &quot;&quot;&quot;</span>
4357
- <a id="__codelineno-0-44" name="__codelineno-0-44"></a>
4358
- <a id="__codelineno-0-45" name="__codelineno-0-45"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</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>
4359
- <a id="__codelineno-0-46" name="__codelineno-0-46"></a> <span class="n">kwargs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s2">&quot;to&quot;</span><span class="p">,</span> <span class="n">Status</span><span class="p">)</span>
4360
- <a id="__codelineno-0-47" name="__codelineno-0-47"></a> <span class="n">kwargs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s2">&quot;on_delete&quot;</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">PROTECT</span><span class="p">)</span>
4361
- <a id="__codelineno-0-48" name="__codelineno-0-48"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</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>
4362
- <a id="__codelineno-0-49" name="__codelineno-0-49"></a>
4363
- <a id="__codelineno-0-50" name="__codelineno-0-50"></a> <span class="k">def</span> <span class="nf">get_limit_choices_to</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4364
- <a id="__codelineno-0-51" name="__codelineno-0-51"></a> <span class="k">return</span> <span class="p">{</span><span class="s2">&quot;content_types&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="bp">self</span><span class="o">.</span><span class="n">model</span><span class="p">)}</span>
4365
- <a id="__codelineno-0-52" name="__codelineno-0-52"></a>
4366
- <a id="__codelineno-0-53" name="__codelineno-0-53"></a> <span class="k">def</span> <span class="nf">contribute_to_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">cls</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>
4367
- <a id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4368
- <a id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="sd"> Overload default so that we can assert that `.get_FOO_display` is</span>
4369
- <a id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="sd"> attached to any model that is using a `StatusField`.</span>
4370
- <a id="__codelineno-0-57" name="__codelineno-0-57"></a>
4371
- <a id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="sd"> Using `.contribute_to_class()` is how field objects get added to the model</span>
4372
- <a id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="sd"> at during the instance preparation. This is also where any custom model</span>
4373
- <a id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="sd"> methods are hooked in. So in short this method asserts that any time a</span>
4374
- <a id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="sd"> `StatusField` is added to a model, that model also gets a</span>
4375
- <a id="__codelineno-0-62" name="__codelineno-0-62"></a><span class="sd"> `.get_status_display()` and a `.get_status_color()` method without</span>
4376
- <a id="__codelineno-0-63" name="__codelineno-0-63"></a><span class="sd"> having to define it on the model yourself.</span>
4377
- <a id="__codelineno-0-64" name="__codelineno-0-64"></a><span class="sd"> &quot;&quot;&quot;</span>
4378
- <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">contribute_to_class</span><span class="p">(</span><span class="bp">cls</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>
4379
- <a id="__codelineno-0-66" name="__codelineno-0-66"></a>
4380
- <a id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="k">def</span> <span class="nf">_get_FIELD_display</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
4381
- <a id="__codelineno-0-68" name="__codelineno-0-68"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4382
- <a id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="sd"> Closure to replace default model method of the same name.</span>
4383
- <a id="__codelineno-0-70" name="__codelineno-0-70"></a>
4384
- <a id="__codelineno-0-71" name="__codelineno-0-71"></a><span class="sd"> Cargo-culted from `django.db.models.base.Model._get_FIELD_display`</span>
4385
- <a id="__codelineno-0-72" name="__codelineno-0-72"></a><span class="sd"> &quot;&quot;&quot;</span>
4386
- <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="n">choices</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">get_choices</span><span class="p">()</span>
4387
- <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">attname</span><span class="p">)</span>
4388
- <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="n">choices_dict</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">choices</span><span class="p">))</span>
4389
- <a id="__codelineno-0-76" name="__codelineno-0-76"></a> <span class="c1"># force_str() to coerce lazy strings.</span>
4390
- <a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="k">return</span> <span class="n">force_str</span><span class="p">(</span><span class="n">choices_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="n">value</span><span class="p">),</span> <span class="n">strings_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
4391
- <a id="__codelineno-0-78" name="__codelineno-0-78"></a>
4392
- <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="c1"># Install `.get_FOO_display()` onto the model using our own version.</span>
4393
- <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
4394
- <a id="__codelineno-0-81" name="__codelineno-0-81"></a> <span class="nb">setattr</span><span class="p">(</span>
4395
- <a id="__codelineno-0-82" name="__codelineno-0-82"></a> <span class="bp">cls</span><span class="p">,</span>
4396
- <a id="__codelineno-0-83" name="__codelineno-0-83"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span><span class="p">,</span>
4397
- <a id="__codelineno-0-84" name="__codelineno-0-84"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_display</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
4398
- <a id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="p">)</span>
4399
- <a id="__codelineno-0-86" name="__codelineno-0-86"></a>
4400
- <a id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="k">def</span> <span class="nf">_get_FIELD_color</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
4401
- <a id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4402
- <a id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="sd"> Return `self.FOO.color` (where FOO is field name).</span>
4403
- <a id="__codelineno-0-90" name="__codelineno-0-90"></a>
4404
- <a id="__codelineno-0-91" name="__codelineno-0-91"></a><span class="sd"> I am added to the model via `StatusField.contribute_to_class()`.</span>
4405
- <a id="__codelineno-0-92" name="__codelineno-0-92"></a><span class="sd"> &quot;&quot;&quot;</span>
4406
- <a id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="n">field_method</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
4407
- <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field_method</span><span class="p">,</span> <span class="s2">&quot;color&quot;</span><span class="p">)</span>
4408
- <a id="__codelineno-0-95" name="__codelineno-0-95"></a>
4409
- <a id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="c1"># Install `.get_FOO_color()` onto the model using our own version.</span>
4410
- <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
4411
- <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="nb">setattr</span><span class="p">(</span>
4412
- <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="bp">cls</span><span class="p">,</span>
4413
- <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span><span class="p">,</span>
4414
- <a id="__codelineno-0-101" name="__codelineno-0-101"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_color</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
4415
- <a id="__codelineno-0-102" name="__codelineno-0-102"></a> <span class="p">)</span>
5697
+ <span class="normal"><a href="#__codelineno-0-100">100</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-37" name="__codelineno-0-37"></a><span class="k">class</span> <span class="nc">StatusField</span><span class="p">(</span><span class="n">ForeignKeyLimitedByContentTypes</span><span class="p">):</span>
5698
+ <a id="__codelineno-0-38" name="__codelineno-0-38"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5699
+ <a id="__codelineno-0-39" name="__codelineno-0-39"></a><span class="sd"> Model database field that automatically limits custom choices.</span>
5700
+ <a id="__codelineno-0-40" name="__codelineno-0-40"></a>
5701
+ <a id="__codelineno-0-41" name="__codelineno-0-41"></a><span class="sd"> The limit_choices_to for the field are automatically derived from:</span>
5702
+ <a id="__codelineno-0-42" name="__codelineno-0-42"></a>
5703
+ <a id="__codelineno-0-43" name="__codelineno-0-43"></a><span class="sd"> - the content-type to which the field is attached (e.g. `dcim.device`)</span>
5704
+ <a id="__codelineno-0-44" name="__codelineno-0-44"></a><span class="sd"> &quot;&quot;&quot;</span>
5705
+ <a id="__codelineno-0-45" name="__codelineno-0-45"></a>
5706
+ <a id="__codelineno-0-46" name="__codelineno-0-46"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span><span class="bp">self</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>
5707
+ <a id="__codelineno-0-47" name="__codelineno-0-47"></a> <span class="n">kwargs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s2">&quot;to&quot;</span><span class="p">,</span> <span class="n">Status</span><span class="p">)</span>
5708
+ <a id="__codelineno-0-48" name="__codelineno-0-48"></a> <span class="n">kwargs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s2">&quot;on_delete&quot;</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">PROTECT</span><span class="p">)</span>
5709
+ <a id="__codelineno-0-49" name="__codelineno-0-49"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</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>
5710
+ <a id="__codelineno-0-50" name="__codelineno-0-50"></a>
5711
+ <a id="__codelineno-0-51" name="__codelineno-0-51"></a> <span class="k">def</span> <span class="nf">contribute_to_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">cls</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>
5712
+ <a id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5713
+ <a id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="sd"> Overload default so that we can assert that `.get_FOO_display` is</span>
5714
+ <a id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="sd"> attached to any model that is using a `StatusField`.</span>
5715
+ <a id="__codelineno-0-55" name="__codelineno-0-55"></a>
5716
+ <a id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="sd"> Using `.contribute_to_class()` is how field objects get added to the model</span>
5717
+ <a id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="sd"> at during the instance preparation. This is also where any custom model</span>
5718
+ <a id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="sd"> methods are hooked in. So in short this method asserts that any time a</span>
5719
+ <a id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="sd"> `StatusField` is added to a model, that model also gets a</span>
5720
+ <a id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="sd"> `.get_status_display()` and a `.get_status_color()` method without</span>
5721
+ <a id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="sd"> having to define it on the model yourself.</span>
5722
+ <a id="__codelineno-0-62" name="__codelineno-0-62"></a><span class="sd"> &quot;&quot;&quot;</span>
5723
+ <a id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">contribute_to_class</span><span class="p">(</span><span class="bp">cls</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>
5724
+ <a id="__codelineno-0-64" name="__codelineno-0-64"></a>
5725
+ <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="k">def</span> <span class="nf">_get_FIELD_display</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
5726
+ <a id="__codelineno-0-66" name="__codelineno-0-66"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5727
+ <a id="__codelineno-0-67" name="__codelineno-0-67"></a><span class="sd"> Closure to replace default model method of the same name.</span>
5728
+ <a id="__codelineno-0-68" name="__codelineno-0-68"></a>
5729
+ <a id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="sd"> Cargo-culted from `django.db.models.base.Model._get_FIELD_display`</span>
5730
+ <a id="__codelineno-0-70" name="__codelineno-0-70"></a><span class="sd"> &quot;&quot;&quot;</span>
5731
+ <a id="__codelineno-0-71" name="__codelineno-0-71"></a> <span class="n">choices</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">get_choices</span><span class="p">()</span>
5732
+ <a id="__codelineno-0-72" name="__codelineno-0-72"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">attname</span><span class="p">)</span>
5733
+ <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="n">choices_dict</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">choices</span><span class="p">))</span>
5734
+ <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="c1"># force_str() to coerce lazy strings.</span>
5735
+ <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="k">return</span> <span class="n">force_str</span><span class="p">(</span><span class="n">choices_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="n">value</span><span class="p">),</span> <span class="n">strings_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
5736
+ <a id="__codelineno-0-76" name="__codelineno-0-76"></a>
5737
+ <a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="c1"># Install `.get_FOO_display()` onto the model using our own version.</span>
5738
+ <a id="__codelineno-0-78" name="__codelineno-0-78"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
5739
+ <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="nb">setattr</span><span class="p">(</span>
5740
+ <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="bp">cls</span><span class="p">,</span>
5741
+ <a id="__codelineno-0-81" name="__codelineno-0-81"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span><span class="p">,</span>
5742
+ <a id="__codelineno-0-82" name="__codelineno-0-82"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_display</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
5743
+ <a id="__codelineno-0-83" name="__codelineno-0-83"></a> <span class="p">)</span>
5744
+ <a id="__codelineno-0-84" name="__codelineno-0-84"></a>
5745
+ <a id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="k">def</span> <span class="nf">_get_FIELD_color</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
5746
+ <a id="__codelineno-0-86" name="__codelineno-0-86"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5747
+ <a id="__codelineno-0-87" name="__codelineno-0-87"></a><span class="sd"> Return `self.FOO.color` (where FOO is field name).</span>
5748
+ <a id="__codelineno-0-88" name="__codelineno-0-88"></a>
5749
+ <a id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="sd"> I am added to the model via `StatusField.contribute_to_class()`.</span>
5750
+ <a id="__codelineno-0-90" name="__codelineno-0-90"></a><span class="sd"> &quot;&quot;&quot;</span>
5751
+ <a id="__codelineno-0-91" name="__codelineno-0-91"></a> <span class="n">field_method</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
5752
+ <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field_method</span><span class="p">,</span> <span class="s2">&quot;color&quot;</span><span class="p">)</span>
5753
+ <a id="__codelineno-0-93" name="__codelineno-0-93"></a>
5754
+ <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="c1"># Install `.get_FOO_color()` onto the model using our own version.</span>
5755
+ <a id="__codelineno-0-95" name="__codelineno-0-95"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
5756
+ <a id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="nb">setattr</span><span class="p">(</span>
5757
+ <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="bp">cls</span><span class="p">,</span>
5758
+ <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span><span class="p">,</span>
5759
+ <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_color</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
5760
+ <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="p">)</span>
4416
5761
  </code></pre></div></td></tr></table></div>
4417
5762
  </details>
4418
5763
 
@@ -4451,7 +5796,9 @@ having to define it on the model yourself.</p>
4451
5796
 
4452
5797
  <details class="quote">
4453
5798
  <summary>Source code in <code>nautobot/extras/models/statuses.py</code></summary>
4454
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-53"> 53</a></span>
5799
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-51"> 51</a></span>
5800
+ <span class="normal"><a href="#__codelineno-0-52"> 52</a></span>
5801
+ <span class="normal"><a href="#__codelineno-0-53"> 53</a></span>
4455
5802
  <span class="normal"><a href="#__codelineno-0-54"> 54</a></span>
4456
5803
  <span class="normal"><a href="#__codelineno-0-55"> 55</a></span>
4457
5804
  <span class="normal"><a href="#__codelineno-0-56"> 56</a></span>
@@ -4498,58 +5845,56 @@ having to define it on the model yourself.</p>
4498
5845
  <span class="normal"><a href="#__codelineno-0-97"> 97</a></span>
4499
5846
  <span class="normal"><a href="#__codelineno-0-98"> 98</a></span>
4500
5847
  <span class="normal"><a href="#__codelineno-0-99"> 99</a></span>
4501
- <span class="normal"><a href="#__codelineno-0-100">100</a></span>
4502
- <span class="normal"><a href="#__codelineno-0-101">101</a></span>
4503
- <span class="normal"><a href="#__codelineno-0-102">102</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="k">def</span> <span class="nf">contribute_to_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">cls</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>
4504
- <a id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4505
- <a id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="sd"> Overload default so that we can assert that `.get_FOO_display` is</span>
4506
- <a id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="sd"> attached to any model that is using a `StatusField`.</span>
4507
- <a id="__codelineno-0-57" name="__codelineno-0-57"></a>
4508
- <a id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="sd"> Using `.contribute_to_class()` is how field objects get added to the model</span>
4509
- <a id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="sd"> at during the instance preparation. This is also where any custom model</span>
4510
- <a id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="sd"> methods are hooked in. So in short this method asserts that any time a</span>
4511
- <a id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="sd"> `StatusField` is added to a model, that model also gets a</span>
4512
- <a id="__codelineno-0-62" name="__codelineno-0-62"></a><span class="sd"> `.get_status_display()` and a `.get_status_color()` method without</span>
4513
- <a id="__codelineno-0-63" name="__codelineno-0-63"></a><span class="sd"> having to define it on the model yourself.</span>
4514
- <a id="__codelineno-0-64" name="__codelineno-0-64"></a><span class="sd"> &quot;&quot;&quot;</span>
4515
- <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">contribute_to_class</span><span class="p">(</span><span class="bp">cls</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>
4516
- <a id="__codelineno-0-66" name="__codelineno-0-66"></a>
4517
- <a id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="k">def</span> <span class="nf">_get_FIELD_display</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
4518
- <a id="__codelineno-0-68" name="__codelineno-0-68"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4519
- <a id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="sd"> Closure to replace default model method of the same name.</span>
4520
- <a id="__codelineno-0-70" name="__codelineno-0-70"></a>
4521
- <a id="__codelineno-0-71" name="__codelineno-0-71"></a><span class="sd"> Cargo-culted from `django.db.models.base.Model._get_FIELD_display`</span>
4522
- <a id="__codelineno-0-72" name="__codelineno-0-72"></a><span class="sd"> &quot;&quot;&quot;</span>
4523
- <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="n">choices</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">get_choices</span><span class="p">()</span>
4524
- <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">attname</span><span class="p">)</span>
4525
- <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="n">choices_dict</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">choices</span><span class="p">))</span>
4526
- <a id="__codelineno-0-76" name="__codelineno-0-76"></a> <span class="c1"># force_str() to coerce lazy strings.</span>
4527
- <a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="k">return</span> <span class="n">force_str</span><span class="p">(</span><span class="n">choices_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="n">value</span><span class="p">),</span> <span class="n">strings_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
4528
- <a id="__codelineno-0-78" name="__codelineno-0-78"></a>
4529
- <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="c1"># Install `.get_FOO_display()` onto the model using our own version.</span>
4530
- <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
4531
- <a id="__codelineno-0-81" name="__codelineno-0-81"></a> <span class="nb">setattr</span><span class="p">(</span>
4532
- <a id="__codelineno-0-82" name="__codelineno-0-82"></a> <span class="bp">cls</span><span class="p">,</span>
4533
- <a id="__codelineno-0-83" name="__codelineno-0-83"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span><span class="p">,</span>
4534
- <a id="__codelineno-0-84" name="__codelineno-0-84"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_display</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
4535
- <a id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="p">)</span>
4536
- <a id="__codelineno-0-86" name="__codelineno-0-86"></a>
4537
- <a id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="k">def</span> <span class="nf">_get_FIELD_color</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
4538
- <a id="__codelineno-0-88" name="__codelineno-0-88"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4539
- <a id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="sd"> Return `self.FOO.color` (where FOO is field name).</span>
4540
- <a id="__codelineno-0-90" name="__codelineno-0-90"></a>
4541
- <a id="__codelineno-0-91" name="__codelineno-0-91"></a><span class="sd"> I am added to the model via `StatusField.contribute_to_class()`.</span>
4542
- <a id="__codelineno-0-92" name="__codelineno-0-92"></a><span class="sd"> &quot;&quot;&quot;</span>
4543
- <a id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="n">field_method</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
4544
- <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field_method</span><span class="p">,</span> <span class="s2">&quot;color&quot;</span><span class="p">)</span>
4545
- <a id="__codelineno-0-95" name="__codelineno-0-95"></a>
4546
- <a id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="c1"># Install `.get_FOO_color()` onto the model using our own version.</span>
4547
- <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
4548
- <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="nb">setattr</span><span class="p">(</span>
4549
- <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="bp">cls</span><span class="p">,</span>
4550
- <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span><span class="p">,</span>
4551
- <a id="__codelineno-0-101" name="__codelineno-0-101"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_color</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
4552
- <a id="__codelineno-0-102" name="__codelineno-0-102"></a> <span class="p">)</span>
5848
+ <span class="normal"><a href="#__codelineno-0-100">100</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-51" name="__codelineno-0-51"></a><span class="k">def</span> <span class="nf">contribute_to_class</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="bp">cls</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>
5849
+ <a id="__codelineno-0-52" name="__codelineno-0-52"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5850
+ <a id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="sd"> Overload default so that we can assert that `.get_FOO_display` is</span>
5851
+ <a id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="sd"> attached to any model that is using a `StatusField`.</span>
5852
+ <a id="__codelineno-0-55" name="__codelineno-0-55"></a>
5853
+ <a id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="sd"> Using `.contribute_to_class()` is how field objects get added to the model</span>
5854
+ <a id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="sd"> at during the instance preparation. This is also where any custom model</span>
5855
+ <a id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="sd"> methods are hooked in. So in short this method asserts that any time a</span>
5856
+ <a id="__codelineno-0-59" name="__codelineno-0-59"></a><span class="sd"> `StatusField` is added to a model, that model also gets a</span>
5857
+ <a id="__codelineno-0-60" name="__codelineno-0-60"></a><span class="sd"> `.get_status_display()` and a `.get_status_color()` method without</span>
5858
+ <a id="__codelineno-0-61" name="__codelineno-0-61"></a><span class="sd"> having to define it on the model yourself.</span>
5859
+ <a id="__codelineno-0-62" name="__codelineno-0-62"></a><span class="sd"> &quot;&quot;&quot;</span>
5860
+ <a id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">contribute_to_class</span><span class="p">(</span><span class="bp">cls</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>
5861
+ <a id="__codelineno-0-64" name="__codelineno-0-64"></a>
5862
+ <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="k">def</span> <span class="nf">_get_FIELD_display</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
5863
+ <a id="__codelineno-0-66" name="__codelineno-0-66"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5864
+ <a id="__codelineno-0-67" name="__codelineno-0-67"></a><span class="sd"> Closure to replace default model method of the same name.</span>
5865
+ <a id="__codelineno-0-68" name="__codelineno-0-68"></a>
5866
+ <a id="__codelineno-0-69" name="__codelineno-0-69"></a><span class="sd"> Cargo-culted from `django.db.models.base.Model._get_FIELD_display`</span>
5867
+ <a id="__codelineno-0-70" name="__codelineno-0-70"></a><span class="sd"> &quot;&quot;&quot;</span>
5868
+ <a id="__codelineno-0-71" name="__codelineno-0-71"></a> <span class="n">choices</span> <span class="o">=</span> <span class="n">field</span><span class="o">.</span><span class="n">get_choices</span><span class="p">()</span>
5869
+ <a id="__codelineno-0-72" name="__codelineno-0-72"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">attname</span><span class="p">)</span>
5870
+ <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="n">choices_dict</span> <span class="o">=</span> <span class="nb">dict</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">choices</span><span class="p">))</span>
5871
+ <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="c1"># force_str() to coerce lazy strings.</span>
5872
+ <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="k">return</span> <span class="n">force_str</span><span class="p">(</span><span class="n">choices_dict</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">make_hashable</span><span class="p">(</span><span class="n">value</span><span class="p">),</span> <span class="n">value</span><span class="p">),</span> <span class="n">strings_only</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
5873
+ <a id="__codelineno-0-76" name="__codelineno-0-76"></a>
5874
+ <a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="c1"># Install `.get_FOO_display()` onto the model using our own version.</span>
5875
+ <a id="__codelineno-0-78" name="__codelineno-0-78"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
5876
+ <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="nb">setattr</span><span class="p">(</span>
5877
+ <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="bp">cls</span><span class="p">,</span>
5878
+ <a id="__codelineno-0-81" name="__codelineno-0-81"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_display&quot;</span><span class="p">,</span>
5879
+ <a id="__codelineno-0-82" name="__codelineno-0-82"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_display</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
5880
+ <a id="__codelineno-0-83" name="__codelineno-0-83"></a> <span class="p">)</span>
5881
+ <a id="__codelineno-0-84" name="__codelineno-0-84"></a>
5882
+ <a id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="k">def</span> <span class="nf">_get_FIELD_color</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="p">):</span>
5883
+ <a id="__codelineno-0-86" name="__codelineno-0-86"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5884
+ <a id="__codelineno-0-87" name="__codelineno-0-87"></a><span class="sd"> Return `self.FOO.color` (where FOO is field name).</span>
5885
+ <a id="__codelineno-0-88" name="__codelineno-0-88"></a>
5886
+ <a id="__codelineno-0-89" name="__codelineno-0-89"></a><span class="sd"> I am added to the model via `StatusField.contribute_to_class()`.</span>
5887
+ <a id="__codelineno-0-90" name="__codelineno-0-90"></a><span class="sd"> &quot;&quot;&quot;</span>
5888
+ <a id="__codelineno-0-91" name="__codelineno-0-91"></a> <span class="n">field_method</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">field</span><span class="o">.</span><span class="n">name</span><span class="p">)</span>
5889
+ <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="k">return</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field_method</span><span class="p">,</span> <span class="s2">&quot;color&quot;</span><span class="p">)</span>
5890
+ <a id="__codelineno-0-93" name="__codelineno-0-93"></a>
5891
+ <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="c1"># Install `.get_FOO_color()` onto the model using our own version.</span>
5892
+ <a id="__codelineno-0-95" name="__codelineno-0-95"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="vm">__dict__</span><span class="p">:</span>
5893
+ <a id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="nb">setattr</span><span class="p">(</span>
5894
+ <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="bp">cls</span><span class="p">,</span>
5895
+ <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2">_color&quot;</span><span class="p">,</span>
5896
+ <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="n">partialmethod</span><span class="p">(</span><span class="n">_get_FIELD_color</span><span class="p">,</span> <span class="n">field</span><span class="o">=</span><span class="bp">self</span><span class="p">),</span>
5897
+ <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="p">)</span>
4553
5898
  </code></pre></div></td></tr></table></div>
4554
5899
  </details>
4555
5900
  </div>
@@ -4973,7 +6318,8 @@ having to define it on the model yourself.</p>
4973
6318
 
4974
6319
  <details class="quote">
4975
6320
  <summary>Source code in <code>nautobot/extras/utils.py</code></summary>
4976
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-206">206</a></span>
6321
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-205">205</a></span>
6322
+ <span class="normal"><a href="#__codelineno-0-206">206</a></span>
4977
6323
  <span class="normal"><a href="#__codelineno-0-207">207</a></span>
4978
6324
  <span class="normal"><a href="#__codelineno-0-208">208</a></span>
4979
6325
  <span class="normal"><a href="#__codelineno-0-209">209</a></span>
@@ -4989,25 +6335,24 @@ having to define it on the model yourself.</p>
4989
6335
  <span class="normal"><a href="#__codelineno-0-219">219</a></span>
4990
6336
  <span class="normal"><a href="#__codelineno-0-220">220</a></span>
4991
6337
  <span class="normal"><a href="#__codelineno-0-221">221</a></span>
4992
- <span class="normal"><a href="#__codelineno-0-222">222</a></span>
4993
- <span class="normal"><a href="#__codelineno-0-223">223</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-206" name="__codelineno-0-206"></a><span class="k">def</span> <span class="nf">extras_features</span><span class="p">(</span><span class="o">*</span><span class="n">features</span><span class="p">):</span>
4994
- <a id="__codelineno-0-207" name="__codelineno-0-207"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4995
- <a id="__codelineno-0-208" name="__codelineno-0-208"></a><span class="sd"> Decorator used to register extras provided features to a model</span>
4996
- <a id="__codelineno-0-209" name="__codelineno-0-209"></a><span class="sd"> &quot;&quot;&quot;</span>
4997
- <a id="__codelineno-0-210" name="__codelineno-0-210"></a>
4998
- <a id="__codelineno-0-211" name="__codelineno-0-211"></a> <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="n">model_class</span><span class="p">):</span>
4999
- <a id="__codelineno-0-212" name="__codelineno-0-212"></a> <span class="c1"># Initialize the model_features store if not already defined</span>
5000
- <a id="__codelineno-0-213" name="__codelineno-0-213"></a> <span class="k">if</span> <span class="s2">&quot;model_features&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">registry</span><span class="p">:</span>
5001
- <a id="__codelineno-0-214" name="__codelineno-0-214"></a> <span class="n">registry</span><span class="p">[</span><span class="s2">&quot;model_features&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="n">f</span><span class="p">:</span> <span class="n">collections</span><span class="o">.</span><span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">EXTRAS_FEATURES</span><span class="p">}</span>
5002
- <a id="__codelineno-0-215" name="__codelineno-0-215"></a> <span class="k">for</span> <span class="n">feature</span> <span class="ow">in</span> <span class="n">features</span><span class="p">:</span>
5003
- <a id="__codelineno-0-216" name="__codelineno-0-216"></a> <span class="k">if</span> <span class="n">feature</span> <span class="ow">in</span> <span class="n">EXTRAS_FEATURES</span><span class="p">:</span>
5004
- <a id="__codelineno-0-217" name="__codelineno-0-217"></a> <span class="n">app_label</span><span class="p">,</span> <span class="n">model_name</span> <span class="o">=</span> <span class="n">model_class</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">label_lower</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>
5005
- <a id="__codelineno-0-218" name="__codelineno-0-218"></a> <span class="n">registry</span><span class="p">[</span><span class="s2">&quot;model_features&quot;</span><span class="p">][</span><span class="n">feature</span><span class="p">][</span><span class="n">app_label</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">model_name</span><span class="p">)</span>
5006
- <a id="__codelineno-0-219" name="__codelineno-0-219"></a> <span class="k">else</span><span class="p">:</span>
5007
- <a id="__codelineno-0-220" name="__codelineno-0-220"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">feature</span><span class="si">}</span><span class="s2"> is not a valid extras feature!&quot;</span><span class="p">)</span>
5008
- <a id="__codelineno-0-221" name="__codelineno-0-221"></a> <span class="k">return</span> <span class="n">model_class</span>
5009
- <a id="__codelineno-0-222" name="__codelineno-0-222"></a>
5010
- <a id="__codelineno-0-223" name="__codelineno-0-223"></a> <span class="k">return</span> <span class="n">wrapper</span>
6338
+ <span class="normal"><a href="#__codelineno-0-222">222</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-205" name="__codelineno-0-205"></a><span class="k">def</span> <span class="nf">extras_features</span><span class="p">(</span><span class="o">*</span><span class="n">features</span><span class="p">):</span>
6339
+ <a id="__codelineno-0-206" name="__codelineno-0-206"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6340
+ <a id="__codelineno-0-207" name="__codelineno-0-207"></a><span class="sd"> Decorator used to register extras provided features to a model</span>
6341
+ <a id="__codelineno-0-208" name="__codelineno-0-208"></a><span class="sd"> &quot;&quot;&quot;</span>
6342
+ <a id="__codelineno-0-209" name="__codelineno-0-209"></a>
6343
+ <a id="__codelineno-0-210" name="__codelineno-0-210"></a> <span class="k">def</span> <span class="nf">wrapper</span><span class="p">(</span><span class="n">model_class</span><span class="p">):</span>
6344
+ <a id="__codelineno-0-211" name="__codelineno-0-211"></a> <span class="c1"># Initialize the model_features store if not already defined</span>
6345
+ <a id="__codelineno-0-212" name="__codelineno-0-212"></a> <span class="k">if</span> <span class="s2">&quot;model_features&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">registry</span><span class="p">:</span>
6346
+ <a id="__codelineno-0-213" name="__codelineno-0-213"></a> <span class="n">registry</span><span class="p">[</span><span class="s2">&quot;model_features&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="p">{</span><span class="n">f</span><span class="p">:</span> <span class="n">collections</span><span class="o">.</span><span class="n">defaultdict</span><span class="p">(</span><span class="nb">list</span><span class="p">)</span> <span class="k">for</span> <span class="n">f</span> <span class="ow">in</span> <span class="n">EXTRAS_FEATURES</span><span class="p">}</span>
6347
+ <a id="__codelineno-0-214" name="__codelineno-0-214"></a> <span class="k">for</span> <span class="n">feature</span> <span class="ow">in</span> <span class="n">features</span><span class="p">:</span>
6348
+ <a id="__codelineno-0-215" name="__codelineno-0-215"></a> <span class="k">if</span> <span class="n">feature</span> <span class="ow">in</span> <span class="n">EXTRAS_FEATURES</span><span class="p">:</span>
6349
+ <a id="__codelineno-0-216" name="__codelineno-0-216"></a> <span class="n">app_label</span><span class="p">,</span> <span class="n">model_name</span> <span class="o">=</span> <span class="n">model_class</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">label_lower</span><span class="o">.</span><span class="n">split</span><span class="p">(</span><span class="s2">&quot;.&quot;</span><span class="p">)</span>
6350
+ <a id="__codelineno-0-217" name="__codelineno-0-217"></a> <span class="n">registry</span><span class="p">[</span><span class="s2">&quot;model_features&quot;</span><span class="p">][</span><span class="n">feature</span><span class="p">][</span><span class="n">app_label</span><span class="p">]</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">model_name</span><span class="p">)</span>
6351
+ <a id="__codelineno-0-218" name="__codelineno-0-218"></a> <span class="k">else</span><span class="p">:</span>
6352
+ <a id="__codelineno-0-219" name="__codelineno-0-219"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">feature</span><span class="si">}</span><span class="s2"> is not a valid extras feature!&quot;</span><span class="p">)</span>
6353
+ <a id="__codelineno-0-220" name="__codelineno-0-220"></a> <span class="k">return</span> <span class="n">model_class</span>
6354
+ <a id="__codelineno-0-221" name="__codelineno-0-221"></a>
6355
+ <a id="__codelineno-0-222" name="__codelineno-0-222"></a> <span class="k">return</span> <span class="n">wrapper</span>
5011
6356
  </code></pre></div></td></tr></table></div>
5012
6357
  </details>
5013
6358
  </div>
@@ -5037,42 +6382,6 @@ having to define it on the model yourself.</p>
5037
6382
 
5038
6383
  <footer class="md-footer">
5039
6384
 
5040
-
5041
- <nav class="md-footer__inner md-grid" aria-label="Footer" >
5042
-
5043
-
5044
- <a href="forms.html" class="md-footer__link md-footer__link--prev" aria-label="Previous: nautobot.apps.forms" rel="prev">
5045
- <div class="md-footer__button md-icon">
5046
- <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>
5047
- </div>
5048
- <div class="md-footer__title">
5049
- <div class="md-ellipsis">
5050
- <span class="md-footer__direction">
5051
- Previous
5052
- </span>
5053
- nautobot.apps.forms
5054
- </div>
5055
- </div>
5056
- </a>
5057
-
5058
-
5059
-
5060
- <a href="secrets.html" class="md-footer__link md-footer__link--next" aria-label="Next: nautobot.apps.secrets" rel="next">
5061
- <div class="md-footer__title">
5062
- <div class="md-ellipsis">
5063
- <span class="md-footer__direction">
5064
- Next
5065
- </span>
5066
- nautobot.apps.secrets
5067
- </div>
5068
- </div>
5069
- <div class="md-footer__button md-icon">
5070
- <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>
5071
- </div>
5072
- </a>
5073
-
5074
- </nav>
5075
-
5076
6385
  <div class="md-footer-meta md-typeset">
5077
6386
  <div class="md-footer-meta__inner md-grid">
5078
6387
  <div class="md-copyright">
@@ -5100,32 +6409,42 @@ having to define it on the model yourself.</p>
5100
6409
 
5101
6410
 
5102
6411
 
6412
+
6413
+
5103
6414
  <a href="https://blog.networktocode.com/blog/tags/nautobot" target="_blank" rel="noopener" title="Network to Code Blog" class="md-social__link">
5104
- <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>
6415
+ <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>
5105
6416
  </a>
5106
6417
 
5107
6418
 
5108
6419
 
6420
+
6421
+
5109
6422
  <a href="https://www.youtube.com/playlist?list=PLjA0bhxgryJ2Ts4GJMDA-tPzVWEncv4pb" target="_blank" rel="noopener" title="Nautobot Videos" class="md-social__link">
5110
- <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>
6423
+ <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>
5111
6424
  </a>
5112
6425
 
5113
6426
 
5114
6427
 
6428
+
6429
+
5115
6430
  <a href="https://www.networktocode.com/community/" target="_blank" rel="noopener" title="Network to Code Community" class="md-social__link">
5116
- <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>
6431
+ <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>
5117
6432
  </a>
5118
6433
 
5119
6434
 
5120
6435
 
6436
+
6437
+
5121
6438
  <a href="https://github.com/nautobot/nautobot" target="_blank" rel="noopener" title="GitHub Repo" class="md-social__link">
5122
- <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>
6439
+ <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>
5123
6440
  </a>
5124
6441
 
5125
6442
 
5126
6443
 
6444
+
6445
+
5127
6446
  <a href="https://twitter.com/networktocode" target="_blank" rel="noopener" title="Network to Code Twitter" class="md-social__link">
5128
- <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>
6447
+ <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>
5129
6448
  </a>
5130
6449
 
5131
6450
  </div>
@@ -5139,14 +6458,13 @@ having to define it on the model yourself.</p>
5139
6458
  <div class="md-dialog__inner md-typeset"></div>
5140
6459
  </div>
5141
6460
 
5142
- <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>
6461
+ <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>
5143
6462
 
5144
6463
 
5145
- <script src="../../../assets/javascripts/bundle.5a2dcb6a.min.js"></script>
6464
+ <script src="../../../assets/javascripts/bundle.51198bba.min.js"></script>
5146
6465
 
5147
6466
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
5148
6467
 
5149
6468
 
5150
-
5151
6469
  </body>
5152
6470
  </html>