nautobot 2.0.0a3__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 (780) hide show
  1. nautobot/apps/api.py +6 -8
  2. nautobot/apps/forms.py +0 -2
  3. nautobot/apps/ui.py +0 -8
  4. nautobot/circuits/api/serializers.py +9 -117
  5. nautobot/circuits/api/urls.py +1 -1
  6. nautobot/circuits/api/views.py +0 -1
  7. nautobot/circuits/forms.py +0 -65
  8. nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
  9. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  10. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  11. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  12. nautobot/circuits/models.py +3 -87
  13. nautobot/circuits/navigation.py +14 -69
  14. nautobot/circuits/signals.py +0 -2
  15. nautobot/circuits/tables.py +39 -1
  16. nautobot/circuits/tests/integration/test_relationships.py +9 -9
  17. nautobot/circuits/tests/test_api.py +4 -8
  18. nautobot/circuits/tests/test_filters.py +10 -4
  19. nautobot/circuits/tests/test_models.py +5 -1
  20. nautobot/circuits/tests/test_views.py +27 -5
  21. nautobot/circuits/views.py +18 -10
  22. nautobot/core/api/__init__.py +8 -2
  23. nautobot/core/api/fields.py +15 -6
  24. nautobot/core/api/filter_backends.py +3 -2
  25. nautobot/core/api/metadata.py +237 -30
  26. nautobot/core/api/mixins.py +94 -0
  27. nautobot/core/api/pagination.py +4 -0
  28. nautobot/core/api/parsers.py +154 -0
  29. nautobot/core/api/renderers.py +153 -2
  30. nautobot/core/api/schema.py +46 -2
  31. nautobot/core/api/serializers.py +377 -35
  32. nautobot/core/api/urls.py +11 -3
  33. nautobot/core/api/utils.py +174 -2
  34. nautobot/core/api/versioning.py +32 -10
  35. nautobot/core/api/views.py +266 -72
  36. nautobot/core/apps/__init__.py +138 -220
  37. nautobot/core/celery/__init__.py +112 -41
  38. nautobot/core/celery/backends.py +19 -12
  39. nautobot/core/celery/control.py +46 -0
  40. nautobot/core/celery/encoders.py +53 -0
  41. nautobot/core/celery/log.py +38 -0
  42. nautobot/core/celery/schedulers.py +23 -4
  43. nautobot/core/celery/task.py +1 -16
  44. nautobot/core/checks.py +0 -27
  45. nautobot/core/choices.py +0 -113
  46. nautobot/core/{cli.py → cli/__init__.py} +1 -1
  47. nautobot/core/cli/__main__.py +3 -0
  48. nautobot/core/constants.py +0 -24
  49. nautobot/core/context_processors.py +12 -0
  50. nautobot/core/filters.py +2 -2
  51. nautobot/core/forms/__init__.py +0 -4
  52. nautobot/core/forms/fields.py +38 -65
  53. nautobot/core/forms/forms.py +4 -1
  54. nautobot/core/forms/utils.py +0 -52
  55. nautobot/core/graphql/schema.py +4 -27
  56. nautobot/core/jobs/__init__.py +75 -0
  57. nautobot/core/management/commands/build_ui.py +255 -0
  58. nautobot/core/management/commands/generate_test_data.py +3 -2
  59. nautobot/core/management/commands/post_upgrade.py +24 -24
  60. nautobot/core/models/__init__.py +26 -1
  61. nautobot/core/models/fields.py +24 -5
  62. nautobot/core/models/generics.py +2 -42
  63. nautobot/core/models/managers.py +5 -0
  64. nautobot/core/models/name_color_content_types.py +0 -14
  65. nautobot/core/models/tree_queries.py +14 -4
  66. nautobot/core/models/utils.py +5 -6
  67. nautobot/core/models/validators.py +17 -8
  68. nautobot/core/releases.py +8 -10
  69. nautobot/core/settings.py +80 -42
  70. nautobot/core/tables.py +5 -5
  71. nautobot/core/tasks.py +4 -7
  72. nautobot/core/templates/base.html +1 -49
  73. nautobot/core/templates/base_django.html +49 -0
  74. nautobot/core/templates/base_react.html +55 -0
  75. nautobot/core/templates/buttons/export.html +6 -4
  76. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  77. nautobot/core/templates/generic/object_list.html +3 -1
  78. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  79. nautobot/core/templates/inc/footer.html +1 -0
  80. nautobot/core/templates/inc/javascript.html +0 -14
  81. nautobot/core/templates/inc/nav_menu.html +28 -33
  82. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  83. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  84. nautobot/core/templates/nautobot_config.py.j2 +8 -20
  85. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  86. nautobot/core/templates/rest_framework/api.html +8 -0
  87. nautobot/core/templatetags/buttons.py +32 -28
  88. nautobot/core/testing/__init__.py +47 -44
  89. nautobot/core/testing/api.py +362 -47
  90. nautobot/core/testing/filters.py +1 -1
  91. nautobot/core/testing/migrations.py +2 -0
  92. nautobot/core/testing/mixins.py +22 -9
  93. nautobot/core/testing/schema.py +2 -1
  94. nautobot/core/testing/views.py +21 -46
  95. nautobot/core/tests/integration/test_filters.py +17 -8
  96. nautobot/core/tests/integration/test_navbar.py +11 -34
  97. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  98. nautobot/core/tests/nautobot_config.py +2 -3
  99. nautobot/core/tests/test_api.py +290 -21
  100. nautobot/core/tests/test_checks.py +0 -7
  101. nautobot/core/tests/test_filters.py +107 -59
  102. nautobot/core/tests/test_forms.py +26 -92
  103. nautobot/core/tests/test_graphql.py +110 -77
  104. nautobot/core/tests/test_logging.py +4 -0
  105. nautobot/core/tests/test_managers.py +3 -1
  106. nautobot/core/tests/test_models.py +2 -0
  107. nautobot/core/tests/test_paginator.py +3 -1
  108. nautobot/core/tests/test_releases.py +12 -12
  109. nautobot/core/tests/test_templatetags_helpers.py +4 -4
  110. nautobot/core/tests/test_utils.py +32 -68
  111. nautobot/core/tests/test_views.py +12 -15
  112. nautobot/core/utils/data.py +17 -0
  113. nautobot/core/utils/deprecation.py +9 -6
  114. nautobot/core/utils/filtering.py +8 -3
  115. nautobot/core/utils/git.py +12 -4
  116. nautobot/core/utils/lookup.py +3 -1
  117. nautobot/core/utils/requests.py +1 -104
  118. nautobot/core/views/__init__.py +1 -0
  119. nautobot/core/views/generic.py +75 -110
  120. nautobot/core/views/mixins.py +52 -61
  121. nautobot/core/views/renderers.py +6 -7
  122. nautobot/core/views/utils.py +80 -0
  123. nautobot/dcim/api/serializers.py +160 -667
  124. nautobot/dcim/api/urls.py +1 -1
  125. nautobot/dcim/api/views.py +7 -44
  126. nautobot/dcim/choices.py +2 -0
  127. nautobot/dcim/filters/__init__.py +21 -0
  128. nautobot/dcim/form_mixins.py +1 -27
  129. nautobot/dcim/forms.py +19 -765
  130. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
  131. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
  132. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
  133. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
  134. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  135. nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
  136. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
  137. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  138. nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
  139. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  140. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  141. nautobot/dcim/models/cables.py +3 -33
  142. nautobot/dcim/models/device_component_templates.py +6 -0
  143. nautobot/dcim/models/device_components.py +12 -198
  144. nautobot/dcim/models/devices.py +30 -143
  145. nautobot/dcim/models/locations.py +3 -64
  146. nautobot/dcim/models/power.py +3 -50
  147. nautobot/dcim/models/racks.py +7 -84
  148. nautobot/dcim/navigation.py +141 -467
  149. nautobot/dcim/signals.py +0 -2
  150. nautobot/dcim/tables/locations.py +2 -2
  151. nautobot/dcim/tables/power.py +1 -2
  152. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  153. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  154. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  155. nautobot/dcim/templates/dcim/location.html +16 -1
  156. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  157. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  158. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  159. nautobot/dcim/tests/test_api.py +166 -81
  160. nautobot/dcim/tests/test_cablepaths.py +41 -35
  161. nautobot/dcim/tests/test_filters.py +67 -23
  162. nautobot/dcim/tests/test_forms.py +5 -205
  163. nautobot/dcim/tests/test_graphql.py +7 -2
  164. nautobot/dcim/tests/test_migrations.py +6 -11
  165. nautobot/dcim/tests/test_models.py +182 -110
  166. nautobot/dcim/tests/test_natural_ordering.py +11 -8
  167. nautobot/dcim/tests/test_signals.py +6 -3
  168. nautobot/dcim/tests/test_views.py +197 -175
  169. nautobot/dcim/urls.py +11 -16
  170. nautobot/dcim/views.py +7 -134
  171. nautobot/docs/additional-features/caching.md +6 -87
  172. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  173. nautobot/docs/additional-features/jobs.md +177 -195
  174. nautobot/docs/administration/nautobot-server.md +6 -21
  175. nautobot/docs/administration/replicating-nautobot.md +0 -10
  176. nautobot/docs/configuration/optional-settings.md +32 -41
  177. nautobot/docs/configuration/required-settings.md +11 -52
  178. nautobot/docs/development/application-registry.md +2 -13
  179. nautobot/docs/development/extending-models.md +15 -17
  180. nautobot/docs/development/generic-views.md +0 -2
  181. nautobot/docs/development/getting-started.md +55 -5
  182. nautobot/docs/development/navigation-menu.md +22 -93
  183. nautobot/docs/development/react-ui.md +105 -0
  184. nautobot/docs/development/role-internals.md +1 -3
  185. nautobot/docs/development/style-guide.md +6 -4
  186. nautobot/docs/index.md +3 -2
  187. nautobot/docs/installation/migrating-from-netbox.md +11 -42
  188. nautobot/docs/installation/nautobot.md +1 -1
  189. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  190. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  191. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  192. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  193. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  194. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  195. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  196. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  197. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  198. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  199. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  200. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  201. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  202. nautobot/docs/installation/upgrading-from-nautobot-v1.md +170 -747
  203. nautobot/docs/models/dcim/device.md +3 -0
  204. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  205. nautobot/docs/models/extras/computedfield.md +4 -4
  206. nautobot/docs/models/extras/gitrepository.md +3 -0
  207. nautobot/docs/models/extras/job.md +1 -0
  208. nautobot/docs/models/extras/jobbutton.md +18 -13
  209. nautobot/docs/models/extras/jobhook.md +7 -4
  210. nautobot/docs/models/extras/jobresult.md +6 -2
  211. nautobot/docs/models/extras/relationship.md +2 -2
  212. nautobot/docs/models/extras/status.md +6 -19
  213. nautobot/docs/models/ipam/ipaddress.md +3 -0
  214. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  215. nautobot/docs/plugins/development.md +83 -21
  216. nautobot/docs/release-notes/version-1.5.md +53 -0
  217. nautobot/docs/release-notes/version-2.0.md +180 -0
  218. nautobot/docs/requirements.txt +1 -0
  219. nautobot/docs/rest-api/overview.md +384 -215
  220. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  221. nautobot/extras/admin.py +3 -5
  222. nautobot/extras/api/customfields.py +15 -39
  223. nautobot/extras/api/fields.py +0 -11
  224. nautobot/extras/api/mixins.py +45 -0
  225. nautobot/extras/api/relationships.py +63 -158
  226. nautobot/extras/api/serializers.py +165 -700
  227. nautobot/extras/api/urls.py +1 -1
  228. nautobot/extras/api/views.py +294 -280
  229. nautobot/extras/apps.py +4 -7
  230. nautobot/extras/choices.py +11 -9
  231. nautobot/extras/constants.py +9 -3
  232. nautobot/extras/datasources/__init__.py +2 -0
  233. nautobot/extras/datasources/git.py +135 -186
  234. nautobot/extras/datasources/registry.py +25 -35
  235. nautobot/extras/filters/__init__.py +20 -19
  236. nautobot/extras/filters/mixins.py +4 -4
  237. nautobot/extras/forms/forms.py +63 -127
  238. nautobot/extras/forms/mixins.py +23 -51
  239. nautobot/extras/health_checks.py +0 -33
  240. nautobot/extras/jobs.py +387 -565
  241. nautobot/extras/management/commands/runjob.py +24 -62
  242. nautobot/extras/managers.py +30 -7
  243. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  244. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -1
  245. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
  246. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
  247. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
  248. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
  249. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
  250. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  251. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
  252. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
  253. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
  254. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
  255. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  256. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -1
  257. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  258. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -9
  259. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
  260. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  261. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  262. 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
  263. nautobot/extras/migrations/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
  264. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  265. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  266. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  267. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  268. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  269. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  270. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  271. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  272. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  273. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  274. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  275. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  276. nautobot/extras/models/__init__.py +2 -3
  277. nautobot/extras/models/change_logging.py +0 -36
  278. nautobot/extras/models/customfields.py +39 -33
  279. nautobot/extras/models/datasources.py +48 -50
  280. nautobot/extras/models/groups.py +5 -6
  281. nautobot/extras/models/jobs.py +189 -321
  282. nautobot/extras/models/mixins.py +0 -71
  283. nautobot/extras/models/models.py +0 -19
  284. nautobot/extras/models/relationships.py +19 -13
  285. nautobot/extras/models/roles.py +0 -34
  286. nautobot/extras/models/secrets.py +2 -26
  287. nautobot/extras/models/statuses.py +6 -5
  288. nautobot/extras/models/tags.py +2 -17
  289. nautobot/extras/navigation.py +89 -307
  290. nautobot/extras/plugins/__init__.py +3 -120
  291. nautobot/extras/plugins/utils.py +0 -3
  292. nautobot/extras/plugins/validators.py +5 -4
  293. nautobot/extras/plugins/views.py +16 -3
  294. nautobot/extras/querysets.py +1 -7
  295. nautobot/extras/registry.py +3 -0
  296. nautobot/extras/signals.py +26 -60
  297. nautobot/extras/tables.py +34 -40
  298. nautobot/extras/tasks.py +0 -12
  299. nautobot/extras/templates/extras/configcontext.html +1 -1
  300. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  301. nautobot/extras/templates/extras/customfield.html +0 -13
  302. nautobot/extras/templates/extras/gitrepository.html +3 -3
  303. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  304. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  305. nautobot/extras/templates/extras/job.html +35 -25
  306. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  307. nautobot/extras/templates/extras/job_detail.html +13 -31
  308. nautobot/extras/templates/extras/job_edit.html +15 -17
  309. nautobot/extras/templates/extras/jobresult.html +24 -6
  310. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  311. nautobot/extras/templates/extras/secret.html +28 -0
  312. nautobot/extras/templatetags/job_buttons.py +1 -0
  313. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  314. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  315. nautobot/extras/test_jobs/dry_run.py +29 -0
  316. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  317. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  318. nautobot/extras/test_jobs/fail.py +23 -0
  319. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  320. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  321. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  322. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  323. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  324. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  325. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  326. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  327. nautobot/extras/test_jobs/job_variables.py +88 -0
  328. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  329. nautobot/extras/test_jobs/log_redaction.py +20 -0
  330. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  331. nautobot/extras/test_jobs/modify_db.py +25 -0
  332. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  333. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  334. nautobot/extras/test_jobs/object_var_required.py +21 -0
  335. nautobot/extras/test_jobs/object_vars.py +26 -0
  336. nautobot/extras/test_jobs/pass.py +25 -0
  337. nautobot/extras/test_jobs/profiling.py +32 -0
  338. nautobot/extras/test_jobs/read_only_job.py +15 -0
  339. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  340. 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
  341. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  342. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  343. nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
  344. nautobot/extras/tests/integration/test_customfields.py +4 -2
  345. nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
  346. nautobot/extras/tests/integration/test_jobs.py +25 -27
  347. nautobot/extras/tests/integration/test_notes.py +8 -4
  348. nautobot/extras/tests/integration/test_relationships.py +2 -2
  349. nautobot/extras/tests/test_api.py +649 -642
  350. nautobot/extras/tests/test_changelog.py +3 -3
  351. nautobot/extras/tests/test_context_managers.py +5 -3
  352. nautobot/extras/tests/test_customfields.py +92 -50
  353. nautobot/extras/tests/test_datasources.py +189 -112
  354. nautobot/extras/tests/test_dynamicgroups.py +7 -8
  355. nautobot/extras/tests/test_filters.py +137 -89
  356. nautobot/extras/tests/test_forms.py +73 -75
  357. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  358. nautobot/extras/tests/test_jobs.py +262 -263
  359. nautobot/extras/tests/test_migrations.py +4 -3
  360. nautobot/extras/tests/test_models.py +116 -161
  361. nautobot/extras/tests/test_plugins.py +38 -60
  362. nautobot/extras/tests/test_relationships.py +167 -120
  363. nautobot/extras/tests/test_tags.py +6 -11
  364. nautobot/extras/tests/test_utils.py +31 -1
  365. nautobot/extras/tests/test_views.py +201 -145
  366. nautobot/extras/tests/test_webhooks.py +6 -2
  367. nautobot/extras/urls.py +42 -42
  368. nautobot/extras/utils.py +137 -163
  369. nautobot/extras/views.py +78 -152
  370. nautobot/ipam/api/fields.py +17 -0
  371. nautobot/ipam/api/serializers.py +58 -164
  372. nautobot/ipam/api/urls.py +1 -1
  373. nautobot/ipam/api/views.py +3 -2
  374. nautobot/ipam/apps.py +1 -2
  375. nautobot/ipam/filters.py +1 -10
  376. nautobot/ipam/forms.py +4 -177
  377. nautobot/ipam/lookups.py +1 -0
  378. nautobot/ipam/management/commands/__init__.py +0 -0
  379. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  380. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
  381. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
  382. nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
  383. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
  384. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  385. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  386. nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
  387. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  388. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  389. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  390. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  391. nautobot/ipam/models.py +100 -236
  392. nautobot/ipam/navigation.py +36 -181
  393. nautobot/ipam/querysets.py +20 -25
  394. nautobot/ipam/signals.py +49 -6
  395. nautobot/ipam/tables.py +10 -3
  396. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  397. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  398. nautobot/ipam/templates/ipam/namespace_retrieve.html +17 -4
  399. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  400. nautobot/ipam/templates/ipam/prefix.html +1 -1
  401. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  402. nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
  403. nautobot/ipam/tests/integration/test_prefixes.py +3 -26
  404. nautobot/ipam/tests/test_api.py +22 -19
  405. nautobot/ipam/tests/test_filters.py +59 -23
  406. nautobot/ipam/tests/test_migrations.py +6 -10
  407. nautobot/ipam/tests/test_models.py +323 -198
  408. nautobot/ipam/tests/test_ordering.py +2 -2
  409. nautobot/ipam/tests/test_querysets.py +44 -24
  410. nautobot/ipam/tests/test_views.py +73 -26
  411. nautobot/ipam/urls.py +16 -0
  412. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  413. nautobot/ipam/utils/migrations.py +713 -0
  414. nautobot/ipam/views.py +137 -20
  415. nautobot/project-static/docs/404.html +1178 -10
  416. nautobot/project-static/docs/additional-features/caching.html +1224 -159
  417. nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
  418. nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
  419. nautobot/project-static/docs/additional-features/graphql.html +1179 -11
  420. nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
  421. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
  422. nautobot/project-static/docs/additional-features/jobs.html +1514 -328
  423. nautobot/project-static/docs/additional-features/napalm.html +1180 -12
  424. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
  425. nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
  426. nautobot/project-static/docs/administration/celery-queues.html +1178 -10
  427. nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
  428. nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
  429. nautobot/project-static/docs/administration/permissions.html +1178 -10
  430. nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
  431. nautobot/project-static/docs/apps/index.html +1178 -10
  432. nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
  433. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
  434. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
  435. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
  436. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
  437. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
  438. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
  439. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
  440. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
  441. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
  442. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
  443. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
  444. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
  445. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
  446. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
  447. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
  448. nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
  449. nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
  450. nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
  451. nautobot/project-static/docs/configuration/index.html +1178 -10
  452. nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
  453. nautobot/project-static/docs/configuration/required-settings.html +1312 -211
  454. nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
  455. nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
  456. nautobot/project-static/docs/core-functionality/devices.html +1182 -10
  457. nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
  458. nautobot/project-static/docs/core-functionality/power.html +1178 -10
  459. nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
  460. nautobot/project-static/docs/core-functionality/services.html +1178 -10
  461. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
  462. nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
  463. nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
  464. nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
  465. nautobot/project-static/docs/development/application-registry.html +1190 -42
  466. nautobot/project-static/docs/development/best-practices.html +1178 -10
  467. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
  468. nautobot/project-static/docs/development/extending-models.html +1238 -83
  469. nautobot/project-static/docs/development/generic-views.html +1180 -14
  470. nautobot/project-static/docs/development/getting-started.html +1365 -90
  471. nautobot/project-static/docs/development/homepage.html +1178 -10
  472. nautobot/project-static/docs/development/index.html +1178 -10
  473. nautobot/project-static/docs/development/model-features.html +1178 -10
  474. nautobot/project-static/docs/development/natural-keys.html +1178 -10
  475. nautobot/project-static/docs/development/navigation-menu.html +1215 -125
  476. nautobot/project-static/docs/development/react-ui.html +4199 -0
  477. nautobot/project-static/docs/development/release-checklist.html +1178 -10
  478. nautobot/project-static/docs/development/role-internals.html +1179 -12
  479. nautobot/project-static/docs/development/style-guide.html +1188 -19
  480. nautobot/project-static/docs/development/templates.html +1178 -10
  481. nautobot/project-static/docs/development/testing.html +1178 -10
  482. nautobot/project-static/docs/development/user-preferences.html +1178 -10
  483. nautobot/project-static/docs/docker/index.html +1178 -10
  484. nautobot/project-static/docs/index.html +1183 -12
  485. nautobot/project-static/docs/installation/centos.html +1178 -10
  486. nautobot/project-static/docs/installation/external-authentication.html +1178 -10
  487. nautobot/project-static/docs/installation/http-server.html +1178 -10
  488. nautobot/project-static/docs/installation/index.html +1178 -10
  489. nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
  490. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
  491. nautobot/project-static/docs/installation/nautobot.html +1179 -11
  492. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
  493. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
  494. nautobot/project-static/docs/installation/services.html +1178 -10
  495. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  496. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  497. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  498. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  499. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  500. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  501. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  502. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  503. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  504. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  505. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  506. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  507. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  508. nautobot/project-static/docs/installation/ubuntu.html +1178 -10
  509. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
  510. nautobot/project-static/docs/installation/upgrading.html +1178 -10
  511. nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
  512. nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
  513. nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
  514. nautobot/project-static/docs/models/circuits/provider.html +1293 -103
  515. nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
  516. nautobot/project-static/docs/models/dcim/cable.html +1324 -103
  517. nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
  518. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
  519. nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
  520. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
  521. nautobot/project-static/docs/models/dcim/device.html +1326 -132
  522. nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
  523. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
  524. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
  525. nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
  526. nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
  527. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
  528. nautobot/project-static/docs/models/dcim/interface.html +1293 -103
  529. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
  530. nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
  531. nautobot/project-static/docs/models/dcim/location.html +1293 -103
  532. nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
  533. nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
  534. nautobot/project-static/docs/models/dcim/platform.html +1272 -82
  535. nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
  536. nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
  537. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
  538. nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
  539. nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
  540. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
  541. nautobot/project-static/docs/models/dcim/rack.html +1272 -82
  542. nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
  543. nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
  544. nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
  545. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
  546. nautobot/project-static/docs/models/dcim/region.html +1178 -10
  547. nautobot/project-static/docs/models/dcim/site.html +1178 -10
  548. nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
  549. nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
  550. nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
  551. nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
  552. nautobot/project-static/docs/models/extras/customfield.html +1180 -12
  553. nautobot/project-static/docs/models/extras/customlink.html +1180 -12
  554. nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
  555. nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
  556. nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
  557. nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
  558. nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
  559. nautobot/project-static/docs/models/extras/job.html +1277 -86
  560. nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
  561. nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
  562. nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
  563. nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
  564. nautobot/project-static/docs/models/extras/note.html +1180 -12
  565. nautobot/project-static/docs/models/extras/relationship.html +1182 -14
  566. nautobot/project-static/docs/models/extras/role.html +1320 -86
  567. nautobot/project-static/docs/models/extras/secret.html +1314 -86
  568. nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
  569. nautobot/project-static/docs/models/extras/status.html +1188 -59
  570. nautobot/project-static/docs/models/extras/tag.html +1180 -12
  571. nautobot/project-static/docs/models/extras/webhook.html +1180 -12
  572. nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
  573. nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
  574. nautobot/project-static/docs/models/ipam/rir.html +1276 -86
  575. nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
  576. nautobot/project-static/docs/models/ipam/service.html +1276 -86
  577. nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
  578. nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
  579. nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
  580. nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
  581. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
  582. nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
  583. nautobot/project-static/docs/models/users/token.html +1276 -86
  584. nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
  585. nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
  586. nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
  587. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
  588. nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
  589. nautobot/project-static/docs/objects.inv +0 -0
  590. nautobot/project-static/docs/plugins/development.html +1726 -495
  591. nautobot/project-static/docs/plugins/index.html +1178 -10
  592. nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
  593. nautobot/project-static/docs/release-notes/index.html +1178 -10
  594. nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
  595. nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
  596. nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
  597. nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
  598. nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
  599. nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
  600. nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
  601. nautobot/project-static/docs/requirements.txt +1 -0
  602. nautobot/project-static/docs/rest-api/authentication.html +1179 -11
  603. nautobot/project-static/docs/rest-api/filtering.html +1178 -10
  604. nautobot/project-static/docs/rest-api/overview.html +1841 -446
  605. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  606. nautobot/project-static/docs/search/search_index.json +1 -1
  607. nautobot/project-static/docs/sitemap.xml +197 -187
  608. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  609. nautobot/project-static/docs/user-guides/custom-fields.html +1178 -10
  610. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
  611. nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
  612. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
  613. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
  614. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
  615. nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
  616. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
  617. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
  618. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
  619. nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
  620. nautobot/project-static/docs/user-guides/graphql.html +1178 -10
  621. nautobot/project-static/docs/user-guides/relationships.html +1178 -10
  622. nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
  623. nautobot/project-static/js/forms.js +16 -9
  624. nautobot/project-static/js/theme.js +5 -0
  625. nautobot/tenancy/api/serializers.py +4 -32
  626. nautobot/tenancy/api/urls.py +1 -1
  627. nautobot/tenancy/forms.py +0 -28
  628. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  629. nautobot/tenancy/models.py +0 -25
  630. nautobot/tenancy/navigation.py +6 -39
  631. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  632. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  633. nautobot/tenancy/tests/test_api.py +1 -3
  634. nautobot/tenancy/tests/test_filters.py +10 -5
  635. nautobot/tenancy/views.py +0 -2
  636. nautobot/ui/.eslintignore +6 -0
  637. nautobot/ui/.gitignore +10 -0
  638. nautobot/ui/.prettierignore +9 -0
  639. nautobot/ui/.prettierrc +4 -0
  640. nautobot/ui/README.md +33 -0
  641. nautobot/ui/app_imports.js.j2 +7 -0
  642. nautobot/ui/craco.config.js +46 -0
  643. nautobot/ui/jsconfig-base.json +11 -0
  644. nautobot/ui/jsconfig.json +5 -0
  645. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  646. nautobot/ui/package-lock.json +21451 -0
  647. nautobot/ui/package.json +70 -0
  648. nautobot/ui/public/index.html +47 -0
  649. nautobot/ui/public/logo192.png +0 -0
  650. nautobot/ui/public/logo512.png +0 -0
  651. nautobot/ui/public/manifest.json +25 -0
  652. nautobot/ui/public/nautobot_logo.svg +131 -0
  653. nautobot/ui/public/robots.txt +3 -0
  654. nautobot/ui/src/App.js +71 -0
  655. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  656. nautobot/ui/src/components/AppTab.js +40 -0
  657. nautobot/ui/src/components/Apps.js +60 -0
  658. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  659. nautobot/ui/src/components/HomePanel.js +58 -0
  660. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  661. nautobot/ui/src/components/Layout.js +53 -0
  662. nautobot/ui/src/components/LoadingWidget.js +25 -0
  663. nautobot/ui/src/components/Navbar.js +116 -0
  664. nautobot/ui/src/components/NotificationPopover.js +27 -0
  665. nautobot/ui/src/components/ObjectListTable.js +209 -0
  666. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  667. nautobot/ui/src/components/RouterButton.js +10 -0
  668. nautobot/ui/src/components/RouterLink.js +10 -0
  669. nautobot/ui/src/components/SidebarNav.js +147 -0
  670. nautobot/ui/src/components/Table.js +48 -0
  671. nautobot/ui/src/components/TableItem.js +71 -0
  672. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  673. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  674. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  675. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  676. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  677. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  678. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  679. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  680. nautobot/ui/src/components/pagination.js +93 -0
  681. nautobot/ui/src/components/paginator.js +79 -0
  682. nautobot/ui/src/components/paginator_form.js +43 -0
  683. nautobot/ui/src/components/usePagination.js +57 -0
  684. nautobot/ui/src/constants/apiPath.js +10 -0
  685. nautobot/ui/src/constants/icons.js +15 -0
  686. nautobot/ui/src/constants/size.js +15 -0
  687. nautobot/ui/src/index.js +65 -0
  688. nautobot/ui/src/reportWebVitals.js +15 -0
  689. nautobot/ui/src/router.js +77 -0
  690. nautobot/ui/src/utils/api.js +131 -0
  691. nautobot/ui/src/utils/app-import.js +15 -0
  692. nautobot/ui/src/utils/color.js +15 -0
  693. nautobot/ui/src/utils/date.js +14 -0
  694. nautobot/ui/src/utils/index.js +15 -0
  695. nautobot/ui/src/utils/navigation.js +32 -0
  696. nautobot/ui/src/utils/session.js +64 -0
  697. nautobot/ui/src/utils/store.js +242 -0
  698. nautobot/ui/src/utils/string.js +6 -0
  699. nautobot/ui/src/utils/url.js +4 -0
  700. nautobot/ui/src/views/Home.js +138 -0
  701. nautobot/ui/src/views/InstalledApps.js +80 -0
  702. nautobot/ui/src/views/Login.js +48 -0
  703. nautobot/ui/src/views/Logout.js +20 -0
  704. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  705. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  706. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  707. nautobot/ui/src/views/generic/GenericView.js +142 -0
  708. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  709. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  710. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  711. nautobot/users/admin.py +1 -1
  712. nautobot/users/api/serializers.py +51 -61
  713. nautobot/users/api/urls.py +1 -1
  714. nautobot/users/api/views.py +53 -2
  715. nautobot/users/tests/test_api.py +110 -25
  716. nautobot/virtualization/api/serializers.py +18 -130
  717. nautobot/virtualization/api/urls.py +1 -1
  718. nautobot/virtualization/api/views.py +1 -22
  719. nautobot/virtualization/forms.py +13 -99
  720. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
  721. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
  722. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
  723. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
  724. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  725. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  726. nautobot/virtualization/migrations/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
  727. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  728. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  729. nautobot/virtualization/models.py +31 -123
  730. nautobot/virtualization/navigation.py +18 -99
  731. nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
  732. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  733. nautobot/virtualization/tests/test_api.py +25 -26
  734. nautobot/virtualization/tests/test_filters.py +41 -15
  735. nautobot/virtualization/tests/test_models.py +31 -7
  736. nautobot/virtualization/tests/test_views.py +42 -25
  737. nautobot/virtualization/views.py +7 -6
  738. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
  739. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
  740. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  741. nautobot/circuits/api/nested_serializers.py +0 -69
  742. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  743. nautobot/dcim/api/nested_serializers.py +0 -356
  744. nautobot/dcim/templates/dcim/device_import.html +0 -5
  745. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  746. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  747. nautobot/extras/api/nested_serializers.py +0 -353
  748. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -41
  749. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
  750. nautobot/extras/reports.py +0 -60
  751. nautobot/extras/scripts.py +0 -72
  752. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  753. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  754. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  755. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  756. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  757. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  758. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  759. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  760. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  761. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -18
  762. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  763. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  764. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  765. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  766. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  767. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  768. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  769. nautobot/ipam/api/nested_serializers.py +0 -159
  770. nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
  771. nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
  772. nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
  773. nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
  774. nautobot/tenancy/api/nested_serializers.py +0 -31
  775. nautobot/users/api/nested_serializers.py +0 -67
  776. nautobot/virtualization/api/nested_serializers.py +0 -65
  777. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  778. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  779. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  780. {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -1346,12 +1346,1166 @@
1346
1346
 
1347
1347
 
1348
1348
  <label class="md-nav__link" for="__nav_2_8" id="__nav_2_8_label" tabindex="0">
1349
+ Model Details
1350
+ <span class="md-nav__icon md-icon"></span>
1351
+ </label>
1352
+
1353
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
1354
+ <label class="md-nav__title" for="__nav_2_8">
1355
+ <span class="md-nav__icon md-icon"></span>
1356
+ Model Details
1357
+ </label>
1358
+ <ul class="md-nav__list" data-md-scrollfix>
1359
+
1360
+
1361
+
1362
+
1363
+
1364
+
1365
+
1366
+ <li class="md-nav__item md-nav__item--nested">
1367
+
1368
+
1369
+
1370
+
1371
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_1" >
1372
+
1373
+
1374
+
1375
+ <label class="md-nav__link" for="__nav_2_8_1" id="__nav_2_8_1_label" tabindex="0">
1376
+ Circuits
1377
+ <span class="md-nav__icon md-icon"></span>
1378
+ </label>
1379
+
1380
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_1_label" aria-expanded="false">
1381
+ <label class="md-nav__title" for="__nav_2_8_1">
1382
+ <span class="md-nav__icon md-icon"></span>
1383
+ Circuits
1384
+ </label>
1385
+ <ul class="md-nav__list" data-md-scrollfix>
1386
+
1387
+
1388
+
1389
+
1390
+
1391
+
1392
+ <li class="md-nav__item">
1393
+ <a href="../../../models/circuits/circuit.html" class="md-nav__link">
1394
+ Circuit
1395
+ </a>
1396
+ </li>
1397
+
1398
+
1399
+
1400
+
1401
+
1402
+
1403
+
1404
+
1405
+
1406
+ <li class="md-nav__item">
1407
+ <a href="../../../models/circuits/circuittermination.html" class="md-nav__link">
1408
+ Circuit Termination
1409
+ </a>
1410
+ </li>
1411
+
1412
+
1413
+
1414
+
1415
+
1416
+
1417
+
1418
+
1419
+
1420
+ <li class="md-nav__item">
1421
+ <a href="../../../models/circuits/circuittype.html" class="md-nav__link">
1422
+ Circuit Type
1423
+ </a>
1424
+ </li>
1425
+
1426
+
1427
+
1428
+
1429
+
1430
+
1431
+
1432
+
1433
+
1434
+ <li class="md-nav__item">
1435
+ <a href="../../../models/circuits/provider.html" class="md-nav__link">
1436
+ Circuit Provider
1437
+ </a>
1438
+ </li>
1439
+
1440
+
1441
+
1442
+
1443
+
1444
+
1445
+
1446
+
1447
+
1448
+ <li class="md-nav__item">
1449
+ <a href="../../../models/circuits/providernetwork.html" class="md-nav__link">
1450
+ Circuit Provider Network
1451
+ </a>
1452
+ </li>
1453
+
1454
+
1455
+
1456
+
1457
+ </ul>
1458
+ </nav>
1459
+ </li>
1460
+
1461
+
1462
+
1463
+
1464
+
1465
+
1466
+
1467
+
1468
+
1469
+
1470
+ <li class="md-nav__item md-nav__item--nested">
1471
+
1472
+
1473
+
1474
+
1475
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_2" >
1476
+
1477
+
1478
+
1479
+ <label class="md-nav__link" for="__nav_2_8_2" id="__nav_2_8_2_label" tabindex="0">
1480
+ DCIM
1481
+ <span class="md-nav__icon md-icon"></span>
1482
+ </label>
1483
+
1484
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_2_label" aria-expanded="false">
1485
+ <label class="md-nav__title" for="__nav_2_8_2">
1486
+ <span class="md-nav__icon md-icon"></span>
1487
+ DCIM
1488
+ </label>
1489
+ <ul class="md-nav__list" data-md-scrollfix>
1490
+
1491
+
1492
+
1493
+
1494
+
1495
+
1496
+ <li class="md-nav__item">
1497
+ <a href="../../../models/dcim/cable.html" class="md-nav__link">
1498
+ Cable
1499
+ </a>
1500
+ </li>
1501
+
1502
+
1503
+
1504
+
1505
+
1506
+
1507
+
1508
+
1509
+
1510
+ <li class="md-nav__item">
1511
+ <a href="../../../models/dcim/consoleport.html" class="md-nav__link">
1512
+ Console Port
1513
+ </a>
1514
+ </li>
1515
+
1516
+
1517
+
1518
+
1519
+
1520
+
1521
+
1522
+
1523
+
1524
+ <li class="md-nav__item">
1525
+ <a href="../../../models/dcim/consoleporttemplate.html" class="md-nav__link">
1526
+ Console Port Template
1527
+ </a>
1528
+ </li>
1529
+
1530
+
1531
+
1532
+
1533
+
1534
+
1535
+
1536
+
1537
+
1538
+ <li class="md-nav__item">
1539
+ <a href="../../../models/dcim/consoleserverport.html" class="md-nav__link">
1540
+ Console Server Port
1541
+ </a>
1542
+ </li>
1543
+
1544
+
1545
+
1546
+
1547
+
1548
+
1549
+
1550
+
1551
+
1552
+ <li class="md-nav__item">
1553
+ <a href="../../../models/dcim/consoleserverporttemplate.html" class="md-nav__link">
1554
+ Console Server Port Template
1555
+ </a>
1556
+ </li>
1557
+
1558
+
1559
+
1560
+
1561
+
1562
+
1563
+
1564
+
1565
+
1566
+ <li class="md-nav__item">
1567
+ <a href="../../../models/dcim/device.html" class="md-nav__link">
1568
+ Device
1569
+ </a>
1570
+ </li>
1571
+
1572
+
1573
+
1574
+
1575
+
1576
+
1577
+
1578
+
1579
+
1580
+ <li class="md-nav__item">
1581
+ <a href="../../../models/dcim/devicebay.html" class="md-nav__link">
1582
+ Device Bay
1583
+ </a>
1584
+ </li>
1585
+
1586
+
1587
+
1588
+
1589
+
1590
+
1591
+
1592
+
1593
+
1594
+ <li class="md-nav__item">
1595
+ <a href="../../../models/dcim/devicebaytemplate.html" class="md-nav__link">
1596
+ Device Bay Template
1597
+ </a>
1598
+ </li>
1599
+
1600
+
1601
+
1602
+
1603
+
1604
+
1605
+
1606
+
1607
+
1608
+ <li class="md-nav__item">
1609
+ <a href="../../../models/dcim/deviceredundancygroup.html" class="md-nav__link">
1610
+ Device Redundancy Group
1611
+ </a>
1612
+ </li>
1613
+
1614
+
1615
+
1616
+
1617
+
1618
+
1619
+
1620
+
1621
+
1622
+ <li class="md-nav__item">
1623
+ <a href="../../../models/dcim/devicetype.html" class="md-nav__link">
1624
+ Device Type
1625
+ </a>
1626
+ </li>
1627
+
1628
+
1629
+
1630
+
1631
+
1632
+
1633
+
1634
+
1635
+
1636
+ <li class="md-nav__item">
1637
+ <a href="../../../models/dcim/frontport.html" class="md-nav__link">
1638
+ Front Port
1639
+ </a>
1640
+ </li>
1641
+
1642
+
1643
+
1644
+
1645
+
1646
+
1647
+
1648
+
1649
+
1650
+ <li class="md-nav__item">
1651
+ <a href="../../../models/dcim/frontporttemplate.html" class="md-nav__link">
1652
+ Front Port Template
1653
+ </a>
1654
+ </li>
1655
+
1656
+
1657
+
1658
+
1659
+
1660
+
1661
+
1662
+
1663
+
1664
+ <li class="md-nav__item">
1665
+ <a href="../../../models/dcim/interface.html" class="md-nav__link">
1666
+ Interface
1667
+ </a>
1668
+ </li>
1669
+
1670
+
1671
+
1672
+
1673
+
1674
+
1675
+
1676
+
1677
+
1678
+ <li class="md-nav__item">
1679
+ <a href="../../../models/dcim/interfacetemplate.html" class="md-nav__link">
1680
+ Interface Template
1681
+ </a>
1682
+ </li>
1683
+
1684
+
1685
+
1686
+
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+ <li class="md-nav__item">
1693
+ <a href="../../../models/dcim/inventoryitem.html" class="md-nav__link">
1694
+ Inventory Item
1695
+ </a>
1696
+ </li>
1697
+
1698
+
1699
+
1700
+
1701
+
1702
+
1703
+
1704
+
1705
+
1706
+ <li class="md-nav__item">
1707
+ <a href="../../../models/dcim/location.html" class="md-nav__link">
1708
+ Location
1709
+ </a>
1710
+ </li>
1711
+
1712
+
1713
+
1714
+
1715
+
1716
+
1717
+
1718
+
1719
+
1720
+ <li class="md-nav__item">
1721
+ <a href="../../../models/dcim/locationtype.html" class="md-nav__link">
1722
+ Location Type
1723
+ </a>
1724
+ </li>
1725
+
1726
+
1727
+
1728
+
1729
+
1730
+
1731
+
1732
+
1733
+
1734
+ <li class="md-nav__item">
1735
+ <a href="../../../models/dcim/manufacturer.html" class="md-nav__link">
1736
+ Manufacturer
1737
+ </a>
1738
+ </li>
1739
+
1740
+
1741
+
1742
+
1743
+
1744
+
1745
+
1746
+
1747
+
1748
+ <li class="md-nav__item">
1749
+ <a href="../../../models/dcim/platform.html" class="md-nav__link">
1750
+ Platform
1751
+ </a>
1752
+ </li>
1753
+
1754
+
1755
+
1756
+
1757
+
1758
+
1759
+
1760
+
1761
+
1762
+ <li class="md-nav__item">
1763
+ <a href="../../../models/dcim/powerfeed.html" class="md-nav__link">
1764
+ Power Feed
1765
+ </a>
1766
+ </li>
1767
+
1768
+
1769
+
1770
+
1771
+
1772
+
1773
+
1774
+
1775
+
1776
+ <li class="md-nav__item">
1777
+ <a href="../../../models/dcim/poweroutlet.html" class="md-nav__link">
1778
+ Power Outlet
1779
+ </a>
1780
+ </li>
1781
+
1782
+
1783
+
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+ <li class="md-nav__item">
1791
+ <a href="../../../models/dcim/poweroutlettemplate.html" class="md-nav__link">
1792
+ Power Outlet Template
1793
+ </a>
1794
+ </li>
1795
+
1796
+
1797
+
1798
+
1799
+
1800
+
1801
+
1802
+
1803
+
1804
+ <li class="md-nav__item">
1805
+ <a href="../../../models/dcim/powerpanel.html" class="md-nav__link">
1806
+ Power Panel
1807
+ </a>
1808
+ </li>
1809
+
1810
+
1811
+
1812
+
1813
+
1814
+
1815
+
1816
+
1817
+
1818
+ <li class="md-nav__item">
1819
+ <a href="../../../models/dcim/powerport.html" class="md-nav__link">
1820
+ Power Port
1821
+ </a>
1822
+ </li>
1823
+
1824
+
1825
+
1826
+
1827
+
1828
+
1829
+
1830
+
1831
+
1832
+ <li class="md-nav__item">
1833
+ <a href="../../../models/dcim/powerporttemplate.html" class="md-nav__link">
1834
+ Power Port Template
1835
+ </a>
1836
+ </li>
1837
+
1838
+
1839
+
1840
+
1841
+
1842
+
1843
+
1844
+
1845
+
1846
+ <li class="md-nav__item">
1847
+ <a href="../../../models/dcim/rack.html" class="md-nav__link">
1848
+ Rack
1849
+ </a>
1850
+ </li>
1851
+
1852
+
1853
+
1854
+
1855
+
1856
+
1857
+
1858
+
1859
+
1860
+ <li class="md-nav__item">
1861
+ <a href="../../../models/dcim/rackgroup.html" class="md-nav__link">
1862
+ Rack Group
1863
+ </a>
1864
+ </li>
1865
+
1866
+
1867
+
1868
+
1869
+
1870
+
1871
+
1872
+
1873
+
1874
+ <li class="md-nav__item">
1875
+ <a href="../../../models/dcim/rackreservation.html" class="md-nav__link">
1876
+ Rack Reservation
1877
+ </a>
1878
+ </li>
1879
+
1880
+
1881
+
1882
+
1883
+
1884
+
1885
+
1886
+
1887
+
1888
+ <li class="md-nav__item">
1889
+ <a href="../../../models/dcim/rearport.html" class="md-nav__link">
1890
+ Rear Port
1891
+ </a>
1892
+ </li>
1893
+
1894
+
1895
+
1896
+
1897
+
1898
+
1899
+
1900
+
1901
+
1902
+ <li class="md-nav__item">
1903
+ <a href="../../../models/dcim/rearporttemplate.html" class="md-nav__link">
1904
+ Rear Port Template
1905
+ </a>
1906
+ </li>
1907
+
1908
+
1909
+
1910
+
1911
+
1912
+
1913
+
1914
+
1915
+
1916
+ <li class="md-nav__item">
1917
+ <a href="../../../models/dcim/virtualchassis.html" class="md-nav__link">
1918
+ Virtual Chassis
1919
+ </a>
1920
+ </li>
1921
+
1922
+
1923
+
1924
+
1925
+ </ul>
1926
+ </nav>
1927
+ </li>
1928
+
1929
+
1930
+
1931
+
1932
+
1933
+
1934
+
1935
+
1936
+
1937
+
1938
+ <li class="md-nav__item md-nav__item--nested">
1939
+
1940
+
1941
+
1942
+
1943
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_3" >
1944
+
1945
+
1946
+
1947
+ <label class="md-nav__link" for="__nav_2_8_3" id="__nav_2_8_3_label" tabindex="0">
1948
+ Extras
1949
+ <span class="md-nav__icon md-icon"></span>
1950
+ </label>
1951
+
1952
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_3_label" aria-expanded="false">
1953
+ <label class="md-nav__title" for="__nav_2_8_3">
1954
+ <span class="md-nav__icon md-icon"></span>
1955
+ Extras
1956
+ </label>
1957
+ <ul class="md-nav__list" data-md-scrollfix>
1958
+
1959
+
1960
+
1961
+
1962
+
1963
+
1964
+ <li class="md-nav__item">
1965
+ <a href="../../../models/extras/configcontext.html" class="md-nav__link">
1966
+ Config Context
1967
+ </a>
1968
+ </li>
1969
+
1970
+
1971
+
1972
+
1973
+
1974
+
1975
+
1976
+
1977
+
1978
+ <li class="md-nav__item">
1979
+ <a href="../../../models/extras/configcontextschema.html" class="md-nav__link">
1980
+ Config Context Schema
1981
+ </a>
1982
+ </li>
1983
+
1984
+
1985
+
1986
+
1987
+
1988
+
1989
+
1990
+
1991
+
1992
+ <li class="md-nav__item">
1993
+ <a href="../../../models/extras/graphqlquery.html" class="md-nav__link">
1994
+ GraphQL Query
1995
+ </a>
1996
+ </li>
1997
+
1998
+
1999
+
2000
+
2001
+
2002
+
2003
+
2004
+
2005
+
2006
+ <li class="md-nav__item">
2007
+ <a href="../../../models/extras/imageattachment.html" class="md-nav__link">
2008
+ Image Attachment
2009
+ </a>
2010
+ </li>
2011
+
2012
+
2013
+
2014
+
2015
+
2016
+
2017
+
2018
+
2019
+
2020
+ <li class="md-nav__item">
2021
+ <a href="../../../models/extras/job.html" class="md-nav__link">
2022
+ Job
2023
+ </a>
2024
+ </li>
2025
+
2026
+
2027
+
2028
+
2029
+
2030
+
2031
+
2032
+
2033
+
2034
+ <li class="md-nav__item">
2035
+ <a href="../../../models/extras/joblogentry.html" class="md-nav__link">
2036
+ Job Log Entry
2037
+ </a>
2038
+ </li>
2039
+
2040
+
2041
+
2042
+
2043
+
2044
+
2045
+
2046
+
2047
+
2048
+ <li class="md-nav__item">
2049
+ <a href="../../../models/extras/jobresult.html" class="md-nav__link">
2050
+ Job Result
2051
+ </a>
2052
+ </li>
2053
+
2054
+
2055
+
2056
+
2057
+
2058
+
2059
+
2060
+
2061
+
2062
+ <li class="md-nav__item">
2063
+ <a href="../../../models/extras/role.html" class="md-nav__link">
2064
+ Role
2065
+ </a>
2066
+ </li>
2067
+
2068
+
2069
+
2070
+
2071
+
2072
+
2073
+
2074
+
2075
+
2076
+ <li class="md-nav__item">
2077
+ <a href="../../../models/extras/secret.html" class="md-nav__link">
2078
+ Secret
2079
+ </a>
2080
+ </li>
2081
+
2082
+
2083
+
2084
+
2085
+
2086
+
2087
+
2088
+
2089
+
2090
+ <li class="md-nav__item">
2091
+ <a href="../../../models/extras/secretsgroup.html" class="md-nav__link">
2092
+ Secrets group
2093
+ </a>
2094
+ </li>
2095
+
2096
+
2097
+
2098
+
2099
+ </ul>
2100
+ </nav>
2101
+ </li>
2102
+
2103
+
2104
+
2105
+
2106
+
2107
+
2108
+
2109
+
2110
+
2111
+
2112
+ <li class="md-nav__item md-nav__item--nested">
2113
+
2114
+
2115
+
2116
+
2117
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_4" >
2118
+
2119
+
2120
+
2121
+ <label class="md-nav__link" for="__nav_2_8_4" id="__nav_2_8_4_label" tabindex="0">
2122
+ IPAM
2123
+ <span class="md-nav__icon md-icon"></span>
2124
+ </label>
2125
+
2126
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_4_label" aria-expanded="false">
2127
+ <label class="md-nav__title" for="__nav_2_8_4">
2128
+ <span class="md-nav__icon md-icon"></span>
2129
+ IPAM
2130
+ </label>
2131
+ <ul class="md-nav__list" data-md-scrollfix>
2132
+
2133
+
2134
+
2135
+
2136
+
2137
+
2138
+ <li class="md-nav__item">
2139
+ <a href="../../../models/ipam/ipaddress.html" class="md-nav__link">
2140
+ IP Address
2141
+ </a>
2142
+ </li>
2143
+
2144
+
2145
+
2146
+
2147
+
2148
+
2149
+
2150
+
2151
+
2152
+ <li class="md-nav__item">
2153
+ <a href="../../../models/ipam/prefix.html" class="md-nav__link">
2154
+ Prefix
2155
+ </a>
2156
+ </li>
2157
+
2158
+
2159
+
2160
+
2161
+
2162
+
2163
+
2164
+
2165
+
2166
+ <li class="md-nav__item">
2167
+ <a href="../../../models/ipam/rir.html" class="md-nav__link">
2168
+ Rir
2169
+ </a>
2170
+ </li>
2171
+
2172
+
2173
+
2174
+
2175
+
2176
+
2177
+
2178
+
2179
+
2180
+ <li class="md-nav__item">
2181
+ <a href="../../../models/ipam/routetarget.html" class="md-nav__link">
2182
+ Route Target
2183
+ </a>
2184
+ </li>
2185
+
2186
+
2187
+
2188
+
2189
+
2190
+
2191
+
2192
+
2193
+
2194
+ <li class="md-nav__item">
2195
+ <a href="../../../models/ipam/service.html" class="md-nav__link">
2196
+ Service
2197
+ </a>
2198
+ </li>
2199
+
2200
+
2201
+
2202
+
2203
+
2204
+
2205
+
2206
+
2207
+
2208
+ <li class="md-nav__item">
2209
+ <a href="../../../models/ipam/vlan.html" class="md-nav__link">
2210
+ VLAN
2211
+ </a>
2212
+ </li>
2213
+
2214
+
2215
+
2216
+
2217
+
2218
+
2219
+
2220
+
2221
+
2222
+ <li class="md-nav__item">
2223
+ <a href="../../../models/ipam/vlangroup.html" class="md-nav__link">
2224
+ VLAN Group
2225
+ </a>
2226
+ </li>
2227
+
2228
+
2229
+
2230
+
2231
+
2232
+
2233
+
2234
+
2235
+
2236
+ <li class="md-nav__item">
2237
+ <a href="../../../models/ipam/vrf.html" class="md-nav__link">
2238
+ VRF
2239
+ </a>
2240
+ </li>
2241
+
2242
+
2243
+
2244
+
2245
+ </ul>
2246
+ </nav>
2247
+ </li>
2248
+
2249
+
2250
+
2251
+
2252
+
2253
+
2254
+
2255
+
2256
+
2257
+
2258
+ <li class="md-nav__item md-nav__item--nested">
2259
+
2260
+
2261
+
2262
+
2263
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_5" >
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">
1349
2503
  Additional Features
1350
2504
  <span class="md-nav__icon md-icon"></span>
1351
2505
  </label>
1352
2506
 
1353
- <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
1354
- <label class="md-nav__title" for="__nav_2_8">
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">
1355
2509
  <span class="md-nav__icon md-icon"></span>
1356
2510
  Additional Features
1357
2511
  </label>
@@ -1683,17 +2837,17 @@
1683
2837
 
1684
2838
 
1685
2839
 
1686
- <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_9" >
2840
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_10" >
1687
2841
 
1688
2842
 
1689
2843
 
1690
- <label class="md-nav__link" for="__nav_2_9" id="__nav_2_9_label" tabindex="0">
2844
+ <label class="md-nav__link" for="__nav_2_10" id="__nav_2_10_label" tabindex="0">
1691
2845
  REST API
1692
2846
  <span class="md-nav__icon md-icon"></span>
1693
2847
  </label>
1694
2848
 
1695
- <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="false">
1696
- <label class="md-nav__title" for="__nav_2_9">
2849
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
2850
+ <label class="md-nav__title" for="__nav_2_10">
1697
2851
  <span class="md-nav__icon md-icon"></span>
1698
2852
  REST API
1699
2853
  </label>
@@ -1741,6 +2895,20 @@
1741
2895
 
1742
2896
 
1743
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
+
1744
2912
  </ul>
1745
2913
  </nav>
1746
2914
  </li>
@@ -1759,17 +2927,17 @@
1759
2927
 
1760
2928
 
1761
2929
 
1762
- <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_10" >
2930
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_11" >
1763
2931
 
1764
2932
 
1765
2933
 
1766
- <label class="md-nav__link" for="__nav_2_10" id="__nav_2_10_label" tabindex="0">
2934
+ <label class="md-nav__link" for="__nav_2_11" id="__nav_2_11_label" tabindex="0">
1767
2935
  GraphQL API
1768
2936
  <span class="md-nav__icon md-icon"></span>
1769
2937
  </label>
1770
2938
 
1771
- <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
1772
- <label class="md-nav__title" for="__nav_2_10">
2939
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_11_label" aria-expanded="false">
2940
+ <label class="md-nav__title" for="__nav_2_11">
1773
2941
  <span class="md-nav__icon md-icon"></span>
1774
2942
  GraphQL API
1775
2943
  </label>
@@ -2169,13 +3337,6 @@
2169
3337
  StatusModelBulkEditFormMixin
2170
3338
  </a>
2171
3339
 
2172
- </li>
2173
-
2174
- <li class="md-nav__item">
2175
- <a href="#nautobot.apps.forms.StatusModelCSVFormMixin" class="md-nav__link">
2176
- StatusModelCSVFormMixin
2177
- </a>
2178
-
2179
3340
  </li>
2180
3341
 
2181
3342
  <li class="md-nav__item">
@@ -3103,13 +4264,6 @@
3103
4264
  StatusModelBulkEditFormMixin
3104
4265
  </a>
3105
4266
 
3106
- </li>
3107
-
3108
- <li class="md-nav__item">
3109
- <a href="#nautobot.apps.forms.StatusModelCSVFormMixin" class="md-nav__link">
3110
- StatusModelCSVFormMixin
3111
- </a>
3112
-
3113
4267
  </li>
3114
4268
 
3115
4269
  <li class="md-nav__item">
@@ -3270,37 +4424,45 @@ a more powerful subclass and should be used instead of directly inheriting from
3270
4424
 
3271
4425
 
3272
4426
  <p>Provides additional validation for model choices entered as CSV data.</p>
4427
+ <p>Note: class name is misleading; the subclass CSVContentTypeField (below) is also used in FilterSets, where it has
4428
+ nothing to do with CSV data.</p>
3273
4429
 
3274
4430
 
3275
4431
  <details class="quote">
3276
4432
  <summary>Source code in <code>nautobot/core/forms/fields.py</code></summary>
3277
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-182">182</a></span>
3278
- <span class="normal"><a href="#__codelineno-0-183">183</a></span>
3279
- <span class="normal"><a href="#__codelineno-0-184">184</a></span>
3280
- <span class="normal"><a href="#__codelineno-0-185">185</a></span>
3281
- <span class="normal"><a href="#__codelineno-0-186">186</a></span>
3282
- <span class="normal"><a href="#__codelineno-0-187">187</a></span>
3283
- <span class="normal"><a href="#__codelineno-0-188">188</a></span>
3284
- <span class="normal"><a href="#__codelineno-0-189">189</a></span>
3285
- <span class="normal"><a href="#__codelineno-0-190">190</a></span>
3286
- <span class="normal"><a href="#__codelineno-0-191">191</a></span>
3287
- <span class="normal"><a href="#__codelineno-0-192">192</a></span>
3288
- <span class="normal"><a href="#__codelineno-0-193">193</a></span>
3289
- <span class="normal"><a href="#__codelineno-0-194">194</a></span>
3290
- <span class="normal"><a href="#__codelineno-0-195">195</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-182" name="__codelineno-0-182"></a><span class="k">class</span> <span class="nc">CSVModelChoiceField</span><span class="p">(</span><span class="n">django_forms</span><span class="o">.</span><span class="n">ModelChoiceField</span><span class="p">):</span>
3291
- <a id="__codelineno-0-183" name="__codelineno-0-183"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3292
- <a id="__codelineno-0-184" name="__codelineno-0-184"></a><span class="sd"> Provides additional validation for model choices entered as CSV data.</span>
3293
- <a id="__codelineno-0-185" name="__codelineno-0-185"></a><span class="sd"> &quot;&quot;&quot;</span>
3294
- <a id="__codelineno-0-186" name="__codelineno-0-186"></a>
3295
- <a id="__codelineno-0-187" name="__codelineno-0-187"></a> <span class="n">default_error_messages</span> <span class="o">=</span> <span class="p">{</span>
3296
- <a id="__codelineno-0-188" name="__codelineno-0-188"></a> <span class="s2">&quot;invalid_choice&quot;</span><span class="p">:</span> <span class="s2">&quot;Object not found.&quot;</span><span class="p">,</span>
3297
- <a id="__codelineno-0-189" name="__codelineno-0-189"></a> <span class="p">}</span>
3298
- <a id="__codelineno-0-190" name="__codelineno-0-190"></a>
3299
- <a id="__codelineno-0-191" name="__codelineno-0-191"></a> <span class="k">def</span> <span class="nf">to_python</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
3300
- <a id="__codelineno-0-192" name="__codelineno-0-192"></a> <span class="k">try</span><span class="p">:</span>
3301
- <a id="__codelineno-0-193" name="__codelineno-0-193"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">to_python</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
3302
- <a id="__codelineno-0-194" name="__codelineno-0-194"></a> <span class="k">except</span> <span class="n">MultipleObjectsReturned</span><span class="p">:</span>
3303
- <a id="__codelineno-0-195" name="__codelineno-0-195"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;&quot;</span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s1">&quot; is not a unique value for this field; multiple objects were found&#39;</span><span class="p">)</span>
4433
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-148">148</a></span>
4434
+ <span class="normal"><a href="#__codelineno-0-149">149</a></span>
4435
+ <span class="normal"><a href="#__codelineno-0-150">150</a></span>
4436
+ <span class="normal"><a href="#__codelineno-0-151">151</a></span>
4437
+ <span class="normal"><a href="#__codelineno-0-152">152</a></span>
4438
+ <span class="normal"><a href="#__codelineno-0-153">153</a></span>
4439
+ <span class="normal"><a href="#__codelineno-0-154">154</a></span>
4440
+ <span class="normal"><a href="#__codelineno-0-155">155</a></span>
4441
+ <span class="normal"><a href="#__codelineno-0-156">156</a></span>
4442
+ <span class="normal"><a href="#__codelineno-0-157">157</a></span>
4443
+ <span class="normal"><a href="#__codelineno-0-158">158</a></span>
4444
+ <span class="normal"><a href="#__codelineno-0-159">159</a></span>
4445
+ <span class="normal"><a href="#__codelineno-0-160">160</a></span>
4446
+ <span class="normal"><a href="#__codelineno-0-161">161</a></span>
4447
+ <span class="normal"><a href="#__codelineno-0-162">162</a></span>
4448
+ <span class="normal"><a href="#__codelineno-0-163">163</a></span>
4449
+ <span class="normal"><a href="#__codelineno-0-164">164</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-148" name="__codelineno-0-148"></a><span class="k">class</span> <span class="nc">CSVModelChoiceField</span><span class="p">(</span><span class="n">django_forms</span><span class="o">.</span><span class="n">ModelChoiceField</span><span class="p">):</span>
4450
+ <a id="__codelineno-0-149" name="__codelineno-0-149"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4451
+ <a id="__codelineno-0-150" name="__codelineno-0-150"></a><span class="sd"> Provides additional validation for model choices entered as CSV data.</span>
4452
+ <a id="__codelineno-0-151" name="__codelineno-0-151"></a>
4453
+ <a id="__codelineno-0-152" name="__codelineno-0-152"></a><span class="sd"> Note: class name is misleading; the subclass CSVContentTypeField (below) is also used in FilterSets, where it has</span>
4454
+ <a id="__codelineno-0-153" name="__codelineno-0-153"></a><span class="sd"> nothing to do with CSV data.</span>
4455
+ <a id="__codelineno-0-154" name="__codelineno-0-154"></a><span class="sd"> &quot;&quot;&quot;</span>
4456
+ <a id="__codelineno-0-155" name="__codelineno-0-155"></a>
4457
+ <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="n">default_error_messages</span> <span class="o">=</span> <span class="p">{</span>
4458
+ <a id="__codelineno-0-157" name="__codelineno-0-157"></a> <span class="s2">&quot;invalid_choice&quot;</span><span class="p">:</span> <span class="s2">&quot;Object not found.&quot;</span><span class="p">,</span>
4459
+ <a id="__codelineno-0-158" name="__codelineno-0-158"></a> <span class="p">}</span>
4460
+ <a id="__codelineno-0-159" name="__codelineno-0-159"></a>
4461
+ <a id="__codelineno-0-160" name="__codelineno-0-160"></a> <span class="k">def</span> <span class="nf">to_python</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
4462
+ <a id="__codelineno-0-161" name="__codelineno-0-161"></a> <span class="k">try</span><span class="p">:</span>
4463
+ <a id="__codelineno-0-162" name="__codelineno-0-162"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">to_python</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
4464
+ <a id="__codelineno-0-163" name="__codelineno-0-163"></a> <span class="k">except</span> <span class="n">MultipleObjectsReturned</span><span class="p">:</span>
4465
+ <a id="__codelineno-0-164" name="__codelineno-0-164"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span><span class="sa">f</span><span class="s1">&#39;&quot;</span><span class="si">{</span><span class="n">value</span><span class="si">}</span><span class="s1">&quot; is not a unique value for this field; multiple objects were found&#39;</span><span class="p">)</span>
3304
4466
  </code></pre></div></td></tr></table></div>
3305
4467
  </details>
3306
4468
 
@@ -3340,7 +4502,9 @@ a more powerful subclass and should be used instead of directly inheriting from
3340
4502
  Bases: <code><span title="django.forms">forms</span>.<span title="django.forms.ModelForm">ModelForm</span></code></p>
3341
4503
 
3342
4504
 
3343
- <p>ModelForm used for the import of objects in CSV format.</p>
4505
+ <p>ModelForm used for the import of objects.</p>
4506
+ <p>Note: the name is misleading as since 2.0 this is no longer used for CSV imports; however it <em>is</em> still used for
4507
+ JSON/YAML imports of DeviceTypes and their component templates.</p>
3344
4508
 
3345
4509
 
3346
4510
  <details class="quote">
@@ -3357,19 +4521,25 @@ a more powerful subclass and should be used instead of directly inheriting from
3357
4521
  <span class="normal"><a href="#__codelineno-0-147">147</a></span>
3358
4522
  <span class="normal"><a href="#__codelineno-0-148">148</a></span>
3359
4523
  <span class="normal"><a href="#__codelineno-0-149">149</a></span>
3360
- <span class="normal"><a href="#__codelineno-0-150">150</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-138" name="__codelineno-0-138"></a><span class="k">class</span> <span class="nc">CSVModelForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
4524
+ <span class="normal"><a href="#__codelineno-0-150">150</a></span>
4525
+ <span class="normal"><a href="#__codelineno-0-151">151</a></span>
4526
+ <span class="normal"><a href="#__codelineno-0-152">152</a></span>
4527
+ <span class="normal"><a href="#__codelineno-0-153">153</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-138" name="__codelineno-0-138"></a><span class="k">class</span> <span class="nc">CSVModelForm</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
3361
4528
  <a id="__codelineno-0-139" name="__codelineno-0-139"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3362
- <a id="__codelineno-0-140" name="__codelineno-0-140"></a><span class="sd"> ModelForm used for the import of objects in CSV format.</span>
3363
- <a id="__codelineno-0-141" name="__codelineno-0-141"></a><span class="sd"> &quot;&quot;&quot;</span>
3364
- <a id="__codelineno-0-142" name="__codelineno-0-142"></a>
3365
- <a id="__codelineno-0-143" name="__codelineno-0-143"></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="n">headers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
3366
- <a id="__codelineno-0-144" name="__codelineno-0-144"></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>
4529
+ <a id="__codelineno-0-140" name="__codelineno-0-140"></a><span class="sd"> ModelForm used for the import of objects.</span>
4530
+ <a id="__codelineno-0-141" name="__codelineno-0-141"></a>
4531
+ <a id="__codelineno-0-142" name="__codelineno-0-142"></a><span class="sd"> Note: the name is misleading as since 2.0 this is no longer used for CSV imports; however it *is* still used for</span>
4532
+ <a id="__codelineno-0-143" name="__codelineno-0-143"></a><span class="sd"> JSON/YAML imports of DeviceTypes and their component templates.</span>
4533
+ <a id="__codelineno-0-144" name="__codelineno-0-144"></a><span class="sd"> &quot;&quot;&quot;</span>
3367
4534
  <a id="__codelineno-0-145" name="__codelineno-0-145"></a>
3368
- <a id="__codelineno-0-146" name="__codelineno-0-146"></a> <span class="c1"># Modify the model form to accommodate any customized to_field_name properties</span>
3369
- <a id="__codelineno-0-147" name="__codelineno-0-147"></a> <span class="k">if</span> <span class="n">headers</span><span class="p">:</span>
3370
- <a id="__codelineno-0-148" name="__codelineno-0-148"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">to_field</span> <span class="ow">in</span> <span class="n">headers</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
3371
- <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="k">if</span> <span class="n">to_field</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
3372
- <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field</span><span class="p">]</span><span class="o">.</span><span class="n">to_field_name</span> <span class="o">=</span> <span class="n">to_field</span>
4535
+ <a id="__codelineno-0-146" name="__codelineno-0-146"></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="n">headers</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span><span class="p">):</span>
4536
+ <a id="__codelineno-0-147" name="__codelineno-0-147"></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>
4537
+ <a id="__codelineno-0-148" name="__codelineno-0-148"></a>
4538
+ <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="c1"># Modify the model form to accommodate any customized to_field_name properties</span>
4539
+ <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="k">if</span> <span class="n">headers</span><span class="p">:</span>
4540
+ <a id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">to_field</span> <span class="ow">in</span> <span class="n">headers</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4541
+ <a id="__codelineno-0-152" name="__codelineno-0-152"></a> <span class="k">if</span> <span class="n">to_field</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
4542
+ <a id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field</span><span class="p">]</span><span class="o">.</span><span class="n">to_field_name</span> <span class="o">=</span> <span class="n">to_field</span>
3373
4543
  </code></pre></div></td></tr></table></div>
3374
4544
  </details>
3375
4545
 
@@ -3409,32 +4579,47 @@ a more powerful subclass and should be used instead of directly inheriting from
3409
4579
  Bases: <code><a class="autorefs autorefs-internal" title="nautobot.core.forms.CSVModelForm" href="#nautobot.apps.forms.CSVModelForm">CSVModelForm</a></code>, <code><a class="autorefs autorefs-internal" title="nautobot.extras.forms.mixins.CustomFieldModelFormMixin" href="#nautobot.apps.forms.CustomFieldModelFormMixin">CustomFieldModelFormMixin</a></code></p>
3410
4580
 
3411
4581
 
3412
- <p>Base class for CSV export of models that support custom fields.</p>
4582
+ <p>Base class for CSV/JSON/YAML import of models that support custom fields.</p>
4583
+ <p>TODO: The class name is a misnomer; as of 2.0 this class is <strong>not</strong> used for any CSV imports,
4584
+ as that's now handled by the REST API. However it is still used when importing component-templates as
4585
+ part of a JSON/YAML DeviceType import.</p>
3413
4586
 
3414
4587
 
3415
4588
  <details class="quote">
3416
4589
  <summary>Source code in <code>nautobot/extras/forms/forms.py</code></summary>
3417
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-405">405</a></span>
3418
- <span class="normal"><a href="#__codelineno-0-406">406</a></span>
3419
- <span class="normal"><a href="#__codelineno-0-407">407</a></span>
3420
- <span class="normal"><a href="#__codelineno-0-408">408</a></span>
3421
- <span class="normal"><a href="#__codelineno-0-409">409</a></span>
3422
- <span class="normal"><a href="#__codelineno-0-410">410</a></span>
4590
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-410">410</a></span>
3423
4591
  <span class="normal"><a href="#__codelineno-0-411">411</a></span>
3424
4592
  <span class="normal"><a href="#__codelineno-0-412">412</a></span>
3425
4593
  <span class="normal"><a href="#__codelineno-0-413">413</a></span>
3426
4594
  <span class="normal"><a href="#__codelineno-0-414">414</a></span>
3427
- <span class="normal"><a href="#__codelineno-0-415">415</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-405" name="__codelineno-0-405"></a><span class="k">class</span> <span class="nc">CustomFieldModelCSVForm</span><span class="p">(</span><span class="n">CSVModelForm</span><span class="p">,</span> <span class="n">CustomFieldModelFormMixin</span><span class="p">):</span>
3428
- <a id="__codelineno-0-406" name="__codelineno-0-406"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Base class for CSV export of models that support custom fields.&quot;&quot;&quot;</span>
3429
- <a id="__codelineno-0-407" name="__codelineno-0-407"></a>
3430
- <a id="__codelineno-0-408" name="__codelineno-0-408"></a> <span class="k">def</span> <span class="nf">_append_customfield_fields</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3431
- <a id="__codelineno-0-409" name="__codelineno-0-409"></a> <span class="c1"># Append form fields</span>
3432
- <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="k">for</span> <span class="n">cf</span> <span class="ow">in</span> <span class="n">CustomField</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">content_types</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">):</span>
3433
- <a id="__codelineno-0-411" name="__codelineno-0-411"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">add_prefix_to_cf_key</span><span class="p">()</span>
3434
- <a id="__codelineno-0-412" name="__codelineno-0-412"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">for_csv_import</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
4595
+ <span class="normal"><a href="#__codelineno-0-415">415</a></span>
4596
+ <span class="normal"><a href="#__codelineno-0-416">416</a></span>
4597
+ <span class="normal"><a href="#__codelineno-0-417">417</a></span>
4598
+ <span class="normal"><a href="#__codelineno-0-418">418</a></span>
4599
+ <span class="normal"><a href="#__codelineno-0-419">419</a></span>
4600
+ <span class="normal"><a href="#__codelineno-0-420">420</a></span>
4601
+ <span class="normal"><a href="#__codelineno-0-421">421</a></span>
4602
+ <span class="normal"><a href="#__codelineno-0-422">422</a></span>
4603
+ <span class="normal"><a href="#__codelineno-0-423">423</a></span>
4604
+ <span class="normal"><a href="#__codelineno-0-424">424</a></span>
4605
+ <span class="normal"><a href="#__codelineno-0-425">425</a></span>
4606
+ <span class="normal"><a href="#__codelineno-0-426">426</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-410" name="__codelineno-0-410"></a><span class="k">class</span> <span class="nc">CustomFieldModelCSVForm</span><span class="p">(</span><span class="n">CSVModelForm</span><span class="p">,</span> <span class="n">CustomFieldModelFormMixin</span><span class="p">):</span>
4607
+ <a id="__codelineno-0-411" name="__codelineno-0-411"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4608
+ <a id="__codelineno-0-412" name="__codelineno-0-412"></a><span class="sd"> Base class for CSV/JSON/YAML import of models that support custom fields.</span>
3435
4609
  <a id="__codelineno-0-413" name="__codelineno-0-413"></a>
3436
- <a id="__codelineno-0-414" name="__codelineno-0-414"></a> <span class="c1"># Annotate the field in the list of CustomField form fields</span>
3437
- <a id="__codelineno-0-415" name="__codelineno-0-415"></a> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4610
+ <a id="__codelineno-0-414" name="__codelineno-0-414"></a><span class="sd"> TODO: The class name is a misnomer; as of 2.0 this class is **not** used for any CSV imports,</span>
4611
+ <a id="__codelineno-0-415" name="__codelineno-0-415"></a><span class="sd"> as that&#39;s now handled by the REST API. However it is still used when importing component-templates as</span>
4612
+ <a id="__codelineno-0-416" name="__codelineno-0-416"></a><span class="sd"> part of a JSON/YAML DeviceType import.</span>
4613
+ <a id="__codelineno-0-417" name="__codelineno-0-417"></a><span class="sd"> &quot;&quot;&quot;</span>
4614
+ <a id="__codelineno-0-418" name="__codelineno-0-418"></a>
4615
+ <a id="__codelineno-0-419" name="__codelineno-0-419"></a> <span class="k">def</span> <span class="nf">_append_customfield_fields</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4616
+ <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="c1"># Append form fields</span>
4617
+ <a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="k">for</span> <span class="n">cf</span> <span class="ow">in</span> <span class="n">CustomField</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">content_types</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">):</span>
4618
+ <a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">add_prefix_to_cf_key</span><span class="p">()</span>
4619
+ <a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">for_csv_import</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
4620
+ <a id="__codelineno-0-424" name="__codelineno-0-424"></a>
4621
+ <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="c1"># Annotate the field in the list of CustomField form fields</span>
4622
+ <a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
3438
4623
  </code></pre></div></td></tr></table></div>
3439
4624
  </details>
3440
4625
 
@@ -3477,7 +4662,12 @@ a more powerful subclass and should be used instead of directly inheriting from
3477
4662
 
3478
4663
  <details class="quote">
3479
4664
  <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
3480
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-90"> 90</a></span>
4665
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-85"> 85</a></span>
4666
+ <span class="normal"><a href="#__codelineno-0-86"> 86</a></span>
4667
+ <span class="normal"><a href="#__codelineno-0-87"> 87</a></span>
4668
+ <span class="normal"><a href="#__codelineno-0-88"> 88</a></span>
4669
+ <span class="normal"><a href="#__codelineno-0-89"> 89</a></span>
4670
+ <span class="normal"><a href="#__codelineno-0-90"> 90</a></span>
3481
4671
  <span class="normal"><a href="#__codelineno-0-91"> 91</a></span>
3482
4672
  <span class="normal"><a href="#__codelineno-0-92"> 92</a></span>
3483
4673
  <span class="normal"><a href="#__codelineno-0-93"> 93</a></span>
@@ -3502,42 +4692,37 @@ a more powerful subclass and should be used instead of directly inheriting from
3502
4692
  <span class="normal"><a href="#__codelineno-0-112">112</a></span>
3503
4693
  <span class="normal"><a href="#__codelineno-0-113">113</a></span>
3504
4694
  <span class="normal"><a href="#__codelineno-0-114">114</a></span>
3505
- <span class="normal"><a href="#__codelineno-0-115">115</a></span>
3506
- <span class="normal"><a href="#__codelineno-0-116">116</a></span>
3507
- <span class="normal"><a href="#__codelineno-0-117">117</a></span>
3508
- <span class="normal"><a href="#__codelineno-0-118">118</a></span>
3509
- <span class="normal"><a href="#__codelineno-0-119">119</a></span>
3510
- <span class="normal"><a href="#__codelineno-0-120">120</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-90" name="__codelineno-0-90"></a><span class="k">class</span> <span class="nc">CustomFieldModelFormMixin</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
3511
- <a id="__codelineno-0-91" name="__codelineno-0-91"></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>
3512
- <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
3513
- <a id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span> <span class="o">=</span> <span class="p">[]</span>
3514
- <a id="__codelineno-0-94" name="__codelineno-0-94"></a>
3515
- <a id="__codelineno-0-95" name="__codelineno-0-95"></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>
3516
- <a id="__codelineno-0-96" name="__codelineno-0-96"></a>
3517
- <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_customfield_fields</span><span class="p">()</span>
3518
- <a id="__codelineno-0-98" name="__codelineno-0-98"></a>
3519
- <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="k">def</span> <span class="nf">_append_customfield_fields</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3520
- <a id="__codelineno-0-100" name="__codelineno-0-100"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3521
- <a id="__codelineno-0-101" name="__codelineno-0-101"></a><span class="sd"> Append form fields for all CustomFields assigned to this model.</span>
3522
- <a id="__codelineno-0-102" name="__codelineno-0-102"></a><span class="sd"> &quot;&quot;&quot;</span>
3523
- <a id="__codelineno-0-103" name="__codelineno-0-103"></a> <span class="c1"># Append form fields; assign initial values if modifying and existing object</span>
3524
- <a id="__codelineno-0-104" name="__codelineno-0-104"></a> <span class="k">for</span> <span class="n">cf</span> <span class="ow">in</span> <span class="n">CustomField</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">content_types</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">):</span>
3525
- <a id="__codelineno-0-105" name="__codelineno-0-105"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">add_prefix_to_cf_key</span><span class="p">()</span>
3526
- <a id="__codelineno-0-106" name="__codelineno-0-106"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">present_in_database</span><span class="p">:</span>
3527
- <a id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">set_initial</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
3528
- <a id="__codelineno-0-108" name="__codelineno-0-108"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">initial</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">cf</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">cf</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
3529
- <a id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="k">else</span><span class="p">:</span>
3530
- <a id="__codelineno-0-110" name="__codelineno-0-110"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">()</span>
3531
- <a id="__codelineno-0-111" name="__codelineno-0-111"></a>
3532
- <a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="c1"># Annotate the field in the list of CustomField form fields</span>
3533
- <a id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4695
+ <span class="normal"><a href="#__codelineno-0-115">115</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-85" name="__codelineno-0-85"></a><span class="k">class</span> <span class="nc">CustomFieldModelFormMixin</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
4696
+ <a id="__codelineno-0-86" name="__codelineno-0-86"></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>
4697
+ <a id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
4698
+ <a id="__codelineno-0-88" name="__codelineno-0-88"></a> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span> <span class="o">=</span> <span class="p">[]</span>
4699
+ <a id="__codelineno-0-89" name="__codelineno-0-89"></a>
4700
+ <a id="__codelineno-0-90" name="__codelineno-0-90"></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>
4701
+ <a id="__codelineno-0-91" name="__codelineno-0-91"></a>
4702
+ <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_customfield_fields</span><span class="p">()</span>
4703
+ <a id="__codelineno-0-93" name="__codelineno-0-93"></a>
4704
+ <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="k">def</span> <span class="nf">_append_customfield_fields</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4705
+ <a id="__codelineno-0-95" name="__codelineno-0-95"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4706
+ <a id="__codelineno-0-96" name="__codelineno-0-96"></a><span class="sd"> Append form fields for all CustomFields assigned to this model.</span>
4707
+ <a id="__codelineno-0-97" name="__codelineno-0-97"></a><span class="sd"> &quot;&quot;&quot;</span>
4708
+ <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="c1"># Append form fields; assign initial values if modifying and existing object</span>
4709
+ <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="k">for</span> <span class="n">cf</span> <span class="ow">in</span> <span class="n">CustomField</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">content_types</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">):</span>
4710
+ <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">add_prefix_to_cf_key</span><span class="p">()</span>
4711
+ <a id="__codelineno-0-101" name="__codelineno-0-101"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">present_in_database</span><span class="p">:</span>
4712
+ <a id="__codelineno-0-102" name="__codelineno-0-102"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">set_initial</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
4713
+ <a id="__codelineno-0-103" name="__codelineno-0-103"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">initial</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">cf</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">cf</span><span class="o">.</span><span class="n">key</span><span class="p">)</span>
4714
+ <a id="__codelineno-0-104" name="__codelineno-0-104"></a> <span class="k">else</span><span class="p">:</span>
4715
+ <a id="__codelineno-0-105" name="__codelineno-0-105"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">()</span>
4716
+ <a id="__codelineno-0-106" name="__codelineno-0-106"></a>
4717
+ <a id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="c1"># Annotate the field in the list of CustomField form fields</span>
4718
+ <a id="__codelineno-0-108" name="__codelineno-0-108"></a> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4719
+ <a id="__codelineno-0-109" name="__codelineno-0-109"></a>
4720
+ <a id="__codelineno-0-110" name="__codelineno-0-110"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4721
+ <a id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="c1"># Save custom field data on instance</span>
4722
+ <a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span><span class="p">:</span>
4723
+ <a id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">cf</span><span class="p">[</span><span class="n">remove_prefix_from_cf_key</span><span class="p">(</span><span class="n">field_name</span><span class="p">)]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
3534
4724
  <a id="__codelineno-0-114" name="__codelineno-0-114"></a>
3535
- <a id="__codelineno-0-115" name="__codelineno-0-115"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3536
- <a id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="c1"># Save custom field data on instance</span>
3537
- <a id="__codelineno-0-117" name="__codelineno-0-117"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">custom_fields</span><span class="p">:</span>
3538
- <a id="__codelineno-0-118" name="__codelineno-0-118"></a> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">cf</span><span class="p">[</span><span class="n">remove_prefix_from_cf_key</span><span class="p">(</span><span class="n">field_name</span><span class="p">)]</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
3539
- <a id="__codelineno-0-119" name="__codelineno-0-119"></a>
3540
- <a id="__codelineno-0-120" name="__codelineno-0-120"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
4725
+ <a id="__codelineno-0-115" name="__codelineno-0-115"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
3541
4726
  </code></pre></div></td></tr></table></div>
3542
4727
  </details>
3543
4728
 
@@ -3705,33 +4890,33 @@ rendered only with choices set via bound data. Choices are populated on-demand v
3705
4890
 
3706
4891
  <details class="quote">
3707
4892
  <summary>Source code in <code>nautobot/core/forms/fields.py</code></summary>
3708
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-595">595</a></span>
3709
- <span class="normal"><a href="#__codelineno-0-596">596</a></span>
3710
- <span class="normal"><a href="#__codelineno-0-597">597</a></span>
3711
- <span class="normal"><a href="#__codelineno-0-598">598</a></span>
3712
- <span class="normal"><a href="#__codelineno-0-599">599</a></span>
3713
- <span class="normal"><a href="#__codelineno-0-600">600</a></span>
3714
- <span class="normal"><a href="#__codelineno-0-601">601</a></span>
3715
- <span class="normal"><a href="#__codelineno-0-602">602</a></span>
3716
- <span class="normal"><a href="#__codelineno-0-603">603</a></span>
3717
- <span class="normal"><a href="#__codelineno-0-604">604</a></span>
3718
- <span class="normal"><a href="#__codelineno-0-605">605</a></span>
3719
- <span class="normal"><a href="#__codelineno-0-606">606</a></span>
3720
- <span class="normal"><a href="#__codelineno-0-607">607</a></span>
3721
- <span class="normal"><a href="#__codelineno-0-608">608</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-595" name="__codelineno-0-595"></a><span class="k">class</span> <span class="nc">DynamicModelChoiceField</span><span class="p">(</span><span class="n">DynamicModelChoiceMixin</span><span class="p">,</span> <span class="n">django_forms</span><span class="o">.</span><span class="n">ModelChoiceField</span><span class="p">):</span>
3722
- <a id="__codelineno-0-596" name="__codelineno-0-596"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3723
- <a id="__codelineno-0-597" name="__codelineno-0-597"></a><span class="sd"> Override get_bound_field() to avoid pre-populating field choices with a SQL query. The field will be</span>
3724
- <a id="__codelineno-0-598" name="__codelineno-0-598"></a><span class="sd"> rendered only with choices set via bound data. Choices are populated on-demand via the APISelect widget.</span>
3725
- <a id="__codelineno-0-599" name="__codelineno-0-599"></a><span class="sd"> &quot;&quot;&quot;</span>
3726
- <a id="__codelineno-0-600" name="__codelineno-0-600"></a>
3727
- <a id="__codelineno-0-601" name="__codelineno-0-601"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
3728
- <a id="__codelineno-0-602" name="__codelineno-0-602"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3729
- <a id="__codelineno-0-603" name="__codelineno-0-603"></a><span class="sd"> When null option is enabled and &quot;None&quot; is sent as part of a form to be submitted, it is sent as the</span>
3730
- <a id="__codelineno-0-604" name="__codelineno-0-604"></a><span class="sd"> string &#39;null&#39;. This will check for that condition and gracefully handle the conversion to a NoneType.</span>
3731
- <a id="__codelineno-0-605" name="__codelineno-0-605"></a><span class="sd"> &quot;&quot;&quot;</span>
3732
- <a id="__codelineno-0-606" name="__codelineno-0-606"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_option</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">==</span> <span class="n">settings</span><span class="o">.</span><span class="n">FILTERS_NULL_CHOICE_VALUE</span><span class="p">:</span>
3733
- <a id="__codelineno-0-607" name="__codelineno-0-607"></a> <span class="k">return</span> <span class="kc">None</span>
3734
- <a id="__codelineno-0-608" name="__codelineno-0-608"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
4893
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-568">568</a></span>
4894
+ <span class="normal"><a href="#__codelineno-0-569">569</a></span>
4895
+ <span class="normal"><a href="#__codelineno-0-570">570</a></span>
4896
+ <span class="normal"><a href="#__codelineno-0-571">571</a></span>
4897
+ <span class="normal"><a href="#__codelineno-0-572">572</a></span>
4898
+ <span class="normal"><a href="#__codelineno-0-573">573</a></span>
4899
+ <span class="normal"><a href="#__codelineno-0-574">574</a></span>
4900
+ <span class="normal"><a href="#__codelineno-0-575">575</a></span>
4901
+ <span class="normal"><a href="#__codelineno-0-576">576</a></span>
4902
+ <span class="normal"><a href="#__codelineno-0-577">577</a></span>
4903
+ <span class="normal"><a href="#__codelineno-0-578">578</a></span>
4904
+ <span class="normal"><a href="#__codelineno-0-579">579</a></span>
4905
+ <span class="normal"><a href="#__codelineno-0-580">580</a></span>
4906
+ <span class="normal"><a href="#__codelineno-0-581">581</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-568" name="__codelineno-0-568"></a><span class="k">class</span> <span class="nc">DynamicModelChoiceField</span><span class="p">(</span><span class="n">DynamicModelChoiceMixin</span><span class="p">,</span> <span class="n">django_forms</span><span class="o">.</span><span class="n">ModelChoiceField</span><span class="p">):</span>
4907
+ <a id="__codelineno-0-569" name="__codelineno-0-569"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4908
+ <a id="__codelineno-0-570" name="__codelineno-0-570"></a><span class="sd"> Override get_bound_field() to avoid pre-populating field choices with a SQL query. The field will be</span>
4909
+ <a id="__codelineno-0-571" name="__codelineno-0-571"></a><span class="sd"> rendered only with choices set via bound data. Choices are populated on-demand via the APISelect widget.</span>
4910
+ <a id="__codelineno-0-572" name="__codelineno-0-572"></a><span class="sd"> &quot;&quot;&quot;</span>
4911
+ <a id="__codelineno-0-573" name="__codelineno-0-573"></a>
4912
+ <a id="__codelineno-0-574" name="__codelineno-0-574"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
4913
+ <a id="__codelineno-0-575" name="__codelineno-0-575"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4914
+ <a id="__codelineno-0-576" name="__codelineno-0-576"></a><span class="sd"> When null option is enabled and &quot;None&quot; is sent as part of a form to be submitted, it is sent as the</span>
4915
+ <a id="__codelineno-0-577" name="__codelineno-0-577"></a><span class="sd"> string &#39;null&#39;. This will check for that condition and gracefully handle the conversion to a NoneType.</span>
4916
+ <a id="__codelineno-0-578" name="__codelineno-0-578"></a><span class="sd"> &quot;&quot;&quot;</span>
4917
+ <a id="__codelineno-0-579" name="__codelineno-0-579"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_option</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">==</span> <span class="n">settings</span><span class="o">.</span><span class="n">FILTERS_NULL_CHOICE_VALUE</span><span class="p">:</span>
4918
+ <a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="k">return</span> <span class="kc">None</span>
4919
+ <a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
3735
4920
  </code></pre></div></td></tr></table></div>
3736
4921
  </details>
3737
4922
 
@@ -3764,21 +4949,21 @@ string 'null'. This will check for that condition and gracefully handle the con
3764
4949
 
3765
4950
  <details class="quote">
3766
4951
  <summary>Source code in <code>nautobot/core/forms/fields.py</code></summary>
3767
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-601">601</a></span>
3768
- <span class="normal"><a href="#__codelineno-0-602">602</a></span>
3769
- <span class="normal"><a href="#__codelineno-0-603">603</a></span>
3770
- <span class="normal"><a href="#__codelineno-0-604">604</a></span>
3771
- <span class="normal"><a href="#__codelineno-0-605">605</a></span>
3772
- <span class="normal"><a href="#__codelineno-0-606">606</a></span>
3773
- <span class="normal"><a href="#__codelineno-0-607">607</a></span>
3774
- <span class="normal"><a href="#__codelineno-0-608">608</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-601" name="__codelineno-0-601"></a><span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
3775
- <a id="__codelineno-0-602" name="__codelineno-0-602"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3776
- <a id="__codelineno-0-603" name="__codelineno-0-603"></a><span class="sd"> When null option is enabled and &quot;None&quot; is sent as part of a form to be submitted, it is sent as the</span>
3777
- <a id="__codelineno-0-604" name="__codelineno-0-604"></a><span class="sd"> string &#39;null&#39;. This will check for that condition and gracefully handle the conversion to a NoneType.</span>
3778
- <a id="__codelineno-0-605" name="__codelineno-0-605"></a><span class="sd"> &quot;&quot;&quot;</span>
3779
- <a id="__codelineno-0-606" name="__codelineno-0-606"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_option</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">==</span> <span class="n">settings</span><span class="o">.</span><span class="n">FILTERS_NULL_CHOICE_VALUE</span><span class="p">:</span>
3780
- <a id="__codelineno-0-607" name="__codelineno-0-607"></a> <span class="k">return</span> <span class="kc">None</span>
3781
- <a id="__codelineno-0-608" name="__codelineno-0-608"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
4952
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-574">574</a></span>
4953
+ <span class="normal"><a href="#__codelineno-0-575">575</a></span>
4954
+ <span class="normal"><a href="#__codelineno-0-576">576</a></span>
4955
+ <span class="normal"><a href="#__codelineno-0-577">577</a></span>
4956
+ <span class="normal"><a href="#__codelineno-0-578">578</a></span>
4957
+ <span class="normal"><a href="#__codelineno-0-579">579</a></span>
4958
+ <span class="normal"><a href="#__codelineno-0-580">580</a></span>
4959
+ <span class="normal"><a href="#__codelineno-0-581">581</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-574" name="__codelineno-0-574"></a><span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
4960
+ <a id="__codelineno-0-575" name="__codelineno-0-575"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4961
+ <a id="__codelineno-0-576" name="__codelineno-0-576"></a><span class="sd"> When null option is enabled and &quot;None&quot; is sent as part of a form to be submitted, it is sent as the</span>
4962
+ <a id="__codelineno-0-577" name="__codelineno-0-577"></a><span class="sd"> string &#39;null&#39;. This will check for that condition and gracefully handle the conversion to a NoneType.</span>
4963
+ <a id="__codelineno-0-578" name="__codelineno-0-578"></a><span class="sd"> &quot;&quot;&quot;</span>
4964
+ <a id="__codelineno-0-579" name="__codelineno-0-579"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_option</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">and</span> <span class="n">value</span> <span class="o">==</span> <span class="n">settings</span><span class="o">.</span><span class="n">FILTERS_NULL_CHOICE_VALUE</span><span class="p">:</span>
4965
+ <a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="k">return</span> <span class="kc">None</span>
4966
+ <a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
3782
4967
  </code></pre></div></td></tr></table></div>
3783
4968
  </details>
3784
4969
  </div>
@@ -3814,19 +4999,19 @@ string 'null'. This will check for that condition and gracefully handle the con
3814
4999
 
3815
5000
  <details class="quote">
3816
5001
  <summary>Source code in <code>nautobot/core/forms/fields.py</code></summary>
3817
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-611">611</a></span>
3818
- <span class="normal"><a href="#__codelineno-0-612">612</a></span>
3819
- <span class="normal"><a href="#__codelineno-0-613">613</a></span>
3820
- <span class="normal"><a href="#__codelineno-0-614">614</a></span>
3821
- <span class="normal"><a href="#__codelineno-0-615">615</a></span>
3822
- <span class="normal"><a href="#__codelineno-0-616">616</a></span>
3823
- <span class="normal"><a href="#__codelineno-0-617">617</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-611" name="__codelineno-0-611"></a><span class="k">class</span> <span class="nc">DynamicModelMultipleChoiceField</span><span class="p">(</span><span class="n">DynamicModelChoiceMixin</span><span class="p">,</span> <span class="n">django_forms</span><span class="o">.</span><span class="n">ModelMultipleChoiceField</span><span class="p">):</span>
3824
- <a id="__codelineno-0-612" name="__codelineno-0-612"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3825
- <a id="__codelineno-0-613" name="__codelineno-0-613"></a><span class="sd"> A multiple-choice version of DynamicModelChoiceField.</span>
3826
- <a id="__codelineno-0-614" name="__codelineno-0-614"></a><span class="sd"> &quot;&quot;&quot;</span>
3827
- <a id="__codelineno-0-615" name="__codelineno-0-615"></a>
3828
- <a id="__codelineno-0-616" name="__codelineno-0-616"></a> <span class="nb">filter</span> <span class="o">=</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">ModelMultipleChoiceFilter</span>
3829
- <a id="__codelineno-0-617" name="__codelineno-0-617"></a> <span class="n">widget</span> <span class="o">=</span> <span class="n">widgets</span><span class="o">.</span><span class="n">APISelectMultiple</span>
5002
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-584">584</a></span>
5003
+ <span class="normal"><a href="#__codelineno-0-585">585</a></span>
5004
+ <span class="normal"><a href="#__codelineno-0-586">586</a></span>
5005
+ <span class="normal"><a href="#__codelineno-0-587">587</a></span>
5006
+ <span class="normal"><a href="#__codelineno-0-588">588</a></span>
5007
+ <span class="normal"><a href="#__codelineno-0-589">589</a></span>
5008
+ <span class="normal"><a href="#__codelineno-0-590">590</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-584" name="__codelineno-0-584"></a><span class="k">class</span> <span class="nc">DynamicModelMultipleChoiceField</span><span class="p">(</span><span class="n">DynamicModelChoiceMixin</span><span class="p">,</span> <span class="n">django_forms</span><span class="o">.</span><span class="n">ModelMultipleChoiceField</span><span class="p">):</span>
5009
+ <a id="__codelineno-0-585" name="__codelineno-0-585"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5010
+ <a id="__codelineno-0-586" name="__codelineno-0-586"></a><span class="sd"> A multiple-choice version of DynamicModelChoiceField.</span>
5011
+ <a id="__codelineno-0-587" name="__codelineno-0-587"></a><span class="sd"> &quot;&quot;&quot;</span>
5012
+ <a id="__codelineno-0-588" name="__codelineno-0-588"></a>
5013
+ <a id="__codelineno-0-589" name="__codelineno-0-589"></a> <span class="nb">filter</span> <span class="o">=</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">ModelMultipleChoiceFilter</span>
5014
+ <a id="__codelineno-0-590" name="__codelineno-0-590"></a> <span class="n">widget</span> <span class="o">=</span> <span class="n">widgets</span><span class="o">.</span><span class="n">APISelectMultiple</span>
3830
5015
  </code></pre></div></td></tr></table></div>
3831
5016
  </details>
3832
5017
 
@@ -3947,17 +5132,17 @@ NoteModelFormMixin are needed.</p>
3947
5132
 
3948
5133
  <details class="quote">
3949
5134
  <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
3950
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-160">160</a></span>
3951
- <span class="normal"><a href="#__codelineno-0-161">161</a></span>
3952
- <span class="normal"><a href="#__codelineno-0-162">162</a></span>
3953
- <span class="normal"><a href="#__codelineno-0-163">163</a></span>
3954
- <span class="normal"><a href="#__codelineno-0-164">164</a></span>
3955
- <span class="normal"><a href="#__codelineno-0-165">165</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-160" name="__codelineno-0-160"></a><span class="k">class</span> <span class="nc">NoteModelBulkEditFormMixin</span><span class="p">(</span><span class="n">BulkEditForm</span><span class="p">,</span> <span class="n">NoteFormBase</span><span class="p">):</span>
3956
- <a id="__codelineno-0-161" name="__codelineno-0-161"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Bulk-edit form mixin for models that support Notes.&quot;&quot;&quot;</span>
3957
- <a id="__codelineno-0-162" name="__codelineno-0-162"></a>
3958
- <a id="__codelineno-0-163" name="__codelineno-0-163"></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>
3959
- <a id="__codelineno-0-164" name="__codelineno-0-164"></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>
3960
- <a id="__codelineno-0-165" name="__codelineno-0-165"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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>
5135
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-155">155</a></span>
5136
+ <span class="normal"><a href="#__codelineno-0-156">156</a></span>
5137
+ <span class="normal"><a href="#__codelineno-0-157">157</a></span>
5138
+ <span class="normal"><a href="#__codelineno-0-158">158</a></span>
5139
+ <span class="normal"><a href="#__codelineno-0-159">159</a></span>
5140
+ <span class="normal"><a href="#__codelineno-0-160">160</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-155" name="__codelineno-0-155"></a><span class="k">class</span> <span class="nc">NoteModelBulkEditFormMixin</span><span class="p">(</span><span class="n">BulkEditForm</span><span class="p">,</span> <span class="n">NoteFormBase</span><span class="p">):</span>
5141
+ <a id="__codelineno-0-156" name="__codelineno-0-156"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Bulk-edit form mixin for models that support Notes.&quot;&quot;&quot;</span>
5142
+ <a id="__codelineno-0-157" name="__codelineno-0-157"></a>
5143
+ <a id="__codelineno-0-158" name="__codelineno-0-158"></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>
5144
+ <a id="__codelineno-0-159" name="__codelineno-0-159"></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>
5145
+ <a id="__codelineno-0-160" name="__codelineno-0-160"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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>
3961
5146
  </code></pre></div></td></tr></table></div>
3962
5147
  </details>
3963
5148
 
@@ -4002,7 +5187,12 @@ NoteModelFormMixin are needed.</p>
4002
5187
 
4003
5188
  <details class="quote">
4004
5189
  <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
4005
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-175">175</a></span>
5190
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-170">170</a></span>
5191
+ <span class="normal"><a href="#__codelineno-0-171">171</a></span>
5192
+ <span class="normal"><a href="#__codelineno-0-172">172</a></span>
5193
+ <span class="normal"><a href="#__codelineno-0-173">173</a></span>
5194
+ <span class="normal"><a href="#__codelineno-0-174">174</a></span>
5195
+ <span class="normal"><a href="#__codelineno-0-175">175</a></span>
4006
5196
  <span class="normal"><a href="#__codelineno-0-176">176</a></span>
4007
5197
  <span class="normal"><a href="#__codelineno-0-177">177</a></span>
4008
5198
  <span class="normal"><a href="#__codelineno-0-178">178</a></span>
@@ -4264,273 +5454,274 @@ NoteModelFormMixin are needed.</p>
4264
5454
  <span class="normal"><a href="#__codelineno-0-434">434</a></span>
4265
5455
  <span class="normal"><a href="#__codelineno-0-435">435</a></span>
4266
5456
  <span class="normal"><a href="#__codelineno-0-436">436</a></span>
4267
- <span class="normal"><a href="#__codelineno-0-437">437</a></span>
4268
- <span class="normal"><a href="#__codelineno-0-438">438</a></span>
4269
- <span class="normal"><a href="#__codelineno-0-439">439</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-175" name="__codelineno-0-175"></a><span class="k">class</span> <span class="nc">RelationshipModelBulkEditFormMixin</span><span class="p">(</span><span class="n">BulkEditForm</span><span class="p">):</span>
4270
- <a id="__codelineno-0-176" name="__codelineno-0-176"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Bulk-edit form mixin for models that support Relationships.&quot;&quot;&quot;</span>
4271
- <a id="__codelineno-0-177" name="__codelineno-0-177"></a>
4272
- <a id="__codelineno-0-178" name="__codelineno-0-178"></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>
4273
- <a id="__codelineno-0-179" name="__codelineno-0-179"></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>
5457
+ <span class="normal"><a href="#__codelineno-0-437">437</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-170" name="__codelineno-0-170"></a><span class="k">class</span> <span class="nc">RelationshipModelBulkEditFormMixin</span><span class="p">(</span><span class="n">BulkEditForm</span><span class="p">):</span>
5458
+ <a id="__codelineno-0-171" name="__codelineno-0-171"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Bulk-edit form mixin for models that support Relationships.&quot;&quot;&quot;</span>
5459
+ <a id="__codelineno-0-172" name="__codelineno-0-172"></a>
5460
+ <a id="__codelineno-0-173" name="__codelineno-0-173"></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>
5461
+ <a id="__codelineno-0-174" name="__codelineno-0-174"></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>
5462
+ <a id="__codelineno-0-175" name="__codelineno-0-175"></a>
5463
+ <a id="__codelineno-0-176" name="__codelineno-0-176"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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>
5464
+ <a id="__codelineno-0-177" name="__codelineno-0-177"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span> <span class="o">=</span> <span class="p">[]</span>
5465
+ <a id="__codelineno-0-178" name="__codelineno-0-178"></a>
5466
+ <a id="__codelineno-0-179" name="__codelineno-0-179"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships</span><span class="p">()</span>
4274
5467
  <a id="__codelineno-0-180" name="__codelineno-0-180"></a>
4275
- <a id="__codelineno-0-181" name="__codelineno-0-181"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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>
4276
- <a id="__codelineno-0-182" name="__codelineno-0-182"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span> <span class="o">=</span> <span class="p">[]</span>
4277
- <a id="__codelineno-0-183" name="__codelineno-0-183"></a>
4278
- <a id="__codelineno-0-184" name="__codelineno-0-184"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships</span><span class="p">()</span>
4279
- <a id="__codelineno-0-185" name="__codelineno-0-185"></a>
4280
- <a id="__codelineno-0-186" name="__codelineno-0-186"></a> <span class="k">def</span> <span class="nf">_append_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4281
- <a id="__codelineno-0-187" name="__codelineno-0-187"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4282
- <a id="__codelineno-0-188" name="__codelineno-0-188"></a><span class="sd"> Append form fields for all Relationships assigned to this model.</span>
4283
- <a id="__codelineno-0-189" name="__codelineno-0-189"></a><span class="sd"> &quot;&quot;&quot;</span>
4284
- <a id="__codelineno-0-190" name="__codelineno-0-190"></a> <span class="n">source_relationships</span> <span class="o">=</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">source_hidden</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
4285
- <a id="__codelineno-0-191" name="__codelineno-0-191"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">(</span><span class="n">source_relationships</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">)</span>
4286
- <a id="__codelineno-0-192" name="__codelineno-0-192"></a>
4287
- <a id="__codelineno-0-193" name="__codelineno-0-193"></a> <span class="n">dest_relationships</span> <span class="o">=</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">destination_hidden</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
4288
- <a id="__codelineno-0-194" name="__codelineno-0-194"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">(</span><span class="n">dest_relationships</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">)</span>
4289
- <a id="__codelineno-0-195" name="__codelineno-0-195"></a>
4290
- <a id="__codelineno-0-196" name="__codelineno-0-196"></a> <span class="k">def</span> <span class="nf">_append_relationships_side</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">relationships</span><span class="p">,</span> <span class="n">initial_side</span><span class="p">):</span>
4291
- <a id="__codelineno-0-197" name="__codelineno-0-197"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4292
- <a id="__codelineno-0-198" name="__codelineno-0-198"></a><span class="sd"> Helper method to _append_relationships, for processing one &quot;side&quot; of the relationships for this model.</span>
4293
- <a id="__codelineno-0-199" name="__codelineno-0-199"></a>
4294
- <a id="__codelineno-0-200" name="__codelineno-0-200"></a><span class="sd"> For different relationship types there are different expectations of the UI:</span>
4295
- <a id="__codelineno-0-201" name="__codelineno-0-201"></a>
4296
- <a id="__codelineno-0-202" name="__codelineno-0-202"></a><span class="sd"> - For one-to-one (symmetric or non-symmetric) it doesn&#39;t make sense to bulk-set this relationship,</span>
4297
- <a id="__codelineno-0-203" name="__codelineno-0-203"></a><span class="sd"> but we want it to be clearable/nullable.</span>
4298
- <a id="__codelineno-0-204" name="__codelineno-0-204"></a><span class="sd"> - For one-to-many (from the source, &quot;one&quot;, side) we likewise want it clearable/nullable but not settable.</span>
4299
- <a id="__codelineno-0-205" name="__codelineno-0-205"></a><span class="sd"> - For one-to-many (from the destination, &quot;many&quot;, side) a single value can be set, or it can be nulled.</span>
4300
- <a id="__codelineno-0-206" name="__codelineno-0-206"></a><span class="sd"> - For many-to-many (symmetric or non-symmetric) we provide &quot;add&quot; and &quot;remove&quot; multi-select fields,</span>
4301
- <a id="__codelineno-0-207" name="__codelineno-0-207"></a><span class="sd"> similar to the TagsBulkEditFormMixin behavior. No nullability is provided here.</span>
4302
- <a id="__codelineno-0-208" name="__codelineno-0-208"></a><span class="sd"> &quot;&quot;&quot;</span>
4303
- <a id="__codelineno-0-209" name="__codelineno-0-209"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
4304
- <a id="__codelineno-0-210" name="__codelineno-0-210"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
4305
- <a id="__codelineno-0-211" name="__codelineno-0-211"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span>
4306
- <a id="__codelineno-0-212" name="__codelineno-0-212"></a> <span class="k">else</span><span class="p">:</span>
4307
- <a id="__codelineno-0-213" name="__codelineno-0-213"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">initial_side</span>
4308
- <a id="__codelineno-0-214" name="__codelineno-0-214"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
4309
- <a id="__codelineno-0-215" name="__codelineno-0-215"></a>
4310
- <a id="__codelineno-0-216" name="__codelineno-0-216"></a> <span class="c1"># If this model is on the &quot;source&quot; side of the relationship, then the field will be named</span>
4311
- <a id="__codelineno-0-217" name="__codelineno-0-217"></a> <span class="c1"># &quot;cr_&lt;relationship-slug&gt;__destination&quot; since it&#39;s used to pick the destination object(s).</span>
4312
- <a id="__codelineno-0-218" name="__codelineno-0-218"></a> <span class="c1"># If we&#39;re on the &quot;destination&quot; side, the field will be &quot;cr_&lt;relationship-slug&gt;__source&quot;.</span>
4313
- <a id="__codelineno-0-219" name="__codelineno-0-219"></a> <span class="c1"># For a symmetric relationship, both sides are &quot;peer&quot;, so the field will be &quot;cr_&lt;relationship-slug&gt;__peer&quot;</span>
4314
- <a id="__codelineno-0-220" name="__codelineno-0-220"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">slug</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
5468
+ <a id="__codelineno-0-181" name="__codelineno-0-181"></a> <span class="k">def</span> <span class="nf">_append_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5469
+ <a id="__codelineno-0-182" name="__codelineno-0-182"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5470
+ <a id="__codelineno-0-183" name="__codelineno-0-183"></a><span class="sd"> Append form fields for all Relationships assigned to this model.</span>
5471
+ <a id="__codelineno-0-184" name="__codelineno-0-184"></a><span class="sd"> &quot;&quot;&quot;</span>
5472
+ <a id="__codelineno-0-185" name="__codelineno-0-185"></a> <span class="n">source_relationships</span> <span class="o">=</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">source_hidden</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
5473
+ <a id="__codelineno-0-186" name="__codelineno-0-186"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">(</span><span class="n">source_relationships</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">)</span>
5474
+ <a id="__codelineno-0-187" name="__codelineno-0-187"></a>
5475
+ <a id="__codelineno-0-188" name="__codelineno-0-188"></a> <span class="n">dest_relationships</span> <span class="o">=</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">destination_hidden</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span>
5476
+ <a id="__codelineno-0-189" name="__codelineno-0-189"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">(</span><span class="n">dest_relationships</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">)</span>
5477
+ <a id="__codelineno-0-190" name="__codelineno-0-190"></a>
5478
+ <a id="__codelineno-0-191" name="__codelineno-0-191"></a> <span class="k">def</span> <span class="nf">_append_relationships_side</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">relationships</span><span class="p">,</span> <span class="n">initial_side</span><span class="p">):</span>
5479
+ <a id="__codelineno-0-192" name="__codelineno-0-192"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5480
+ <a id="__codelineno-0-193" name="__codelineno-0-193"></a><span class="sd"> Helper method to _append_relationships, for processing one &quot;side&quot; of the relationships for this model.</span>
5481
+ <a id="__codelineno-0-194" name="__codelineno-0-194"></a>
5482
+ <a id="__codelineno-0-195" name="__codelineno-0-195"></a><span class="sd"> For different relationship types there are different expectations of the UI:</span>
5483
+ <a id="__codelineno-0-196" name="__codelineno-0-196"></a>
5484
+ <a id="__codelineno-0-197" name="__codelineno-0-197"></a><span class="sd"> - For one-to-one (symmetric or non-symmetric) it doesn&#39;t make sense to bulk-set this relationship,</span>
5485
+ <a id="__codelineno-0-198" name="__codelineno-0-198"></a><span class="sd"> but we want it to be clearable/nullable.</span>
5486
+ <a id="__codelineno-0-199" name="__codelineno-0-199"></a><span class="sd"> - For one-to-many (from the source, &quot;one&quot;, side) we likewise want it clearable/nullable but not settable.</span>
5487
+ <a id="__codelineno-0-200" name="__codelineno-0-200"></a><span class="sd"> - For one-to-many (from the destination, &quot;many&quot;, side) a single value can be set, or it can be nulled.</span>
5488
+ <a id="__codelineno-0-201" name="__codelineno-0-201"></a><span class="sd"> - For many-to-many (symmetric or non-symmetric) we provide &quot;add&quot; and &quot;remove&quot; multi-select fields,</span>
5489
+ <a id="__codelineno-0-202" name="__codelineno-0-202"></a><span class="sd"> similar to the TagsBulkEditFormMixin behavior. No nullability is provided here.</span>
5490
+ <a id="__codelineno-0-203" name="__codelineno-0-203"></a><span class="sd"> &quot;&quot;&quot;</span>
5491
+ <a id="__codelineno-0-204" name="__codelineno-0-204"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
5492
+ <a id="__codelineno-0-205" name="__codelineno-0-205"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
5493
+ <a id="__codelineno-0-206" name="__codelineno-0-206"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span>
5494
+ <a id="__codelineno-0-207" name="__codelineno-0-207"></a> <span class="k">else</span><span class="p">:</span>
5495
+ <a id="__codelineno-0-208" name="__codelineno-0-208"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">initial_side</span>
5496
+ <a id="__codelineno-0-209" name="__codelineno-0-209"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
5497
+ <a id="__codelineno-0-210" name="__codelineno-0-210"></a>
5498
+ <a id="__codelineno-0-211" name="__codelineno-0-211"></a> <span class="c1"># If this model is on the &quot;source&quot; side of the relationship, then the field will be named</span>
5499
+ <a id="__codelineno-0-212" name="__codelineno-0-212"></a> <span class="c1"># &quot;cr_&lt;relationship_key&gt;__destination&quot; since it&#39;s used to pick the destination object(s).</span>
5500
+ <a id="__codelineno-0-213" name="__codelineno-0-213"></a> <span class="c1"># If we&#39;re on the &quot;destination&quot; side, the field will be &quot;cr_&lt;relationship_key&gt;__source&quot;.</span>
5501
+ <a id="__codelineno-0-214" name="__codelineno-0-214"></a> <span class="c1"># For a symmetric relationship, both sides are &quot;peer&quot;, so the field will be &quot;cr_&lt;relationship_key&gt;__peer&quot;</span>
5502
+ <a id="__codelineno-0-215" name="__codelineno-0-215"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
5503
+ <a id="__codelineno-0-216" name="__codelineno-0-216"></a>
5504
+ <a id="__codelineno-0-217" name="__codelineno-0-217"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="p">:</span>
5505
+ <a id="__codelineno-0-218" name="__codelineno-0-218"></a> <span class="c1"># This is a symmetric relationship that we already processed from the opposing &quot;initial_side&quot;.</span>
5506
+ <a id="__codelineno-0-219" name="__codelineno-0-219"></a> <span class="c1"># No need to process it a second time!</span>
5507
+ <a id="__codelineno-0-220" name="__codelineno-0-220"></a> <span class="k">continue</span>
4315
5508
  <a id="__codelineno-0-221" name="__codelineno-0-221"></a>
4316
- <a id="__codelineno-0-222" name="__codelineno-0-222"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="p">:</span>
4317
- <a id="__codelineno-0-223" name="__codelineno-0-223"></a> <span class="c1"># This is a symmetric relationship that we already processed from the opposing &quot;initial_side&quot;.</span>
4318
- <a id="__codelineno-0-224" name="__codelineno-0-224"></a> <span class="c1"># No need to process it a second time!</span>
4319
- <a id="__codelineno-0-225" name="__codelineno-0-225"></a> <span class="k">continue</span>
4320
- <a id="__codelineno-0-226" name="__codelineno-0-226"></a>
4321
- <a id="__codelineno-0-227" name="__codelineno-0-227"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">side</span><span class="p">):</span>
4322
- <a id="__codelineno-0-228" name="__codelineno-0-228"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">RelationshipTypeChoices</span><span class="o">.</span><span class="n">TYPE_ONE_TO_MANY</span><span class="p">:</span>
4323
- <a id="__codelineno-0-229" name="__codelineno-0-229"></a> <span class="c1"># Destination side of a one-to-many field - provide a standard form field for selecting the &quot;one&quot;,</span>
4324
- <a id="__codelineno-0-230" name="__codelineno-0-230"></a> <span class="c1"># as well as making this field nullable.</span>
4325
- <a id="__codelineno-0-231" name="__codelineno-0-231"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
4326
- <a id="__codelineno-0-232" name="__codelineno-0-232"></a> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4327
- <a id="__codelineno-0-233" name="__codelineno-0-233"></a> <span class="k">else</span><span class="p">:</span>
4328
- <a id="__codelineno-0-234" name="__codelineno-0-234"></a> <span class="c1"># Many-to-many field - provide &quot;add&quot; and &quot;remove&quot; form fields like with tags, no nullable option.</span>
4329
- <a id="__codelineno-0-235" name="__codelineno-0-235"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
4330
- <a id="__codelineno-0-236" name="__codelineno-0-236"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="s2">&quot;Add &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span>
4331
- <a id="__codelineno-0-237" name="__codelineno-0-237"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
4332
- <a id="__codelineno-0-238" name="__codelineno-0-238"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="s2">&quot;Remove &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span>
4333
- <a id="__codelineno-0-239" name="__codelineno-0-239"></a> <span class="k">else</span><span class="p">:</span>
4334
- <a id="__codelineno-0-240" name="__codelineno-0-240"></a> <span class="c1"># The &quot;one&quot; side of a one-to-one or one-to-many relationship.</span>
4335
- <a id="__codelineno-0-241" name="__codelineno-0-241"></a> <span class="c1"># In this case, the only valid bulk-edit operation is nulling/clearing the relationship,</span>
4336
- <a id="__codelineno-0-242" name="__codelineno-0-242"></a> <span class="c1"># but the &quot;Set null&quot; checkbox only appears if we have a form field for the the relationship itself.</span>
4337
- <a id="__codelineno-0-243" name="__codelineno-0-243"></a> <span class="c1"># This could probably be refined, but for now we just add the field and disable it.</span>
4338
- <a id="__codelineno-0-244" name="__codelineno-0-244"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
4339
- <a id="__codelineno-0-245" name="__codelineno-0-245"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">disabled</span> <span class="o">=</span> <span class="kc">True</span>
4340
- <a id="__codelineno-0-246" name="__codelineno-0-246"></a> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4341
- <a id="__codelineno-0-247" name="__codelineno-0-247"></a>
4342
- <a id="__codelineno-0-248" name="__codelineno-0-248"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4343
- <a id="__codelineno-0-249" name="__codelineno-0-249"></a>
4344
- <a id="__codelineno-0-250" name="__codelineno-0-250"></a> <span class="k">def</span> <span class="nf">save_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">nullified_fields</span><span class="p">):</span>
4345
- <a id="__codelineno-0-251" name="__codelineno-0-251"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Helper method to be called from BulkEditView.post().&quot;&quot;&quot;</span>
4346
- <a id="__codelineno-0-252" name="__codelineno-0-252"></a> <span class="c1"># The below may seem inefficient as it re-loads the Relationship objects afresh for each instance;</span>
4347
- <a id="__codelineno-0-253" name="__codelineno-0-253"></a> <span class="c1"># however this is necessary as it applies the source/destination filters (if any) to determine</span>
4348
- <a id="__codelineno-0-254" name="__codelineno-0-254"></a> <span class="c1"># whether each relationship actually applies to the given instance.</span>
4349
- <a id="__codelineno-0-255" name="__codelineno-0-255"></a> <span class="n">instance_relationships</span> <span class="o">=</span> <span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">(</span><span class="n">include_hidden</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
4350
- <a id="__codelineno-0-256" name="__codelineno-0-256"></a>
4351
- <a id="__codelineno-0-257" name="__codelineno-0-257"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships_data</span> <span class="ow">in</span> <span class="n">instance_relationships</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4352
- <a id="__codelineno-0-258" name="__codelineno-0-258"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
4353
- <a id="__codelineno-0-259" name="__codelineno-0-259"></a> <span class="k">for</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">relationshipassociation_queryset</span> <span class="ow">in</span> <span class="n">relationships_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4354
- <a id="__codelineno-0-260" name="__codelineno-0-260"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">slug</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
4355
- <a id="__codelineno-0-261" name="__codelineno-0-261"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
4356
- <a id="__codelineno-0-262" name="__codelineno-0-262"></a> <span class="s2">&quot;Processing relationship </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> (field </span><span class="si">%s</span><span class="s2">) for instance </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
4357
- <a id="__codelineno-0-263" name="__codelineno-0-263"></a> <span class="n">relationship</span><span class="p">,</span>
4358
- <a id="__codelineno-0-264" name="__codelineno-0-264"></a> <span class="n">side</span><span class="p">,</span>
4359
- <a id="__codelineno-0-265" name="__codelineno-0-265"></a> <span class="n">field_name</span><span class="p">,</span>
4360
- <a id="__codelineno-0-266" name="__codelineno-0-266"></a> <span class="n">instance</span><span class="p">,</span>
4361
- <a id="__codelineno-0-267" name="__codelineno-0-267"></a> <span class="p">)</span>
4362
- <a id="__codelineno-0-268" name="__codelineno-0-268"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span> <span class="ow">and</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">nullified_fields</span><span class="p">:</span>
4363
- <a id="__codelineno-0-269" name="__codelineno-0-269"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleting existing relationship associations for </span><span class="si">%s</span><span class="s2"> on </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">instance</span><span class="p">)</span>
4364
- <a id="__codelineno-0-270" name="__codelineno-0-270"></a> <span class="n">relationshipassociation_queryset</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
4365
- <a id="__codelineno-0-271" name="__codelineno-0-271"></a> <span class="k">elif</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4366
- <a id="__codelineno-0-272" name="__codelineno-0-272"></a> <span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4367
- <a id="__codelineno-0-273" name="__codelineno-0-273"></a> <span class="k">if</span> <span class="n">value</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
4368
- <a id="__codelineno-0-274" name="__codelineno-0-274"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
4369
- <a id="__codelineno-0-275" name="__codelineno-0-275"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4370
- <a id="__codelineno-0-276" name="__codelineno-0-276"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
4371
- <a id="__codelineno-0-277" name="__codelineno-0-277"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
4372
- <a id="__codelineno-0-278" name="__codelineno-0-278"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">value</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
4373
- <a id="__codelineno-0-279" name="__codelineno-0-279"></a> <span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
4374
- <a id="__codelineno-0-280" name="__codelineno-0-280"></a> <span class="p">)</span>
4375
- <a id="__codelineno-0-281" name="__codelineno-0-281"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
4376
- <a id="__codelineno-0-282" name="__codelineno-0-282"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
4377
- <a id="__codelineno-0-283" name="__codelineno-0-283"></a> <span class="k">else</span><span class="p">:</span>
4378
- <a id="__codelineno-0-284" name="__codelineno-0-284"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Updated </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
4379
- <a id="__codelineno-0-285" name="__codelineno-0-285"></a> <span class="k">else</span><span class="p">:</span>
4380
- <a id="__codelineno-0-286" name="__codelineno-0-286"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4381
- <a id="__codelineno-0-287" name="__codelineno-0-287"></a> <span class="n">added</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4382
- <a id="__codelineno-0-288" name="__codelineno-0-288"></a> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">added</span><span class="p">:</span>
4383
- <a id="__codelineno-0-289" name="__codelineno-0-289"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
4384
- <a id="__codelineno-0-290" name="__codelineno-0-290"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">(</span>
4385
- <a id="__codelineno-0-291" name="__codelineno-0-291"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4386
- <a id="__codelineno-0-292" name="__codelineno-0-292"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
4387
- <a id="__codelineno-0-293" name="__codelineno-0-293"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
4388
- <a id="__codelineno-0-294" name="__codelineno-0-294"></a> <span class="o">**</span><span class="p">{</span>
4389
- <a id="__codelineno-0-295" name="__codelineno-0-295"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4390
- <a id="__codelineno-0-296" name="__codelineno-0-296"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4391
- <a id="__codelineno-0-297" name="__codelineno-0-297"></a> <span class="p">},</span>
4392
- <a id="__codelineno-0-298" name="__codelineno-0-298"></a> <span class="p">)</span>
4393
- <a id="__codelineno-0-299" name="__codelineno-0-299"></a> <span class="k">else</span><span class="p">:</span>
4394
- <a id="__codelineno-0-300" name="__codelineno-0-300"></a> <span class="k">if</span> <span class="p">(</span>
4395
- <a id="__codelineno-0-301" name="__codelineno-0-301"></a> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5509
+ <a id="__codelineno-0-222" name="__codelineno-0-222"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">side</span><span class="p">):</span>
5510
+ <a id="__codelineno-0-223" name="__codelineno-0-223"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">type</span> <span class="o">==</span> <span class="n">RelationshipTypeChoices</span><span class="o">.</span><span class="n">TYPE_ONE_TO_MANY</span><span class="p">:</span>
5511
+ <a id="__codelineno-0-224" name="__codelineno-0-224"></a> <span class="c1"># Destination side of a one-to-many field - provide a standard form field for selecting the &quot;one&quot;,</span>
5512
+ <a id="__codelineno-0-225" name="__codelineno-0-225"></a> <span class="c1"># as well as making this field nullable.</span>
5513
+ <a id="__codelineno-0-226" name="__codelineno-0-226"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
5514
+ <a id="__codelineno-0-227" name="__codelineno-0-227"></a> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5515
+ <a id="__codelineno-0-228" name="__codelineno-0-228"></a> <span class="k">else</span><span class="p">:</span>
5516
+ <a id="__codelineno-0-229" name="__codelineno-0-229"></a> <span class="c1"># Many-to-many field - provide &quot;add&quot; and &quot;remove&quot; form fields like with tags, no nullable option.</span>
5517
+ <a id="__codelineno-0-230" name="__codelineno-0-230"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
5518
+ <a id="__codelineno-0-231" name="__codelineno-0-231"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="s2">&quot;Add &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span>
5519
+ <a id="__codelineno-0-232" name="__codelineno-0-232"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
5520
+ <a id="__codelineno-0-233" name="__codelineno-0-233"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="s2">&quot;Remove &quot;</span> <span class="o">+</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span><span class="o">.</span><span class="n">label</span>
5521
+ <a id="__codelineno-0-234" name="__codelineno-0-234"></a> <span class="k">else</span><span class="p">:</span>
5522
+ <a id="__codelineno-0-235" name="__codelineno-0-235"></a> <span class="c1"># The &quot;one&quot; side of a one-to-one or one-to-many relationship.</span>
5523
+ <a id="__codelineno-0-236" name="__codelineno-0-236"></a> <span class="c1"># In this case, the only valid bulk-edit operation is nulling/clearing the relationship,</span>
5524
+ <a id="__codelineno-0-237" name="__codelineno-0-237"></a> <span class="c1"># but the &quot;Set null&quot; checkbox only appears if we have a form field for the the relationship itself.</span>
5525
+ <a id="__codelineno-0-238" name="__codelineno-0-238"></a> <span class="c1"># This could probably be refined, but for now we just add the field and disable it.</span>
5526
+ <a id="__codelineno-0-239" name="__codelineno-0-239"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
5527
+ <a id="__codelineno-0-240" name="__codelineno-0-240"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">disabled</span> <span class="o">=</span> <span class="kc">True</span>
5528
+ <a id="__codelineno-0-241" name="__codelineno-0-241"></a> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5529
+ <a id="__codelineno-0-242" name="__codelineno-0-242"></a>
5530
+ <a id="__codelineno-0-243" name="__codelineno-0-243"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5531
+ <a id="__codelineno-0-244" name="__codelineno-0-244"></a>
5532
+ <a id="__codelineno-0-245" name="__codelineno-0-245"></a> <span class="k">def</span> <span class="nf">save_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">nullified_fields</span><span class="p">):</span>
5533
+ <a id="__codelineno-0-246" name="__codelineno-0-246"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Helper method to be called from BulkEditView.post().&quot;&quot;&quot;</span>
5534
+ <a id="__codelineno-0-247" name="__codelineno-0-247"></a> <span class="c1"># The below may seem inefficient as it re-loads the Relationship objects afresh for each instance;</span>
5535
+ <a id="__codelineno-0-248" name="__codelineno-0-248"></a> <span class="c1"># however this is necessary as it applies the source/destination filters (if any) to determine</span>
5536
+ <a id="__codelineno-0-249" name="__codelineno-0-249"></a> <span class="c1"># whether each relationship actually applies to the given instance.</span>
5537
+ <a id="__codelineno-0-250" name="__codelineno-0-250"></a> <span class="n">instance_relationships</span> <span class="o">=</span> <span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">(</span><span class="n">include_hidden</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
5538
+ <a id="__codelineno-0-251" name="__codelineno-0-251"></a>
5539
+ <a id="__codelineno-0-252" name="__codelineno-0-252"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships_data</span> <span class="ow">in</span> <span class="n">instance_relationships</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5540
+ <a id="__codelineno-0-253" name="__codelineno-0-253"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
5541
+ <a id="__codelineno-0-254" name="__codelineno-0-254"></a> <span class="k">for</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">relationshipassociation_queryset</span> <span class="ow">in</span> <span class="n">relationships_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5542
+ <a id="__codelineno-0-255" name="__codelineno-0-255"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
5543
+ <a id="__codelineno-0-256" name="__codelineno-0-256"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
5544
+ <a id="__codelineno-0-257" name="__codelineno-0-257"></a> <span class="s2">&quot;Processing relationship </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> (field </span><span class="si">%s</span><span class="s2">) for instance </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
5545
+ <a id="__codelineno-0-258" name="__codelineno-0-258"></a> <span class="n">relationship</span><span class="p">,</span>
5546
+ <a id="__codelineno-0-259" name="__codelineno-0-259"></a> <span class="n">side</span><span class="p">,</span>
5547
+ <a id="__codelineno-0-260" name="__codelineno-0-260"></a> <span class="n">field_name</span><span class="p">,</span>
5548
+ <a id="__codelineno-0-261" name="__codelineno-0-261"></a> <span class="n">instance</span><span class="p">,</span>
5549
+ <a id="__codelineno-0-262" name="__codelineno-0-262"></a> <span class="p">)</span>
5550
+ <a id="__codelineno-0-263" name="__codelineno-0-263"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span> <span class="ow">and</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">nullified_fields</span><span class="p">:</span>
5551
+ <a id="__codelineno-0-264" name="__codelineno-0-264"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleting existing relationship associations for </span><span class="si">%s</span><span class="s2"> on </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">instance</span><span class="p">)</span>
5552
+ <a id="__codelineno-0-265" name="__codelineno-0-265"></a> <span class="n">relationshipassociation_queryset</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
5553
+ <a id="__codelineno-0-266" name="__codelineno-0-266"></a> <span class="k">elif</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5554
+ <a id="__codelineno-0-267" name="__codelineno-0-267"></a> <span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5555
+ <a id="__codelineno-0-268" name="__codelineno-0-268"></a> <span class="k">if</span> <span class="n">value</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
5556
+ <a id="__codelineno-0-269" name="__codelineno-0-269"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
5557
+ <a id="__codelineno-0-270" name="__codelineno-0-270"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5558
+ <a id="__codelineno-0-271" name="__codelineno-0-271"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
5559
+ <a id="__codelineno-0-272" name="__codelineno-0-272"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
5560
+ <a id="__codelineno-0-273" name="__codelineno-0-273"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">value</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
5561
+ <a id="__codelineno-0-274" name="__codelineno-0-274"></a> <span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
5562
+ <a id="__codelineno-0-275" name="__codelineno-0-275"></a> <span class="p">)</span>
5563
+ <a id="__codelineno-0-276" name="__codelineno-0-276"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
5564
+ <a id="__codelineno-0-277" name="__codelineno-0-277"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
5565
+ <a id="__codelineno-0-278" name="__codelineno-0-278"></a> <span class="k">else</span><span class="p">:</span>
5566
+ <a id="__codelineno-0-279" name="__codelineno-0-279"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Updated </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
5567
+ <a id="__codelineno-0-280" name="__codelineno-0-280"></a> <span class="k">else</span><span class="p">:</span>
5568
+ <a id="__codelineno-0-281" name="__codelineno-0-281"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5569
+ <a id="__codelineno-0-282" name="__codelineno-0-282"></a> <span class="n">added</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5570
+ <a id="__codelineno-0-283" name="__codelineno-0-283"></a> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">added</span><span class="p">:</span>
5571
+ <a id="__codelineno-0-284" name="__codelineno-0-284"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
5572
+ <a id="__codelineno-0-285" name="__codelineno-0-285"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">(</span>
5573
+ <a id="__codelineno-0-286" name="__codelineno-0-286"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5574
+ <a id="__codelineno-0-287" name="__codelineno-0-287"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
5575
+ <a id="__codelineno-0-288" name="__codelineno-0-288"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
5576
+ <a id="__codelineno-0-289" name="__codelineno-0-289"></a> <span class="o">**</span><span class="p">{</span>
5577
+ <a id="__codelineno-0-290" name="__codelineno-0-290"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5578
+ <a id="__codelineno-0-291" name="__codelineno-0-291"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5579
+ <a id="__codelineno-0-292" name="__codelineno-0-292"></a> <span class="p">},</span>
5580
+ <a id="__codelineno-0-293" name="__codelineno-0-293"></a> <span class="p">)</span>
5581
+ <a id="__codelineno-0-294" name="__codelineno-0-294"></a> <span class="k">else</span><span class="p">:</span>
5582
+ <a id="__codelineno-0-295" name="__codelineno-0-295"></a> <span class="k">if</span> <span class="p">(</span>
5583
+ <a id="__codelineno-0-296" name="__codelineno-0-296"></a> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5584
+ <a id="__codelineno-0-297" name="__codelineno-0-297"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5585
+ <a id="__codelineno-0-298" name="__codelineno-0-298"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5586
+ <a id="__codelineno-0-299" name="__codelineno-0-299"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5587
+ <a id="__codelineno-0-300" name="__codelineno-0-300"></a> <span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
5588
+ <a id="__codelineno-0-301" name="__codelineno-0-301"></a> <span class="ow">or</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4396
5589
  <a id="__codelineno-0-302" name="__codelineno-0-302"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4397
- <a id="__codelineno-0-303" name="__codelineno-0-303"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4398
- <a id="__codelineno-0-304" name="__codelineno-0-304"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5590
+ <a id="__codelineno-0-303" name="__codelineno-0-303"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5591
+ <a id="__codelineno-0-304" name="__codelineno-0-304"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4399
5592
  <a id="__codelineno-0-305" name="__codelineno-0-305"></a> <span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
4400
- <a id="__codelineno-0-306" name="__codelineno-0-306"></a> <span class="ow">or</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4401
- <a id="__codelineno-0-307" name="__codelineno-0-307"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4402
- <a id="__codelineno-0-308" name="__codelineno-0-308"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4403
- <a id="__codelineno-0-309" name="__codelineno-0-309"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4404
- <a id="__codelineno-0-310" name="__codelineno-0-310"></a> <span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
4405
- <a id="__codelineno-0-311" name="__codelineno-0-311"></a> <span class="p">):</span>
4406
- <a id="__codelineno-0-312" name="__codelineno-0-312"></a> <span class="n">ra</span> <span class="o">=</span> <span class="kc">None</span>
4407
- <a id="__codelineno-0-313" name="__codelineno-0-313"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">False</span>
4408
- <a id="__codelineno-0-314" name="__codelineno-0-314"></a> <span class="k">else</span><span class="p">:</span>
4409
- <a id="__codelineno-0-315" name="__codelineno-0-315"></a> <span class="n">ra</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
4410
- <a id="__codelineno-0-316" name="__codelineno-0-316"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4411
- <a id="__codelineno-0-317" name="__codelineno-0-317"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
4412
- <a id="__codelineno-0-318" name="__codelineno-0-318"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4413
- <a id="__codelineno-0-319" name="__codelineno-0-319"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
4414
- <a id="__codelineno-0-320" name="__codelineno-0-320"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4415
- <a id="__codelineno-0-321" name="__codelineno-0-321"></a> <span class="p">)</span>
4416
- <a id="__codelineno-0-322" name="__codelineno-0-322"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">True</span>
4417
- <a id="__codelineno-0-323" name="__codelineno-0-323"></a>
4418
- <a id="__codelineno-0-324" name="__codelineno-0-324"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
4419
- <a id="__codelineno-0-325" name="__codelineno-0-325"></a> <span class="n">ra</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
4420
- <a id="__codelineno-0-326" name="__codelineno-0-326"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
4421
- <a id="__codelineno-0-327" name="__codelineno-0-327"></a>
4422
- <a id="__codelineno-0-328" name="__codelineno-0-328"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4423
- <a id="__codelineno-0-329" name="__codelineno-0-329"></a> <span class="n">removed</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4424
- <a id="__codelineno-0-330" name="__codelineno-0-330"></a>
4425
- <a id="__codelineno-0-331" name="__codelineno-0-331"></a> <span class="n">source_count</span> <span class="o">=</span> <span class="mi">0</span>
4426
- <a id="__codelineno-0-332" name="__codelineno-0-332"></a> <span class="n">destination_count</span> <span class="o">=</span> <span class="mi">0</span>
4427
- <a id="__codelineno-0-333" name="__codelineno-0-333"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
4428
- <a id="__codelineno-0-334" name="__codelineno-0-334"></a> <span class="n">source_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4429
- <a id="__codelineno-0-335" name="__codelineno-0-335"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4430
- <a id="__codelineno-0-336" name="__codelineno-0-336"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4431
- <a id="__codelineno-0-337" name="__codelineno-0-337"></a> <span class="n">destination_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
4432
- <a id="__codelineno-0-338" name="__codelineno-0-338"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
4433
- <a id="__codelineno-0-339" name="__codelineno-0-339"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
4434
- <a id="__codelineno-0-340" name="__codelineno-0-340"></a> <span class="n">destination_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4435
- <a id="__codelineno-0-341" name="__codelineno-0-341"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4436
- <a id="__codelineno-0-342" name="__codelineno-0-342"></a> <span class="n">source_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
4437
- <a id="__codelineno-0-343" name="__codelineno-0-343"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4438
- <a id="__codelineno-0-344" name="__codelineno-0-344"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
4439
- <a id="__codelineno-0-345" name="__codelineno-0-345"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleted </span><span class="si">%s</span><span class="s2"> RelationshipAssociation(s)&quot;</span><span class="p">,</span> <span class="n">source_count</span> <span class="o">+</span> <span class="n">destination_count</span><span class="p">)</span>
4440
- <a id="__codelineno-0-346" name="__codelineno-0-346"></a>
4441
- <a id="__codelineno-0-347" name="__codelineno-0-347"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4442
- <a id="__codelineno-0-348" name="__codelineno-0-348"></a> <span class="c1"># Get any initial required relationship objects errors (i.e. non-existent required objects)</span>
4443
- <a id="__codelineno-0-349" name="__codelineno-0-349"></a> <span class="n">required_objects_errors</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">required_related_objects_errors</span><span class="p">(</span><span class="n">output_for</span><span class="o">=</span><span class="s2">&quot;ui&quot;</span><span class="p">)</span>
4444
- <a id="__codelineno-0-350" name="__codelineno-0-350"></a> <span class="n">already_invalidated_slugs</span> <span class="o">=</span> <span class="p">[]</span>
4445
- <a id="__codelineno-0-351" name="__codelineno-0-351"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">errors</span> <span class="ow">in</span> <span class="n">required_objects_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4446
- <a id="__codelineno-0-352" name="__codelineno-0-352"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span>
4447
- <a id="__codelineno-0-353" name="__codelineno-0-353"></a> <span class="n">relationship_slug</span> <span class="o">=</span> <span class="n">field</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="mi">0</span><span class="p">][</span><span class="mi">3</span><span class="p">:]</span>
4448
- <a id="__codelineno-0-354" name="__codelineno-0-354"></a> <span class="n">already_invalidated_slugs</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">relationship_slug</span><span class="p">)</span>
4449
- <a id="__codelineno-0-355" name="__codelineno-0-355"></a>
4450
- <a id="__codelineno-0-356" name="__codelineno-0-356"></a> <span class="n">required_relationships</span> <span class="o">=</span> <span class="p">[]</span>
4451
- <a id="__codelineno-0-357" name="__codelineno-0-357"></a> <span class="c1"># The following query excludes already invalidated relationships (this happened above</span>
4452
- <a id="__codelineno-0-358" name="__codelineno-0-358"></a> <span class="c1"># by checking for the existence of required objects</span>
4453
- <a id="__codelineno-0-359" name="__codelineno-0-359"></a> <span class="c1"># with the call to self.Meta().model.required_related_objects_errors(output_for=&quot;ui&quot;))</span>
4454
- <a id="__codelineno-0-360" name="__codelineno-0-360"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_required_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><span class="o">.</span><span class="n">exclude</span><span class="p">(</span>
4455
- <a id="__codelineno-0-361" name="__codelineno-0-361"></a> <span class="n">slug__in</span><span class="o">=</span><span class="n">already_invalidated_slugs</span>
4456
- <a id="__codelineno-0-362" name="__codelineno-0-362"></a> <span class="p">):</span>
4457
- <a id="__codelineno-0-363" name="__codelineno-0-363"></a> <span class="n">required_relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
4458
- <a id="__codelineno-0-364" name="__codelineno-0-364"></a> <span class="p">{</span>
4459
- <a id="__codelineno-0-365" name="__codelineno-0-365"></a> <span class="s2">&quot;slug&quot;</span><span class="p">:</span> <span class="n">relationship</span><span class="o">.</span><span class="n">slug</span><span class="p">,</span>
4460
- <a id="__codelineno-0-366" name="__codelineno-0-366"></a> <span class="s2">&quot;required_side&quot;</span><span class="p">:</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="p">],</span>
4461
- <a id="__codelineno-0-367" name="__codelineno-0-367"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="n">relationship</span><span class="p">,</span>
4462
- <a id="__codelineno-0-368" name="__codelineno-0-368"></a> <span class="p">}</span>
4463
- <a id="__codelineno-0-369" name="__codelineno-0-369"></a> <span class="p">)</span>
4464
- <a id="__codelineno-0-370" name="__codelineno-0-370"></a>
4465
- <a id="__codelineno-0-371" name="__codelineno-0-371"></a> <span class="c1"># Get difference of add/remove objects for each required relationship:</span>
4466
- <a id="__codelineno-0-372" name="__codelineno-0-372"></a> <span class="n">required_relationships_to_check</span> <span class="o">=</span> <span class="p">[]</span>
4467
- <a id="__codelineno-0-373" name="__codelineno-0-373"></a> <span class="k">for</span> <span class="n">required_relationship</span> <span class="ow">in</span> <span class="n">required_relationships</span><span class="p">:</span>
4468
- <a id="__codelineno-0-374" name="__codelineno-0-374"></a> <span class="n">required_field</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">required_relationship</span><span class="p">[</span><span class="s1">&#39;slug&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">required_relationship</span><span class="p">[</span><span class="s1">&#39;required_side&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
4469
- <a id="__codelineno-0-375" name="__codelineno-0-375"></a>
4470
- <a id="__codelineno-0-376" name="__codelineno-0-376"></a> <span class="n">add_list</span> <span class="o">=</span> <span class="p">[]</span>
4471
- <a id="__codelineno-0-377" name="__codelineno-0-377"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4472
- <a id="__codelineno-0-378" name="__codelineno-0-378"></a> <span class="n">add_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span>
4473
- <a id="__codelineno-0-379" name="__codelineno-0-379"></a>
4474
- <a id="__codelineno-0-380" name="__codelineno-0-380"></a> <span class="n">remove_list</span> <span class="o">=</span> <span class="p">[]</span>
4475
- <a id="__codelineno-0-381" name="__codelineno-0-381"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4476
- <a id="__codelineno-0-382" name="__codelineno-0-382"></a> <span class="n">remove_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span>
4477
- <a id="__codelineno-0-383" name="__codelineno-0-383"></a>
4478
- <a id="__codelineno-0-384" name="__codelineno-0-384"></a> <span class="c1"># Determine difference of add/remove inputs</span>
4479
- <a id="__codelineno-0-385" name="__codelineno-0-385"></a> <span class="n">to_add</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">add_list</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">remove_list</span><span class="p">]</span>
4480
- <a id="__codelineno-0-386" name="__codelineno-0-386"></a>
4481
- <a id="__codelineno-0-387" name="__codelineno-0-387"></a> <span class="c1"># If we are adding at least one relationship association (and also not removing it), further validation is</span>
4482
- <a id="__codelineno-0-388" name="__codelineno-0-388"></a> <span class="c1"># not necessary because at least one object is required for every type of required relationship (one-to-one,</span>
4483
- <a id="__codelineno-0-389" name="__codelineno-0-389"></a> <span class="c1"># one-to-many and many-to-many)</span>
4484
- <a id="__codelineno-0-390" name="__codelineno-0-390"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">to_add</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
4485
- <a id="__codelineno-0-391" name="__codelineno-0-391"></a> <span class="k">continue</span>
5593
+ <a id="__codelineno-0-306" name="__codelineno-0-306"></a> <span class="p">):</span>
5594
+ <a id="__codelineno-0-307" name="__codelineno-0-307"></a> <span class="n">ra</span> <span class="o">=</span> <span class="kc">None</span>
5595
+ <a id="__codelineno-0-308" name="__codelineno-0-308"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">False</span>
5596
+ <a id="__codelineno-0-309" name="__codelineno-0-309"></a> <span class="k">else</span><span class="p">:</span>
5597
+ <a id="__codelineno-0-310" name="__codelineno-0-310"></a> <span class="n">ra</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
5598
+ <a id="__codelineno-0-311" name="__codelineno-0-311"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5599
+ <a id="__codelineno-0-312" name="__codelineno-0-312"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
5600
+ <a id="__codelineno-0-313" name="__codelineno-0-313"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5601
+ <a id="__codelineno-0-314" name="__codelineno-0-314"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
5602
+ <a id="__codelineno-0-315" name="__codelineno-0-315"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5603
+ <a id="__codelineno-0-316" name="__codelineno-0-316"></a> <span class="p">)</span>
5604
+ <a id="__codelineno-0-317" name="__codelineno-0-317"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">True</span>
5605
+ <a id="__codelineno-0-318" name="__codelineno-0-318"></a>
5606
+ <a id="__codelineno-0-319" name="__codelineno-0-319"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
5607
+ <a id="__codelineno-0-320" name="__codelineno-0-320"></a> <span class="n">ra</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
5608
+ <a id="__codelineno-0-321" name="__codelineno-0-321"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
5609
+ <a id="__codelineno-0-322" name="__codelineno-0-322"></a>
5610
+ <a id="__codelineno-0-323" name="__codelineno-0-323"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5611
+ <a id="__codelineno-0-324" name="__codelineno-0-324"></a> <span class="n">removed</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5612
+ <a id="__codelineno-0-325" name="__codelineno-0-325"></a>
5613
+ <a id="__codelineno-0-326" name="__codelineno-0-326"></a> <span class="n">source_count</span> <span class="o">=</span> <span class="mi">0</span>
5614
+ <a id="__codelineno-0-327" name="__codelineno-0-327"></a> <span class="n">destination_count</span> <span class="o">=</span> <span class="mi">0</span>
5615
+ <a id="__codelineno-0-328" name="__codelineno-0-328"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
5616
+ <a id="__codelineno-0-329" name="__codelineno-0-329"></a> <span class="n">source_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5617
+ <a id="__codelineno-0-330" name="__codelineno-0-330"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5618
+ <a id="__codelineno-0-331" name="__codelineno-0-331"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5619
+ <a id="__codelineno-0-332" name="__codelineno-0-332"></a> <span class="n">destination_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
5620
+ <a id="__codelineno-0-333" name="__codelineno-0-333"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
5621
+ <a id="__codelineno-0-334" name="__codelineno-0-334"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
5622
+ <a id="__codelineno-0-335" name="__codelineno-0-335"></a> <span class="n">destination_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5623
+ <a id="__codelineno-0-336" name="__codelineno-0-336"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5624
+ <a id="__codelineno-0-337" name="__codelineno-0-337"></a> <span class="n">source_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
5625
+ <a id="__codelineno-0-338" name="__codelineno-0-338"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5626
+ <a id="__codelineno-0-339" name="__codelineno-0-339"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
5627
+ <a id="__codelineno-0-340" name="__codelineno-0-340"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleted </span><span class="si">%s</span><span class="s2"> RelationshipAssociation(s)&quot;</span><span class="p">,</span> <span class="n">source_count</span> <span class="o">+</span> <span class="n">destination_count</span><span class="p">)</span>
5628
+ <a id="__codelineno-0-341" name="__codelineno-0-341"></a>
5629
+ <a id="__codelineno-0-342" name="__codelineno-0-342"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5630
+ <a id="__codelineno-0-343" name="__codelineno-0-343"></a> <span class="c1"># Get any initial required relationship objects errors (i.e. non-existent required objects)</span>
5631
+ <a id="__codelineno-0-344" name="__codelineno-0-344"></a> <span class="n">required_objects_errors</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">required_related_objects_errors</span><span class="p">(</span><span class="n">output_for</span><span class="o">=</span><span class="s2">&quot;ui&quot;</span><span class="p">)</span>
5632
+ <a id="__codelineno-0-345" name="__codelineno-0-345"></a> <span class="n">already_invalidated_keys</span> <span class="o">=</span> <span class="p">[]</span>
5633
+ <a id="__codelineno-0-346" name="__codelineno-0-346"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">errors</span> <span class="ow">in</span> <span class="n">required_objects_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5634
+ <a id="__codelineno-0-347" name="__codelineno-0-347"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span>
5635
+ <a id="__codelineno-0-348" name="__codelineno-0-348"></a> <span class="c1"># rindex() find the last occurrence of &quot;__&quot; which is</span>
5636
+ <a id="__codelineno-0-349" name="__codelineno-0-349"></a> <span class="c1"># guaranteed to be cr_{key}__source, cr_{key}__destination, or cr_{key}__peer</span>
5637
+ <a id="__codelineno-0-350" name="__codelineno-0-350"></a> <span class="c1"># regardless of how {key} is formatted</span>
5638
+ <a id="__codelineno-0-351" name="__codelineno-0-351"></a> <span class="n">relationship_key</span> <span class="o">=</span> <span class="n">field</span><span class="p">[:</span> <span class="n">field</span><span class="o">.</span><span class="n">rindex</span><span class="p">(</span><span class="s2">&quot;__&quot;</span><span class="p">)][</span><span class="mi">3</span><span class="p">:]</span>
5639
+ <a id="__codelineno-0-352" name="__codelineno-0-352"></a> <span class="n">already_invalidated_keys</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">relationship_key</span><span class="p">)</span>
5640
+ <a id="__codelineno-0-353" name="__codelineno-0-353"></a>
5641
+ <a id="__codelineno-0-354" name="__codelineno-0-354"></a> <span class="n">required_relationships</span> <span class="o">=</span> <span class="p">[]</span>
5642
+ <a id="__codelineno-0-355" name="__codelineno-0-355"></a> <span class="c1"># The following query excludes already invalidated relationships (this happened above</span>
5643
+ <a id="__codelineno-0-356" name="__codelineno-0-356"></a> <span class="c1"># by checking for the existence of required objects</span>
5644
+ <a id="__codelineno-0-357" name="__codelineno-0-357"></a> <span class="c1"># with the call to self.Meta().model.required_related_objects_errors(output_for=&quot;ui&quot;))</span>
5645
+ <a id="__codelineno-0-358" name="__codelineno-0-358"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_required_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><span class="o">.</span><span class="n">exclude</span><span class="p">(</span>
5646
+ <a id="__codelineno-0-359" name="__codelineno-0-359"></a> <span class="n">key__in</span><span class="o">=</span><span class="n">already_invalidated_keys</span>
5647
+ <a id="__codelineno-0-360" name="__codelineno-0-360"></a> <span class="p">):</span>
5648
+ <a id="__codelineno-0-361" name="__codelineno-0-361"></a> <span class="n">required_relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
5649
+ <a id="__codelineno-0-362" name="__codelineno-0-362"></a> <span class="p">{</span>
5650
+ <a id="__codelineno-0-363" name="__codelineno-0-363"></a> <span class="s2">&quot;key&quot;</span><span class="p">:</span> <span class="n">relationship</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
5651
+ <a id="__codelineno-0-364" name="__codelineno-0-364"></a> <span class="s2">&quot;required_side&quot;</span><span class="p">:</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="p">],</span>
5652
+ <a id="__codelineno-0-365" name="__codelineno-0-365"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="n">relationship</span><span class="p">,</span>
5653
+ <a id="__codelineno-0-366" name="__codelineno-0-366"></a> <span class="p">}</span>
5654
+ <a id="__codelineno-0-367" name="__codelineno-0-367"></a> <span class="p">)</span>
5655
+ <a id="__codelineno-0-368" name="__codelineno-0-368"></a>
5656
+ <a id="__codelineno-0-369" name="__codelineno-0-369"></a> <span class="c1"># Get difference of add/remove objects for each required relationship:</span>
5657
+ <a id="__codelineno-0-370" name="__codelineno-0-370"></a> <span class="n">required_relationships_to_check</span> <span class="o">=</span> <span class="p">[]</span>
5658
+ <a id="__codelineno-0-371" name="__codelineno-0-371"></a> <span class="k">for</span> <span class="n">required_relationship</span> <span class="ow">in</span> <span class="n">required_relationships</span><span class="p">:</span>
5659
+ <a id="__codelineno-0-372" name="__codelineno-0-372"></a> <span class="n">required_field</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">required_relationship</span><span class="p">[</span><span class="s1">&#39;key&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">required_relationship</span><span class="p">[</span><span class="s1">&#39;required_side&#39;</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span>
5660
+ <a id="__codelineno-0-373" name="__codelineno-0-373"></a>
5661
+ <a id="__codelineno-0-374" name="__codelineno-0-374"></a> <span class="n">add_list</span> <span class="o">=</span> <span class="p">[]</span>
5662
+ <a id="__codelineno-0-375" name="__codelineno-0-375"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5663
+ <a id="__codelineno-0-376" name="__codelineno-0-376"></a> <span class="n">add_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span>
5664
+ <a id="__codelineno-0-377" name="__codelineno-0-377"></a>
5665
+ <a id="__codelineno-0-378" name="__codelineno-0-378"></a> <span class="n">remove_list</span> <span class="o">=</span> <span class="p">[]</span>
5666
+ <a id="__codelineno-0-379" name="__codelineno-0-379"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5667
+ <a id="__codelineno-0-380" name="__codelineno-0-380"></a> <span class="n">remove_list</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">required_field</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">]</span>
5668
+ <a id="__codelineno-0-381" name="__codelineno-0-381"></a>
5669
+ <a id="__codelineno-0-382" name="__codelineno-0-382"></a> <span class="c1"># Determine difference of add/remove inputs</span>
5670
+ <a id="__codelineno-0-383" name="__codelineno-0-383"></a> <span class="n">to_add</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">add_list</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">remove_list</span><span class="p">]</span>
5671
+ <a id="__codelineno-0-384" name="__codelineno-0-384"></a>
5672
+ <a id="__codelineno-0-385" name="__codelineno-0-385"></a> <span class="c1"># If we are adding at least one relationship association (and also not removing it), further validation is</span>
5673
+ <a id="__codelineno-0-386" name="__codelineno-0-386"></a> <span class="c1"># not necessary because at least one object is required for every type of required relationship (one-to-one,</span>
5674
+ <a id="__codelineno-0-387" name="__codelineno-0-387"></a> <span class="c1"># one-to-many and many-to-many)</span>
5675
+ <a id="__codelineno-0-388" name="__codelineno-0-388"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">to_add</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">0</span><span class="p">:</span>
5676
+ <a id="__codelineno-0-389" name="__codelineno-0-389"></a> <span class="k">continue</span>
5677
+ <a id="__codelineno-0-390" name="__codelineno-0-390"></a>
5678
+ <a id="__codelineno-0-391" name="__codelineno-0-391"></a> <span class="n">to_remove</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">remove_list</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">add_list</span><span class="p">]</span>
4486
5679
  <a id="__codelineno-0-392" name="__codelineno-0-392"></a>
4487
- <a id="__codelineno-0-393" name="__codelineno-0-393"></a> <span class="n">to_remove</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">remove_list</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">add_list</span><span class="p">]</span>
4488
- <a id="__codelineno-0-394" name="__codelineno-0-394"></a>
4489
- <a id="__codelineno-0-395" name="__codelineno-0-395"></a> <span class="c1"># Add to list of required relationships to enforce on each object being bulk-edited</span>
4490
- <a id="__codelineno-0-396" name="__codelineno-0-396"></a> <span class="n">required_relationships_to_check</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
4491
- <a id="__codelineno-0-397" name="__codelineno-0-397"></a> <span class="p">{</span>
4492
- <a id="__codelineno-0-398" name="__codelineno-0-398"></a> <span class="s2">&quot;field&quot;</span><span class="p">:</span> <span class="n">required_field</span><span class="p">,</span>
4493
- <a id="__codelineno-0-399" name="__codelineno-0-399"></a> <span class="s2">&quot;to_add&quot;</span><span class="p">:</span> <span class="n">to_add</span><span class="p">,</span>
4494
- <a id="__codelineno-0-400" name="__codelineno-0-400"></a> <span class="s2">&quot;to_remove&quot;</span><span class="p">:</span> <span class="n">to_remove</span><span class="p">,</span>
4495
- <a id="__codelineno-0-401" name="__codelineno-0-401"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="n">required_relationship</span><span class="p">[</span><span class="s2">&quot;relationship&quot;</span><span class="p">],</span>
4496
- <a id="__codelineno-0-402" name="__codelineno-0-402"></a> <span class="p">}</span>
4497
- <a id="__codelineno-0-403" name="__codelineno-0-403"></a> <span class="p">)</span>
5680
+ <a id="__codelineno-0-393" name="__codelineno-0-393"></a> <span class="c1"># Add to list of required relationships to enforce on each object being bulk-edited</span>
5681
+ <a id="__codelineno-0-394" name="__codelineno-0-394"></a> <span class="n">required_relationships_to_check</span><span class="o">.</span><span class="n">append</span><span class="p">(</span>
5682
+ <a id="__codelineno-0-395" name="__codelineno-0-395"></a> <span class="p">{</span>
5683
+ <a id="__codelineno-0-396" name="__codelineno-0-396"></a> <span class="s2">&quot;field&quot;</span><span class="p">:</span> <span class="n">required_field</span><span class="p">,</span>
5684
+ <a id="__codelineno-0-397" name="__codelineno-0-397"></a> <span class="s2">&quot;to_add&quot;</span><span class="p">:</span> <span class="n">to_add</span><span class="p">,</span>
5685
+ <a id="__codelineno-0-398" name="__codelineno-0-398"></a> <span class="s2">&quot;to_remove&quot;</span><span class="p">:</span> <span class="n">to_remove</span><span class="p">,</span>
5686
+ <a id="__codelineno-0-399" name="__codelineno-0-399"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="n">required_relationship</span><span class="p">[</span><span class="s2">&quot;relationship&quot;</span><span class="p">],</span>
5687
+ <a id="__codelineno-0-400" name="__codelineno-0-400"></a> <span class="p">}</span>
5688
+ <a id="__codelineno-0-401" name="__codelineno-0-401"></a> <span class="p">)</span>
5689
+ <a id="__codelineno-0-402" name="__codelineno-0-402"></a>
5690
+ <a id="__codelineno-0-403" name="__codelineno-0-403"></a> <span class="n">relationship_data_errors</span> <span class="o">=</span> <span class="p">{}</span>
4498
5691
  <a id="__codelineno-0-404" name="__codelineno-0-404"></a>
4499
- <a id="__codelineno-0-405" name="__codelineno-0-405"></a> <span class="n">relationship_data_errors</span> <span class="o">=</span> <span class="p">{}</span>
4500
- <a id="__codelineno-0-406" name="__codelineno-0-406"></a>
4501
- <a id="__codelineno-0-407" name="__codelineno-0-407"></a> <span class="k">for</span> <span class="n">relationship_to_check</span> <span class="ow">in</span> <span class="n">required_relationships_to_check</span><span class="p">:</span>
4502
- <a id="__codelineno-0-408" name="__codelineno-0-408"></a> <span class="n">relationship</span> <span class="o">=</span> <span class="n">relationship_to_check</span><span class="p">[</span><span class="s2">&quot;relationship&quot;</span><span class="p">]</span>
4503
- <a id="__codelineno-0-409" name="__codelineno-0-409"></a> <span class="k">for</span> <span class="n">editing</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s2">&quot;pk&quot;</span><span class="p">]:</span>
4504
- <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="n">required_target_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="p">]</span>
4505
- <a id="__codelineno-0-411" name="__codelineno-0-411"></a> <span class="n">required_target_type</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">relationship</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">required_target_side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">)</span>
4506
- <a id="__codelineno-0-412" name="__codelineno-0-412"></a> <span class="n">required_type_verbose_name</span> <span class="o">=</span> <span class="n">required_target_type</span><span class="o">.</span><span class="n">model_class</span><span class="p">()</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">verbose_name</span>
4507
- <a id="__codelineno-0-413" name="__codelineno-0-413"></a> <span class="n">filter_kwargs</span> <span class="o">=</span> <span class="p">{</span>
4508
- <a id="__codelineno-0-414" name="__codelineno-0-414"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="n">relationship</span><span class="p">,</span>
4509
- <a id="__codelineno-0-415" name="__codelineno-0-415"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">editing</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4510
- <a id="__codelineno-0-416" name="__codelineno-0-416"></a> <span class="p">}</span>
4511
- <a id="__codelineno-0-417" name="__codelineno-0-417"></a> <span class="n">existing_objects</span> <span class="o">=</span> <span class="p">[</span>
4512
- <a id="__codelineno-0-418" name="__codelineno-0-418"></a> <span class="nb">getattr</span><span class="p">(</span><span class="n">association</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)()</span>
4513
- <a id="__codelineno-0-419" name="__codelineno-0-419"></a> <span class="k">for</span> <span class="n">association</span> <span class="ow">in</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">**</span><span class="n">filter_kwargs</span><span class="p">)</span>
4514
- <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="p">]</span>
4515
- <a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="n">requires_message</span> <span class="o">=</span> <span class="p">(</span>
4516
- <a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">editing</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">verbose_name_plural</span><span class="si">}</span><span class="s2"> require a </span><span class="si">{</span><span class="n">required_type_verbose_name</span><span class="si">}</span><span class="s2"> &quot;</span>
4517
- <a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="sa">f</span><span class="s1">&#39;for the required relationship &quot;</span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">relationship</span><span class="p">)</span><span class="si">}</span><span class="s1">&quot;&#39;</span>
4518
- <a id="__codelineno-0-424" name="__codelineno-0-424"></a> <span class="p">)</span>
4519
- <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">existing_objects</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">relationship_to_check</span><span class="p">[</span><span class="s2">&quot;to_add&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
4520
- <a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="n">relationship_data_errors</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">requires_message</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">editing</span><span class="p">))</span>
4521
- <a id="__codelineno-0-427" name="__codelineno-0-427"></a> <span class="k">else</span><span class="p">:</span>
4522
- <a id="__codelineno-0-428" name="__codelineno-0-428"></a> <span class="n">removed</span> <span class="o">=</span> <span class="n">relationship_to_check</span><span class="p">[</span><span class="s2">&quot;to_remove&quot;</span><span class="p">]</span>
4523
- <a id="__codelineno-0-429" name="__codelineno-0-429"></a> <span class="n">difference</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">existing_objects</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">]</span>
4524
- <a id="__codelineno-0-430" name="__codelineno-0-430"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">difference</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
4525
- <a id="__codelineno-0-431" name="__codelineno-0-431"></a> <span class="n">relationship_data_errors</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">requires_message</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">editing</span><span class="p">))</span>
4526
- <a id="__codelineno-0-432" name="__codelineno-0-432"></a>
4527
- <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="k">for</span> <span class="n">relationship_message</span><span class="p">,</span> <span class="n">object_list</span> <span class="ow">in</span> <span class="n">relationship_data_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4528
- <a id="__codelineno-0-434" name="__codelineno-0-434"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">object_list</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">5</span><span class="p">:</span>
4529
- <a id="__codelineno-0-435" name="__codelineno-0-435"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">object_list</span><span class="p">)</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">relationship_message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4530
- <a id="__codelineno-0-436" name="__codelineno-0-436"></a> <span class="k">else</span><span class="p">:</span>
4531
- <a id="__codelineno-0-437" name="__codelineno-0-437"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;These </span><span class="si">{</span><span class="n">relationship_message</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">object_list</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4532
- <a id="__codelineno-0-438" name="__codelineno-0-438"></a>
4533
- <a id="__codelineno-0-439" name="__codelineno-0-439"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
5692
+ <a id="__codelineno-0-405" name="__codelineno-0-405"></a> <span class="k">for</span> <span class="n">relationship_to_check</span> <span class="ow">in</span> <span class="n">required_relationships_to_check</span><span class="p">:</span>
5693
+ <a id="__codelineno-0-406" name="__codelineno-0-406"></a> <span class="n">relationship</span> <span class="o">=</span> <span class="n">relationship_to_check</span><span class="p">[</span><span class="s2">&quot;relationship&quot;</span><span class="p">]</span>
5694
+ <a id="__codelineno-0-407" name="__codelineno-0-407"></a> <span class="k">for</span> <span class="n">editing</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="s2">&quot;pk&quot;</span><span class="p">]:</span>
5695
+ <a id="__codelineno-0-408" name="__codelineno-0-408"></a> <span class="n">required_target_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="p">]</span>
5696
+ <a id="__codelineno-0-409" name="__codelineno-0-409"></a> <span class="n">required_target_type</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">relationship</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">required_target_side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">)</span>
5697
+ <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="n">required_type_verbose_name</span> <span class="o">=</span> <span class="n">required_target_type</span><span class="o">.</span><span class="n">model_class</span><span class="p">()</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">verbose_name</span>
5698
+ <a id="__codelineno-0-411" name="__codelineno-0-411"></a> <span class="n">filter_kwargs</span> <span class="o">=</span> <span class="p">{</span>
5699
+ <a id="__codelineno-0-412" name="__codelineno-0-412"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="n">relationship</span><span class="p">,</span>
5700
+ <a id="__codelineno-0-413" name="__codelineno-0-413"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">editing</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5701
+ <a id="__codelineno-0-414" name="__codelineno-0-414"></a> <span class="p">}</span>
5702
+ <a id="__codelineno-0-415" name="__codelineno-0-415"></a> <span class="n">existing_objects</span> <span class="o">=</span> <span class="p">[</span>
5703
+ <a id="__codelineno-0-416" name="__codelineno-0-416"></a> <span class="nb">getattr</span><span class="p">(</span><span class="n">association</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;get_</span><span class="si">{</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span><span class="p">]</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)()</span>
5704
+ <a id="__codelineno-0-417" name="__codelineno-0-417"></a> <span class="k">for</span> <span class="n">association</span> <span class="ow">in</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">**</span><span class="n">filter_kwargs</span><span class="p">)</span>
5705
+ <a id="__codelineno-0-418" name="__codelineno-0-418"></a> <span class="p">]</span>
5706
+ <a id="__codelineno-0-419" name="__codelineno-0-419"></a> <span class="n">requires_message</span> <span class="o">=</span> <span class="p">(</span>
5707
+ <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">editing</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">verbose_name_plural</span><span class="si">}</span><span class="s2"> require a </span><span class="si">{</span><span class="n">required_type_verbose_name</span><span class="si">}</span><span class="s2"> &quot;</span>
5708
+ <a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="sa">f</span><span class="s1">&#39;for the required relationship &quot;</span><span class="si">{</span><span class="nb">str</span><span class="p">(</span><span class="n">relationship</span><span class="p">)</span><span class="si">}</span><span class="s1">&quot;&#39;</span>
5709
+ <a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="p">)</span>
5710
+ <a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">existing_objects</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span> <span class="ow">and</span> <span class="nb">len</span><span class="p">(</span><span class="n">relationship_to_check</span><span class="p">[</span><span class="s2">&quot;to_add&quot;</span><span class="p">])</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
5711
+ <a id="__codelineno-0-424" name="__codelineno-0-424"></a> <span class="n">relationship_data_errors</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">requires_message</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">editing</span><span class="p">))</span>
5712
+ <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="k">else</span><span class="p">:</span>
5713
+ <a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="n">removed</span> <span class="o">=</span> <span class="n">relationship_to_check</span><span class="p">[</span><span class="s2">&quot;to_remove&quot;</span><span class="p">]</span>
5714
+ <a id="__codelineno-0-427" name="__codelineno-0-427"></a> <span class="n">difference</span> <span class="o">=</span> <span class="p">[</span><span class="n">obj</span> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">existing_objects</span> <span class="k">if</span> <span class="n">obj</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">]</span>
5715
+ <a id="__codelineno-0-428" name="__codelineno-0-428"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">difference</span><span class="p">)</span> <span class="o">==</span> <span class="mi">0</span><span class="p">:</span>
5716
+ <a id="__codelineno-0-429" name="__codelineno-0-429"></a> <span class="n">relationship_data_errors</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">requires_message</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">editing</span><span class="p">))</span>
5717
+ <a id="__codelineno-0-430" name="__codelineno-0-430"></a>
5718
+ <a id="__codelineno-0-431" name="__codelineno-0-431"></a> <span class="k">for</span> <span class="n">relationship_message</span><span class="p">,</span> <span class="n">object_list</span> <span class="ow">in</span> <span class="n">relationship_data_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5719
+ <a id="__codelineno-0-432" name="__codelineno-0-432"></a> <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">object_list</span><span class="p">)</span> <span class="o">&gt;</span> <span class="mi">5</span><span class="p">:</span>
5720
+ <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="nb">len</span><span class="p">(</span><span class="n">object_list</span><span class="p">)</span><span class="si">}</span><span class="s2"> </span><span class="si">{</span><span class="n">relationship_message</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5721
+ <a id="__codelineno-0-434" name="__codelineno-0-434"></a> <span class="k">else</span><span class="p">:</span>
5722
+ <a id="__codelineno-0-435" name="__codelineno-0-435"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="kc">None</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;These </span><span class="si">{</span><span class="n">relationship_message</span><span class="si">}</span><span class="s2">: </span><span class="si">{</span><span class="s1">&#39;, &#39;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">object_list</span><span class="p">)</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5723
+ <a id="__codelineno-0-436" name="__codelineno-0-436"></a>
5724
+ <a id="__codelineno-0-437" name="__codelineno-0-437"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
4534
5725
  </code></pre></div></td></tr></table></div>
4535
5726
  </details>
4536
5727
 
@@ -4562,7 +5753,12 @@ NoteModelFormMixin are needed.</p>
4562
5753
 
4563
5754
  <details class="quote">
4564
5755
  <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
4565
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-250">250</a></span>
5756
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-245">245</a></span>
5757
+ <span class="normal"><a href="#__codelineno-0-246">246</a></span>
5758
+ <span class="normal"><a href="#__codelineno-0-247">247</a></span>
5759
+ <span class="normal"><a href="#__codelineno-0-248">248</a></span>
5760
+ <span class="normal"><a href="#__codelineno-0-249">249</a></span>
5761
+ <span class="normal"><a href="#__codelineno-0-250">250</a></span>
4566
5762
  <span class="normal"><a href="#__codelineno-0-251">251</a></span>
4567
5763
  <span class="normal"><a href="#__codelineno-0-252">252</a></span>
4568
5764
  <span class="normal"><a href="#__codelineno-0-253">253</a></span>
@@ -4652,107 +5848,102 @@ NoteModelFormMixin are needed.</p>
4652
5848
  <span class="normal"><a href="#__codelineno-0-337">337</a></span>
4653
5849
  <span class="normal"><a href="#__codelineno-0-338">338</a></span>
4654
5850
  <span class="normal"><a href="#__codelineno-0-339">339</a></span>
4655
- <span class="normal"><a href="#__codelineno-0-340">340</a></span>
4656
- <span class="normal"><a href="#__codelineno-0-341">341</a></span>
4657
- <span class="normal"><a href="#__codelineno-0-342">342</a></span>
4658
- <span class="normal"><a href="#__codelineno-0-343">343</a></span>
4659
- <span class="normal"><a href="#__codelineno-0-344">344</a></span>
4660
- <span class="normal"><a href="#__codelineno-0-345">345</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-250" name="__codelineno-0-250"></a><span class="k">def</span> <span class="nf">save_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">nullified_fields</span><span class="p">):</span>
4661
- <a id="__codelineno-0-251" name="__codelineno-0-251"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Helper method to be called from BulkEditView.post().&quot;&quot;&quot;</span>
4662
- <a id="__codelineno-0-252" name="__codelineno-0-252"></a> <span class="c1"># The below may seem inefficient as it re-loads the Relationship objects afresh for each instance;</span>
4663
- <a id="__codelineno-0-253" name="__codelineno-0-253"></a> <span class="c1"># however this is necessary as it applies the source/destination filters (if any) to determine</span>
4664
- <a id="__codelineno-0-254" name="__codelineno-0-254"></a> <span class="c1"># whether each relationship actually applies to the given instance.</span>
4665
- <a id="__codelineno-0-255" name="__codelineno-0-255"></a> <span class="n">instance_relationships</span> <span class="o">=</span> <span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">(</span><span class="n">include_hidden</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
4666
- <a id="__codelineno-0-256" name="__codelineno-0-256"></a>
4667
- <a id="__codelineno-0-257" name="__codelineno-0-257"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships_data</span> <span class="ow">in</span> <span class="n">instance_relationships</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4668
- <a id="__codelineno-0-258" name="__codelineno-0-258"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
4669
- <a id="__codelineno-0-259" name="__codelineno-0-259"></a> <span class="k">for</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">relationshipassociation_queryset</span> <span class="ow">in</span> <span class="n">relationships_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4670
- <a id="__codelineno-0-260" name="__codelineno-0-260"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">slug</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
4671
- <a id="__codelineno-0-261" name="__codelineno-0-261"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
4672
- <a id="__codelineno-0-262" name="__codelineno-0-262"></a> <span class="s2">&quot;Processing relationship </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> (field </span><span class="si">%s</span><span class="s2">) for instance </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
4673
- <a id="__codelineno-0-263" name="__codelineno-0-263"></a> <span class="n">relationship</span><span class="p">,</span>
4674
- <a id="__codelineno-0-264" name="__codelineno-0-264"></a> <span class="n">side</span><span class="p">,</span>
4675
- <a id="__codelineno-0-265" name="__codelineno-0-265"></a> <span class="n">field_name</span><span class="p">,</span>
4676
- <a id="__codelineno-0-266" name="__codelineno-0-266"></a> <span class="n">instance</span><span class="p">,</span>
4677
- <a id="__codelineno-0-267" name="__codelineno-0-267"></a> <span class="p">)</span>
4678
- <a id="__codelineno-0-268" name="__codelineno-0-268"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span> <span class="ow">and</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">nullified_fields</span><span class="p">:</span>
4679
- <a id="__codelineno-0-269" name="__codelineno-0-269"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleting existing relationship associations for </span><span class="si">%s</span><span class="s2"> on </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">instance</span><span class="p">)</span>
4680
- <a id="__codelineno-0-270" name="__codelineno-0-270"></a> <span class="n">relationshipassociation_queryset</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
4681
- <a id="__codelineno-0-271" name="__codelineno-0-271"></a> <span class="k">elif</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4682
- <a id="__codelineno-0-272" name="__codelineno-0-272"></a> <span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4683
- <a id="__codelineno-0-273" name="__codelineno-0-273"></a> <span class="k">if</span> <span class="n">value</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
4684
- <a id="__codelineno-0-274" name="__codelineno-0-274"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
4685
- <a id="__codelineno-0-275" name="__codelineno-0-275"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4686
- <a id="__codelineno-0-276" name="__codelineno-0-276"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
4687
- <a id="__codelineno-0-277" name="__codelineno-0-277"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
4688
- <a id="__codelineno-0-278" name="__codelineno-0-278"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">value</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
4689
- <a id="__codelineno-0-279" name="__codelineno-0-279"></a> <span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
4690
- <a id="__codelineno-0-280" name="__codelineno-0-280"></a> <span class="p">)</span>
4691
- <a id="__codelineno-0-281" name="__codelineno-0-281"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
4692
- <a id="__codelineno-0-282" name="__codelineno-0-282"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
4693
- <a id="__codelineno-0-283" name="__codelineno-0-283"></a> <span class="k">else</span><span class="p">:</span>
4694
- <a id="__codelineno-0-284" name="__codelineno-0-284"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Updated </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
4695
- <a id="__codelineno-0-285" name="__codelineno-0-285"></a> <span class="k">else</span><span class="p">:</span>
4696
- <a id="__codelineno-0-286" name="__codelineno-0-286"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4697
- <a id="__codelineno-0-287" name="__codelineno-0-287"></a> <span class="n">added</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4698
- <a id="__codelineno-0-288" name="__codelineno-0-288"></a> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">added</span><span class="p">:</span>
4699
- <a id="__codelineno-0-289" name="__codelineno-0-289"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
4700
- <a id="__codelineno-0-290" name="__codelineno-0-290"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">(</span>
4701
- <a id="__codelineno-0-291" name="__codelineno-0-291"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4702
- <a id="__codelineno-0-292" name="__codelineno-0-292"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
4703
- <a id="__codelineno-0-293" name="__codelineno-0-293"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
4704
- <a id="__codelineno-0-294" name="__codelineno-0-294"></a> <span class="o">**</span><span class="p">{</span>
4705
- <a id="__codelineno-0-295" name="__codelineno-0-295"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4706
- <a id="__codelineno-0-296" name="__codelineno-0-296"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4707
- <a id="__codelineno-0-297" name="__codelineno-0-297"></a> <span class="p">},</span>
4708
- <a id="__codelineno-0-298" name="__codelineno-0-298"></a> <span class="p">)</span>
4709
- <a id="__codelineno-0-299" name="__codelineno-0-299"></a> <span class="k">else</span><span class="p">:</span>
4710
- <a id="__codelineno-0-300" name="__codelineno-0-300"></a> <span class="k">if</span> <span class="p">(</span>
4711
- <a id="__codelineno-0-301" name="__codelineno-0-301"></a> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5851
+ <span class="normal"><a href="#__codelineno-0-340">340</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-245" name="__codelineno-0-245"></a><span class="k">def</span> <span class="nf">save_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">instance</span><span class="p">,</span> <span class="n">nullified_fields</span><span class="p">):</span>
5852
+ <a id="__codelineno-0-246" name="__codelineno-0-246"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Helper method to be called from BulkEditView.post().&quot;&quot;&quot;</span>
5853
+ <a id="__codelineno-0-247" name="__codelineno-0-247"></a> <span class="c1"># The below may seem inefficient as it re-loads the Relationship objects afresh for each instance;</span>
5854
+ <a id="__codelineno-0-248" name="__codelineno-0-248"></a> <span class="c1"># however this is necessary as it applies the source/destination filters (if any) to determine</span>
5855
+ <a id="__codelineno-0-249" name="__codelineno-0-249"></a> <span class="c1"># whether each relationship actually applies to the given instance.</span>
5856
+ <a id="__codelineno-0-250" name="__codelineno-0-250"></a> <span class="n">instance_relationships</span> <span class="o">=</span> <span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">(</span><span class="n">include_hidden</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span>
5857
+ <a id="__codelineno-0-251" name="__codelineno-0-251"></a>
5858
+ <a id="__codelineno-0-252" name="__codelineno-0-252"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships_data</span> <span class="ow">in</span> <span class="n">instance_relationships</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5859
+ <a id="__codelineno-0-253" name="__codelineno-0-253"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
5860
+ <a id="__codelineno-0-254" name="__codelineno-0-254"></a> <span class="k">for</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">relationshipassociation_queryset</span> <span class="ow">in</span> <span class="n">relationships_data</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5861
+ <a id="__codelineno-0-255" name="__codelineno-0-255"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
5862
+ <a id="__codelineno-0-256" name="__codelineno-0-256"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span>
5863
+ <a id="__codelineno-0-257" name="__codelineno-0-257"></a> <span class="s2">&quot;Processing relationship </span><span class="si">%s</span><span class="s2"> </span><span class="si">%s</span><span class="s2"> (field </span><span class="si">%s</span><span class="s2">) for instance </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span>
5864
+ <a id="__codelineno-0-258" name="__codelineno-0-258"></a> <span class="n">relationship</span><span class="p">,</span>
5865
+ <a id="__codelineno-0-259" name="__codelineno-0-259"></a> <span class="n">side</span><span class="p">,</span>
5866
+ <a id="__codelineno-0-260" name="__codelineno-0-260"></a> <span class="n">field_name</span><span class="p">,</span>
5867
+ <a id="__codelineno-0-261" name="__codelineno-0-261"></a> <span class="n">instance</span><span class="p">,</span>
5868
+ <a id="__codelineno-0-262" name="__codelineno-0-262"></a> <span class="p">)</span>
5869
+ <a id="__codelineno-0-263" name="__codelineno-0-263"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">nullable_fields</span> <span class="ow">and</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="n">nullified_fields</span><span class="p">:</span>
5870
+ <a id="__codelineno-0-264" name="__codelineno-0-264"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleting existing relationship associations for </span><span class="si">%s</span><span class="s2"> on </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">instance</span><span class="p">)</span>
5871
+ <a id="__codelineno-0-265" name="__codelineno-0-265"></a> <span class="n">relationshipassociation_queryset</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
5872
+ <a id="__codelineno-0-266" name="__codelineno-0-266"></a> <span class="k">elif</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5873
+ <a id="__codelineno-0-267" name="__codelineno-0-267"></a> <span class="n">value</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5874
+ <a id="__codelineno-0-268" name="__codelineno-0-268"></a> <span class="k">if</span> <span class="n">value</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
5875
+ <a id="__codelineno-0-269" name="__codelineno-0-269"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">update_or_create</span><span class="p">(</span>
5876
+ <a id="__codelineno-0-270" name="__codelineno-0-270"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5877
+ <a id="__codelineno-0-271" name="__codelineno-0-271"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
5878
+ <a id="__codelineno-0-272" name="__codelineno-0-272"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
5879
+ <a id="__codelineno-0-273" name="__codelineno-0-273"></a> <span class="n">defaults</span><span class="o">=</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">value</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
5880
+ <a id="__codelineno-0-274" name="__codelineno-0-274"></a> <span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">},</span>
5881
+ <a id="__codelineno-0-275" name="__codelineno-0-275"></a> <span class="p">)</span>
5882
+ <a id="__codelineno-0-276" name="__codelineno-0-276"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
5883
+ <a id="__codelineno-0-277" name="__codelineno-0-277"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
5884
+ <a id="__codelineno-0-278" name="__codelineno-0-278"></a> <span class="k">else</span><span class="p">:</span>
5885
+ <a id="__codelineno-0-279" name="__codelineno-0-279"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Updated </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
5886
+ <a id="__codelineno-0-280" name="__codelineno-0-280"></a> <span class="k">else</span><span class="p">:</span>
5887
+ <a id="__codelineno-0-281" name="__codelineno-0-281"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5888
+ <a id="__codelineno-0-282" name="__codelineno-0-282"></a> <span class="n">added</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;add_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5889
+ <a id="__codelineno-0-283" name="__codelineno-0-283"></a> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">added</span><span class="p">:</span>
5890
+ <a id="__codelineno-0-284" name="__codelineno-0-284"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
5891
+ <a id="__codelineno-0-285" name="__codelineno-0-285"></a> <span class="n">ra</span><span class="p">,</span> <span class="n">created</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_or_create</span><span class="p">(</span>
5892
+ <a id="__codelineno-0-286" name="__codelineno-0-286"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5893
+ <a id="__codelineno-0-287" name="__codelineno-0-287"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
5894
+ <a id="__codelineno-0-288" name="__codelineno-0-288"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
5895
+ <a id="__codelineno-0-289" name="__codelineno-0-289"></a> <span class="o">**</span><span class="p">{</span>
5896
+ <a id="__codelineno-0-290" name="__codelineno-0-290"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5897
+ <a id="__codelineno-0-291" name="__codelineno-0-291"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5898
+ <a id="__codelineno-0-292" name="__codelineno-0-292"></a> <span class="p">},</span>
5899
+ <a id="__codelineno-0-293" name="__codelineno-0-293"></a> <span class="p">)</span>
5900
+ <a id="__codelineno-0-294" name="__codelineno-0-294"></a> <span class="k">else</span><span class="p">:</span>
5901
+ <a id="__codelineno-0-295" name="__codelineno-0-295"></a> <span class="k">if</span> <span class="p">(</span>
5902
+ <a id="__codelineno-0-296" name="__codelineno-0-296"></a> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5903
+ <a id="__codelineno-0-297" name="__codelineno-0-297"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5904
+ <a id="__codelineno-0-298" name="__codelineno-0-298"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5905
+ <a id="__codelineno-0-299" name="__codelineno-0-299"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5906
+ <a id="__codelineno-0-300" name="__codelineno-0-300"></a> <span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
5907
+ <a id="__codelineno-0-301" name="__codelineno-0-301"></a> <span class="ow">or</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4712
5908
  <a id="__codelineno-0-302" name="__codelineno-0-302"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4713
- <a id="__codelineno-0-303" name="__codelineno-0-303"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4714
- <a id="__codelineno-0-304" name="__codelineno-0-304"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5909
+ <a id="__codelineno-0-303" name="__codelineno-0-303"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5910
+ <a id="__codelineno-0-304" name="__codelineno-0-304"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4715
5911
  <a id="__codelineno-0-305" name="__codelineno-0-305"></a> <span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
4716
- <a id="__codelineno-0-306" name="__codelineno-0-306"></a> <span class="ow">or</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4717
- <a id="__codelineno-0-307" name="__codelineno-0-307"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4718
- <a id="__codelineno-0-308" name="__codelineno-0-308"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4719
- <a id="__codelineno-0-309" name="__codelineno-0-309"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4720
- <a id="__codelineno-0-310" name="__codelineno-0-310"></a> <span class="p">)</span><span class="o">.</span><span class="n">exists</span><span class="p">()</span>
4721
- <a id="__codelineno-0-311" name="__codelineno-0-311"></a> <span class="p">):</span>
4722
- <a id="__codelineno-0-312" name="__codelineno-0-312"></a> <span class="n">ra</span> <span class="o">=</span> <span class="kc">None</span>
4723
- <a id="__codelineno-0-313" name="__codelineno-0-313"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">False</span>
4724
- <a id="__codelineno-0-314" name="__codelineno-0-314"></a> <span class="k">else</span><span class="p">:</span>
4725
- <a id="__codelineno-0-315" name="__codelineno-0-315"></a> <span class="n">ra</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
4726
- <a id="__codelineno-0-316" name="__codelineno-0-316"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4727
- <a id="__codelineno-0-317" name="__codelineno-0-317"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
4728
- <a id="__codelineno-0-318" name="__codelineno-0-318"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4729
- <a id="__codelineno-0-319" name="__codelineno-0-319"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
4730
- <a id="__codelineno-0-320" name="__codelineno-0-320"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4731
- <a id="__codelineno-0-321" name="__codelineno-0-321"></a> <span class="p">)</span>
4732
- <a id="__codelineno-0-322" name="__codelineno-0-322"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">True</span>
4733
- <a id="__codelineno-0-323" name="__codelineno-0-323"></a>
4734
- <a id="__codelineno-0-324" name="__codelineno-0-324"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
4735
- <a id="__codelineno-0-325" name="__codelineno-0-325"></a> <span class="n">ra</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
4736
- <a id="__codelineno-0-326" name="__codelineno-0-326"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
4737
- <a id="__codelineno-0-327" name="__codelineno-0-327"></a>
4738
- <a id="__codelineno-0-328" name="__codelineno-0-328"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
4739
- <a id="__codelineno-0-329" name="__codelineno-0-329"></a> <span class="n">removed</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4740
- <a id="__codelineno-0-330" name="__codelineno-0-330"></a>
4741
- <a id="__codelineno-0-331" name="__codelineno-0-331"></a> <span class="n">source_count</span> <span class="o">=</span> <span class="mi">0</span>
4742
- <a id="__codelineno-0-332" name="__codelineno-0-332"></a> <span class="n">destination_count</span> <span class="o">=</span> <span class="mi">0</span>
4743
- <a id="__codelineno-0-333" name="__codelineno-0-333"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
4744
- <a id="__codelineno-0-334" name="__codelineno-0-334"></a> <span class="n">source_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4745
- <a id="__codelineno-0-335" name="__codelineno-0-335"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4746
- <a id="__codelineno-0-336" name="__codelineno-0-336"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4747
- <a id="__codelineno-0-337" name="__codelineno-0-337"></a> <span class="n">destination_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
4748
- <a id="__codelineno-0-338" name="__codelineno-0-338"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
4749
- <a id="__codelineno-0-339" name="__codelineno-0-339"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
4750
- <a id="__codelineno-0-340" name="__codelineno-0-340"></a> <span class="n">destination_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
4751
- <a id="__codelineno-0-341" name="__codelineno-0-341"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4752
- <a id="__codelineno-0-342" name="__codelineno-0-342"></a> <span class="n">source_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
4753
- <a id="__codelineno-0-343" name="__codelineno-0-343"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
4754
- <a id="__codelineno-0-344" name="__codelineno-0-344"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
4755
- <a id="__codelineno-0-345" name="__codelineno-0-345"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleted </span><span class="si">%s</span><span class="s2"> RelationshipAssociation(s)&quot;</span><span class="p">,</span> <span class="n">source_count</span> <span class="o">+</span> <span class="n">destination_count</span><span class="p">)</span>
5912
+ <a id="__codelineno-0-306" name="__codelineno-0-306"></a> <span class="p">):</span>
5913
+ <a id="__codelineno-0-307" name="__codelineno-0-307"></a> <span class="n">ra</span> <span class="o">=</span> <span class="kc">None</span>
5914
+ <a id="__codelineno-0-308" name="__codelineno-0-308"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">False</span>
5915
+ <a id="__codelineno-0-309" name="__codelineno-0-309"></a> <span class="k">else</span><span class="p">:</span>
5916
+ <a id="__codelineno-0-310" name="__codelineno-0-310"></a> <span class="n">ra</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">create</span><span class="p">(</span>
5917
+ <a id="__codelineno-0-311" name="__codelineno-0-311"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5918
+ <a id="__codelineno-0-312" name="__codelineno-0-312"></a> <span class="n">source_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="p">,</span>
5919
+ <a id="__codelineno-0-313" name="__codelineno-0-313"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5920
+ <a id="__codelineno-0-314" name="__codelineno-0-314"></a> <span class="n">destination_type</span><span class="o">=</span><span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="p">,</span>
5921
+ <a id="__codelineno-0-315" name="__codelineno-0-315"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5922
+ <a id="__codelineno-0-316" name="__codelineno-0-316"></a> <span class="p">)</span>
5923
+ <a id="__codelineno-0-317" name="__codelineno-0-317"></a> <span class="n">created</span> <span class="o">=</span> <span class="kc">True</span>
5924
+ <a id="__codelineno-0-318" name="__codelineno-0-318"></a>
5925
+ <a id="__codelineno-0-319" name="__codelineno-0-319"></a> <span class="k">if</span> <span class="n">created</span><span class="p">:</span>
5926
+ <a id="__codelineno-0-320" name="__codelineno-0-320"></a> <span class="n">ra</span><span class="o">.</span><span class="n">validated_save</span><span class="p">()</span>
5927
+ <a id="__codelineno-0-321" name="__codelineno-0-321"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Created </span><span class="si">%s</span><span class="s2">&quot;</span><span class="p">,</span> <span class="n">ra</span><span class="p">)</span>
5928
+ <a id="__codelineno-0-322" name="__codelineno-0-322"></a>
5929
+ <a id="__codelineno-0-323" name="__codelineno-0-323"></a> <span class="k">if</span> <span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">:</span>
5930
+ <a id="__codelineno-0-324" name="__codelineno-0-324"></a> <span class="n">removed</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;remove_</span><span class="si">{</span><span class="n">field_name</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5931
+ <a id="__codelineno-0-325" name="__codelineno-0-325"></a>
5932
+ <a id="__codelineno-0-326" name="__codelineno-0-326"></a> <span class="n">source_count</span> <span class="o">=</span> <span class="mi">0</span>
5933
+ <a id="__codelineno-0-327" name="__codelineno-0-327"></a> <span class="n">destination_count</span> <span class="o">=</span> <span class="mi">0</span>
5934
+ <a id="__codelineno-0-328" name="__codelineno-0-328"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
5935
+ <a id="__codelineno-0-329" name="__codelineno-0-329"></a> <span class="n">source_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5936
+ <a id="__codelineno-0-330" name="__codelineno-0-330"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5937
+ <a id="__codelineno-0-331" name="__codelineno-0-331"></a> <span class="n">source_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5938
+ <a id="__codelineno-0-332" name="__codelineno-0-332"></a> <span class="n">destination_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
5939
+ <a id="__codelineno-0-333" name="__codelineno-0-333"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
5940
+ <a id="__codelineno-0-334" name="__codelineno-0-334"></a> <span class="k">if</span> <span class="n">side</span> <span class="ow">in</span> <span class="p">[</span><span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">,</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">]:</span>
5941
+ <a id="__codelineno-0-335" name="__codelineno-0-335"></a> <span class="n">destination_count</span><span class="p">,</span> <span class="n">_</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5942
+ <a id="__codelineno-0-336" name="__codelineno-0-336"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5943
+ <a id="__codelineno-0-337" name="__codelineno-0-337"></a> <span class="n">source_id__in</span><span class="o">=</span><span class="p">[</span><span class="n">target</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">target</span> <span class="ow">in</span> <span class="n">removed</span><span class="p">],</span>
5944
+ <a id="__codelineno-0-338" name="__codelineno-0-338"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5945
+ <a id="__codelineno-0-339" name="__codelineno-0-339"></a> <span class="p">)</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
5946
+ <a id="__codelineno-0-340" name="__codelineno-0-340"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Deleted </span><span class="si">%s</span><span class="s2"> RelationshipAssociation(s)&quot;</span><span class="p">,</span> <span class="n">source_count</span> <span class="o">+</span> <span class="n">destination_count</span><span class="p">)</span>
4756
5947
  </code></pre></div></td></tr></table></div>
4757
5948
  </details>
4758
5949
  </div>
@@ -4786,7 +5977,9 @@ NoteModelFormMixin are needed.</p>
4786
5977
 
4787
5978
  <details class="quote">
4788
5979
  <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
4789
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-442">442</a></span>
5980
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-440">440</a></span>
5981
+ <span class="normal"><a href="#__codelineno-0-441">441</a></span>
5982
+ <span class="normal"><a href="#__codelineno-0-442">442</a></span>
4790
5983
  <span class="normal"><a href="#__codelineno-0-443">443</a></span>
4791
5984
  <span class="normal"><a href="#__codelineno-0-444">444</a></span>
4792
5985
  <span class="normal"><a href="#__codelineno-0-445">445</a></span>
@@ -4980,205 +6173,203 @@ NoteModelFormMixin are needed.</p>
4980
6173
  <span class="normal"><a href="#__codelineno-0-633">633</a></span>
4981
6174
  <span class="normal"><a href="#__codelineno-0-634">634</a></span>
4982
6175
  <span class="normal"><a href="#__codelineno-0-635">635</a></span>
4983
- <span class="normal"><a href="#__codelineno-0-636">636</a></span>
4984
- <span class="normal"><a href="#__codelineno-0-637">637</a></span>
4985
- <span class="normal"><a href="#__codelineno-0-638">638</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-442" name="__codelineno-0-442"></a><span class="k">class</span> <span class="nc">RelationshipModelFormMixin</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
4986
- <a id="__codelineno-0-443" name="__codelineno-0-443"></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>
4987
- <a id="__codelineno-0-444" name="__codelineno-0-444"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
4988
- <a id="__codelineno-0-445" name="__codelineno-0-445"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span> <span class="o">=</span> <span class="p">[]</span>
4989
- <a id="__codelineno-0-446" name="__codelineno-0-446"></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>
6176
+ <span class="normal"><a href="#__codelineno-0-636">636</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-440" name="__codelineno-0-440"></a><span class="k">class</span> <span class="nc">RelationshipModelFormMixin</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">ModelForm</span><span class="p">):</span>
6177
+ <a id="__codelineno-0-441" name="__codelineno-0-441"></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>
6178
+ <a id="__codelineno-0-442" name="__codelineno-0-442"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</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">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
6179
+ <a id="__codelineno-0-443" name="__codelineno-0-443"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span> <span class="o">=</span> <span class="p">[]</span>
6180
+ <a id="__codelineno-0-444" name="__codelineno-0-444"></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>
6181
+ <a id="__codelineno-0-445" name="__codelineno-0-445"></a>
6182
+ <a id="__codelineno-0-446" name="__codelineno-0-446"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships</span><span class="p">()</span>
4990
6183
  <a id="__codelineno-0-447" name="__codelineno-0-447"></a>
4991
- <a id="__codelineno-0-448" name="__codelineno-0-448"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships</span><span class="p">()</span>
4992
- <a id="__codelineno-0-449" name="__codelineno-0-449"></a>
4993
- <a id="__codelineno-0-450" name="__codelineno-0-450"></a> <span class="k">def</span> <span class="nf">_append_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4994
- <a id="__codelineno-0-451" name="__codelineno-0-451"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4995
- <a id="__codelineno-0-452" name="__codelineno-0-452"></a><span class="sd"> Append form fields for all Relationships assigned to this model.</span>
4996
- <a id="__codelineno-0-453" name="__codelineno-0-453"></a><span class="sd"> One form field per side will be added to the list.</span>
4997
- <a id="__codelineno-0-454" name="__codelineno-0-454"></a><span class="sd"> &quot;&quot;&quot;</span>
4998
- <a id="__codelineno-0-455" name="__codelineno-0-455"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4999
- <a id="__codelineno-0-456" name="__codelineno-0-456"></a> <span class="k">for</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">queryset</span> <span class="ow">in</span> <span class="n">relationships</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5000
- <a id="__codelineno-0-457" name="__codelineno-0-457"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
5001
- <a id="__codelineno-0-458" name="__codelineno-0-458"></a> <span class="c1"># If this model is on the &quot;source&quot; side of the relationship, then the field will be named</span>
5002
- <a id="__codelineno-0-459" name="__codelineno-0-459"></a> <span class="c1"># cr_&lt;relationship-slug&gt;__destination since it&#39;s used to pick the destination object(s).</span>
5003
- <a id="__codelineno-0-460" name="__codelineno-0-460"></a> <span class="c1"># If we&#39;re on the &quot;destination&quot; side, the field will be cr_&lt;relationship-slug&gt;__source.</span>
5004
- <a id="__codelineno-0-461" name="__codelineno-0-461"></a> <span class="c1"># For a symmetric relationship, both sides are &quot;peer&quot;, so the field will be cr_&lt;relationship-slug&gt;__peer</span>
5005
- <a id="__codelineno-0-462" name="__codelineno-0-462"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">slug</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
5006
- <a id="__codelineno-0-463" name="__codelineno-0-463"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
5007
- <a id="__codelineno-0-464" name="__codelineno-0-464"></a>
5008
- <a id="__codelineno-0-465" name="__codelineno-0-465"></a> <span class="c1"># HTML5 validation for required relationship field:</span>
5009
- <a id="__codelineno-0-466" name="__codelineno-0-466"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span> <span class="o">==</span> <span class="n">side</span><span class="p">:</span>
5010
- <a id="__codelineno-0-467" name="__codelineno-0-467"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">required</span> <span class="o">=</span> <span class="kc">True</span>
5011
- <a id="__codelineno-0-468" name="__codelineno-0-468"></a>
5012
- <a id="__codelineno-0-469" name="__codelineno-0-469"></a> <span class="c1"># if the object already exists, populate the field with existing values</span>
5013
- <a id="__codelineno-0-470" name="__codelineno-0-470"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">present_in_database</span><span class="p">:</span>
5014
- <a id="__codelineno-0-471" name="__codelineno-0-471"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
5015
- <a id="__codelineno-0-472" name="__codelineno-0-472"></a> <span class="n">initial</span> <span class="o">=</span> <span class="p">[</span><span class="n">association</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="p">)</span> <span class="k">for</span> <span class="n">association</span> <span class="ow">in</span> <span class="n">queryset</span><span class="o">.</span><span class="n">all</span><span class="p">()]</span>
5016
- <a id="__codelineno-0-473" name="__codelineno-0-473"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">initial</span> <span class="o">=</span> <span class="n">initial</span>
5017
- <a id="__codelineno-0-474" name="__codelineno-0-474"></a> <span class="k">else</span><span class="p">:</span>
5018
- <a id="__codelineno-0-475" name="__codelineno-0-475"></a> <span class="n">association</span> <span class="o">=</span> <span class="n">queryset</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
5019
- <a id="__codelineno-0-476" name="__codelineno-0-476"></a> <span class="k">if</span> <span class="n">association</span><span class="p">:</span>
5020
- <a id="__codelineno-0-477" name="__codelineno-0-477"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">initial</span> <span class="o">=</span> <span class="n">association</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="p">)</span>
5021
- <a id="__codelineno-0-478" name="__codelineno-0-478"></a>
5022
- <a id="__codelineno-0-479" name="__codelineno-0-479"></a> <span class="c1"># Annotate the field in the list of Relationship form fields</span>
5023
- <a id="__codelineno-0-480" name="__codelineno-0-480"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5024
- <a id="__codelineno-0-481" name="__codelineno-0-481"></a>
5025
- <a id="__codelineno-0-482" name="__codelineno-0-482"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5026
- <a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5027
- <a id="__codelineno-0-484" name="__codelineno-0-484"></a><span class="sd"> First check for any required relationships errors and if there are any, add them via form field errors.</span>
5028
- <a id="__codelineno-0-485" name="__codelineno-0-485"></a><span class="sd"> Then verify that any requested RelationshipAssociations do not violate relationship cardinality restrictions.</span>
5029
- <a id="__codelineno-0-486" name="__codelineno-0-486"></a>
5030
- <a id="__codelineno-0-487" name="__codelineno-0-487"></a><span class="sd"> - For TYPE_ONE_TO_MANY and TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;source&quot; side of</span>
5031
- <a id="__codelineno-0-488" name="__codelineno-0-488"></a><span class="sd"> the relationship, verify that the requested &quot;destination&quot; object(s) do not already have any existing</span>
5032
- <a id="__codelineno-0-489" name="__codelineno-0-489"></a><span class="sd"> RelationshipAssociation to a different source object.</span>
5033
- <a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="sd"> - For TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;destination&quot; side of the relationship,</span>
5034
- <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="sd"> verify that the requested &quot;source&quot; object does not have an existing RelationshipAssociation to</span>
5035
- <a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> a different destination object.</span>
5036
- <a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> &quot;&quot;&quot;</span>
5037
- <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="n">required_relationships_errors</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Meta</span><span class="p">()</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">required_related_objects_errors</span><span class="p">(</span>
5038
- <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="n">output_for</span><span class="o">=</span><span class="s2">&quot;ui&quot;</span><span class="p">,</span> <span class="n">initial_data</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">,</span> <span class="n">instance</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span>
5039
- <a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="p">)</span>
5040
- <a id="__codelineno-0-497" name="__codelineno-0-497"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">errors</span> <span class="ow">in</span> <span class="n">required_relationships_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5041
- <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span>
5042
- <a id="__codelineno-0-499" name="__codelineno-0-499"></a>
5043
- <a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5044
- <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
5045
- <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="c1"># The form field name reflects what it provides, i.e. the peer object(s) to link via this relationship.</span>
5046
- <a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
5047
- <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">slug</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
5048
- <a id="__codelineno-0-505" name="__codelineno-0-505"></a>
5049
- <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="c1"># Is the form trying to set this field (create/update a RelationshipAssociation(s))?</span>
5050
- <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="c1"># If not (that is, clearing the field / deleting RelationshipAssociation(s)), we don&#39;t need to check.</span>
5051
- <a id="__codelineno-0-508" name="__codelineno-0-508"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]:</span>
5052
- <a id="__codelineno-0-509" name="__codelineno-0-509"></a> <span class="k">continue</span>
5053
- <a id="__codelineno-0-510" name="__codelineno-0-510"></a>
5054
- <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="c1"># Are any of the objects we want a relationship with already entangled with another object?</span>
5055
- <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
5056
- <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">])</span>
5057
- <a id="__codelineno-0-514" name="__codelineno-0-514"></a> <span class="k">else</span><span class="p">:</span>
5058
- <a id="__codelineno-0-515" name="__codelineno-0-515"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]]</span>
5059
- <a id="__codelineno-0-516" name="__codelineno-0-516"></a>
5060
- <a id="__codelineno-0-517" name="__codelineno-0-517"></a> <span class="k">for</span> <span class="n">target_peer</span> <span class="ow">in</span> <span class="n">target_peers</span><span class="p">:</span>
5061
- <a id="__codelineno-0-518" name="__codelineno-0-518"></a> <span class="k">if</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">:</span>
5062
- <a id="__codelineno-0-519" name="__codelineno-0-519"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
5063
- <a id="__codelineno-0-520" name="__codelineno-0-520"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;Object </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="si">}</span><span class="s2"> cannot form a relationship to itself!&quot;</span><span class="p">}</span>
5064
- <a id="__codelineno-0-521" name="__codelineno-0-521"></a> <span class="p">)</span>
5065
- <a id="__codelineno-0-522" name="__codelineno-0-522"></a>
5066
- <a id="__codelineno-0-523" name="__codelineno-0-523"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">side</span><span class="p">):</span>
5067
- <a id="__codelineno-0-524" name="__codelineno-0-524"></a> <span class="c1"># No need to check for existing RelationshipAssociations since this is a &quot;many&quot; relationship</span>
5068
- <a id="__codelineno-0-525" name="__codelineno-0-525"></a> <span class="k">continue</span>
5069
- <a id="__codelineno-0-526" name="__codelineno-0-526"></a>
5070
- <a id="__codelineno-0-527" name="__codelineno-0-527"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
5071
- <a id="__codelineno-0-528" name="__codelineno-0-528"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5072
- <a id="__codelineno-0-529" name="__codelineno-0-529"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5073
- <a id="__codelineno-0-530" name="__codelineno-0-530"></a> <span class="o">**</span><span class="p">{</span>
5074
- <a id="__codelineno-0-531" name="__codelineno-0-531"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5075
- <a id="__codelineno-0-532" name="__codelineno-0-532"></a> <span class="p">},</span>
5076
- <a id="__codelineno-0-533" name="__codelineno-0-533"></a> <span class="p">)</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>
5077
- <a id="__codelineno-0-534" name="__codelineno-0-534"></a> <span class="k">else</span><span class="p">:</span>
5078
- <a id="__codelineno-0-535" name="__codelineno-0-535"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5079
- <a id="__codelineno-0-536" name="__codelineno-0-536"></a> <span class="p">(</span>
5080
- <a id="__codelineno-0-537" name="__codelineno-0-537"></a> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
5081
- <a id="__codelineno-0-538" name="__codelineno-0-538"></a> <span class="o">|</span> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
5082
- <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="p">),</span>
5083
- <a id="__codelineno-0-540" name="__codelineno-0-540"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5084
- <a id="__codelineno-0-541" name="__codelineno-0-541"></a> <span class="p">)</span>
5085
- <a id="__codelineno-0-542" name="__codelineno-0-542"></a>
5086
- <a id="__codelineno-0-543" name="__codelineno-0-543"></a> <span class="k">if</span> <span class="n">existing_peer_associations</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
5087
- <a id="__codelineno-0-544" name="__codelineno-0-544"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
5088
- <a id="__codelineno-0-545" name="__codelineno-0-545"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">target_peer</span><span class="si">}</span><span class="s2"> is already involved in a </span><span class="si">{</span><span class="n">relationship</span><span class="si">}</span><span class="s2"> relationship&quot;</span><span class="p">}</span>
5089
- <a id="__codelineno-0-546" name="__codelineno-0-546"></a> <span class="p">)</span>
6184
+ <a id="__codelineno-0-448" name="__codelineno-0-448"></a> <span class="k">def</span> <span class="nf">_append_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
6185
+ <a id="__codelineno-0-449" name="__codelineno-0-449"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6186
+ <a id="__codelineno-0-450" name="__codelineno-0-450"></a><span class="sd"> Append form fields for all Relationships assigned to this model.</span>
6187
+ <a id="__codelineno-0-451" name="__codelineno-0-451"></a><span class="sd"> One form field per side will be added to the list.</span>
6188
+ <a id="__codelineno-0-452" name="__codelineno-0-452"></a><span class="sd"> &quot;&quot;&quot;</span>
6189
+ <a id="__codelineno-0-453" name="__codelineno-0-453"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
6190
+ <a id="__codelineno-0-454" name="__codelineno-0-454"></a> <span class="k">for</span> <span class="n">relationship</span><span class="p">,</span> <span class="n">queryset</span> <span class="ow">in</span> <span class="n">relationships</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
6191
+ <a id="__codelineno-0-455" name="__codelineno-0-455"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
6192
+ <a id="__codelineno-0-456" name="__codelineno-0-456"></a> <span class="c1"># If this model is on the &quot;source&quot; side of the relationship, then the field will be named</span>
6193
+ <a id="__codelineno-0-457" name="__codelineno-0-457"></a> <span class="c1"># cr_&lt;relationship_key&gt;__destination since it&#39;s used to pick the destination object(s).</span>
6194
+ <a id="__codelineno-0-458" name="__codelineno-0-458"></a> <span class="c1"># If we&#39;re on the &quot;destination&quot; side, the field will be cr_&lt;relationship_key&gt;__source.</span>
6195
+ <a id="__codelineno-0-459" name="__codelineno-0-459"></a> <span class="c1"># For a symmetric relationship, both sides are &quot;peer&quot;, so the field will be cr_&lt;relationship_key&gt;__peer</span>
6196
+ <a id="__codelineno-0-460" name="__codelineno-0-460"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
6197
+ <a id="__codelineno-0-461" name="__codelineno-0-461"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">to_form_field</span><span class="p">(</span><span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">)</span>
6198
+ <a id="__codelineno-0-462" name="__codelineno-0-462"></a>
6199
+ <a id="__codelineno-0-463" name="__codelineno-0-463"></a> <span class="c1"># HTML5 validation for required relationship field:</span>
6200
+ <a id="__codelineno-0-464" name="__codelineno-0-464"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">required_on</span> <span class="o">==</span> <span class="n">side</span><span class="p">:</span>
6201
+ <a id="__codelineno-0-465" name="__codelineno-0-465"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">required</span> <span class="o">=</span> <span class="kc">True</span>
6202
+ <a id="__codelineno-0-466" name="__codelineno-0-466"></a>
6203
+ <a id="__codelineno-0-467" name="__codelineno-0-467"></a> <span class="c1"># if the object already exists, populate the field with existing values</span>
6204
+ <a id="__codelineno-0-468" name="__codelineno-0-468"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">present_in_database</span><span class="p">:</span>
6205
+ <a id="__codelineno-0-469" name="__codelineno-0-469"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
6206
+ <a id="__codelineno-0-470" name="__codelineno-0-470"></a> <span class="n">initial</span> <span class="o">=</span> <span class="p">[</span><span class="n">association</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="p">)</span> <span class="k">for</span> <span class="n">association</span> <span class="ow">in</span> <span class="n">queryset</span><span class="o">.</span><span class="n">all</span><span class="p">()]</span>
6207
+ <a id="__codelineno-0-471" name="__codelineno-0-471"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">initial</span> <span class="o">=</span> <span class="n">initial</span>
6208
+ <a id="__codelineno-0-472" name="__codelineno-0-472"></a> <span class="k">else</span><span class="p">:</span>
6209
+ <a id="__codelineno-0-473" name="__codelineno-0-473"></a> <span class="n">association</span> <span class="o">=</span> <span class="n">queryset</span><span class="o">.</span><span class="n">first</span><span class="p">()</span>
6210
+ <a id="__codelineno-0-474" name="__codelineno-0-474"></a> <span class="k">if</span> <span class="n">association</span><span class="p">:</span>
6211
+ <a id="__codelineno-0-475" name="__codelineno-0-475"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">initial</span> <span class="o">=</span> <span class="n">association</span><span class="o">.</span><span class="n">get_peer</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="p">)</span>
6212
+ <a id="__codelineno-0-476" name="__codelineno-0-476"></a>
6213
+ <a id="__codelineno-0-477" name="__codelineno-0-477"></a> <span class="c1"># Annotate the field in the list of Relationship form fields</span>
6214
+ <a id="__codelineno-0-478" name="__codelineno-0-478"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
6215
+ <a id="__codelineno-0-479" name="__codelineno-0-479"></a>
6216
+ <a id="__codelineno-0-480" name="__codelineno-0-480"></a> <span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
6217
+ <a id="__codelineno-0-481" name="__codelineno-0-481"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6218
+ <a id="__codelineno-0-482" name="__codelineno-0-482"></a><span class="sd"> First check for any required relationships errors and if there are any, add them via form field errors.</span>
6219
+ <a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="sd"> Then verify that any requested RelationshipAssociations do not violate relationship cardinality restrictions.</span>
6220
+ <a id="__codelineno-0-484" name="__codelineno-0-484"></a>
6221
+ <a id="__codelineno-0-485" name="__codelineno-0-485"></a><span class="sd"> - For TYPE_ONE_TO_MANY and TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;source&quot; side of</span>
6222
+ <a id="__codelineno-0-486" name="__codelineno-0-486"></a><span class="sd"> the relationship, verify that the requested &quot;destination&quot; object(s) do not already have any existing</span>
6223
+ <a id="__codelineno-0-487" name="__codelineno-0-487"></a><span class="sd"> RelationshipAssociation to a different source object.</span>
6224
+ <a id="__codelineno-0-488" name="__codelineno-0-488"></a><span class="sd"> - For TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;destination&quot; side of the relationship,</span>
6225
+ <a id="__codelineno-0-489" name="__codelineno-0-489"></a><span class="sd"> verify that the requested &quot;source&quot; object does not have an existing RelationshipAssociation to</span>
6226
+ <a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="sd"> a different destination object.</span>
6227
+ <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="sd"> &quot;&quot;&quot;</span>
6228
+ <a id="__codelineno-0-492" name="__codelineno-0-492"></a> <span class="n">required_relationships_errors</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Meta</span><span class="p">()</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">required_related_objects_errors</span><span class="p">(</span>
6229
+ <a id="__codelineno-0-493" name="__codelineno-0-493"></a> <span class="n">output_for</span><span class="o">=</span><span class="s2">&quot;ui&quot;</span><span class="p">,</span> <span class="n">initial_data</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">,</span> <span class="n">instance</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span>
6230
+ <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="p">)</span>
6231
+ <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">errors</span> <span class="ow">in</span> <span class="n">required_relationships_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
6232
+ <a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span>
6233
+ <a id="__codelineno-0-497" name="__codelineno-0-497"></a>
6234
+ <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
6235
+ <a id="__codelineno-0-499" name="__codelineno-0-499"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
6236
+ <a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="c1"># The form field name reflects what it provides, i.e. the peer object(s) to link via this relationship.</span>
6237
+ <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
6238
+ <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
6239
+ <a id="__codelineno-0-503" name="__codelineno-0-503"></a>
6240
+ <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="c1"># Is the form trying to set this field (create/update a RelationshipAssociation(s))?</span>
6241
+ <a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="c1"># If not (that is, clearing the field / deleting RelationshipAssociation(s)), we don&#39;t need to check.</span>
6242
+ <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]:</span>
6243
+ <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="k">continue</span>
6244
+ <a id="__codelineno-0-508" name="__codelineno-0-508"></a>
6245
+ <a id="__codelineno-0-509" name="__codelineno-0-509"></a> <span class="c1"># Are any of the objects we want a relationship with already entangled with another object?</span>
6246
+ <a id="__codelineno-0-510" name="__codelineno-0-510"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
6247
+ <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">])</span>
6248
+ <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="k">else</span><span class="p">:</span>
6249
+ <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]]</span>
6250
+ <a id="__codelineno-0-514" name="__codelineno-0-514"></a>
6251
+ <a id="__codelineno-0-515" name="__codelineno-0-515"></a> <span class="k">for</span> <span class="n">target_peer</span> <span class="ow">in</span> <span class="n">target_peers</span><span class="p">:</span>
6252
+ <a id="__codelineno-0-516" name="__codelineno-0-516"></a> <span class="k">if</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">:</span>
6253
+ <a id="__codelineno-0-517" name="__codelineno-0-517"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
6254
+ <a id="__codelineno-0-518" name="__codelineno-0-518"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;Object </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="si">}</span><span class="s2"> cannot form a relationship to itself!&quot;</span><span class="p">}</span>
6255
+ <a id="__codelineno-0-519" name="__codelineno-0-519"></a> <span class="p">)</span>
6256
+ <a id="__codelineno-0-520" name="__codelineno-0-520"></a>
6257
+ <a id="__codelineno-0-521" name="__codelineno-0-521"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">side</span><span class="p">):</span>
6258
+ <a id="__codelineno-0-522" name="__codelineno-0-522"></a> <span class="c1"># No need to check for existing RelationshipAssociations since this is a &quot;many&quot; relationship</span>
6259
+ <a id="__codelineno-0-523" name="__codelineno-0-523"></a> <span class="k">continue</span>
6260
+ <a id="__codelineno-0-524" name="__codelineno-0-524"></a>
6261
+ <a id="__codelineno-0-525" name="__codelineno-0-525"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
6262
+ <a id="__codelineno-0-526" name="__codelineno-0-526"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
6263
+ <a id="__codelineno-0-527" name="__codelineno-0-527"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
6264
+ <a id="__codelineno-0-528" name="__codelineno-0-528"></a> <span class="o">**</span><span class="p">{</span>
6265
+ <a id="__codelineno-0-529" name="__codelineno-0-529"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
6266
+ <a id="__codelineno-0-530" name="__codelineno-0-530"></a> <span class="p">},</span>
6267
+ <a id="__codelineno-0-531" name="__codelineno-0-531"></a> <span class="p">)</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>
6268
+ <a id="__codelineno-0-532" name="__codelineno-0-532"></a> <span class="k">else</span><span class="p">:</span>
6269
+ <a id="__codelineno-0-533" name="__codelineno-0-533"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
6270
+ <a id="__codelineno-0-534" name="__codelineno-0-534"></a> <span class="p">(</span>
6271
+ <a id="__codelineno-0-535" name="__codelineno-0-535"></a> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
6272
+ <a id="__codelineno-0-536" name="__codelineno-0-536"></a> <span class="o">|</span> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
6273
+ <a id="__codelineno-0-537" name="__codelineno-0-537"></a> <span class="p">),</span>
6274
+ <a id="__codelineno-0-538" name="__codelineno-0-538"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
6275
+ <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="p">)</span>
6276
+ <a id="__codelineno-0-540" name="__codelineno-0-540"></a>
6277
+ <a id="__codelineno-0-541" name="__codelineno-0-541"></a> <span class="k">if</span> <span class="n">existing_peer_associations</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
6278
+ <a id="__codelineno-0-542" name="__codelineno-0-542"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
6279
+ <a id="__codelineno-0-543" name="__codelineno-0-543"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">target_peer</span><span class="si">}</span><span class="s2"> is already involved in a </span><span class="si">{</span><span class="n">relationship</span><span class="si">}</span><span class="s2"> relationship&quot;</span><span class="p">}</span>
6280
+ <a id="__codelineno-0-544" name="__codelineno-0-544"></a> <span class="p">)</span>
6281
+ <a id="__codelineno-0-545" name="__codelineno-0-545"></a>
6282
+ <a id="__codelineno-0-546" name="__codelineno-0-546"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
5090
6283
  <a id="__codelineno-0-547" name="__codelineno-0-547"></a>
5091
- <a id="__codelineno-0-548" name="__codelineno-0-548"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
5092
- <a id="__codelineno-0-549" name="__codelineno-0-549"></a>
5093
- <a id="__codelineno-0-550" name="__codelineno-0-550"></a> <span class="k">def</span> <span class="nf">_save_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5094
- <a id="__codelineno-0-551" name="__codelineno-0-551"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Update RelationshipAssociations for all Relationships on form save.&quot;&quot;&quot;</span>
5095
- <a id="__codelineno-0-552" name="__codelineno-0-552"></a>
5096
- <a id="__codelineno-0-553" name="__codelineno-0-553"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="p">:</span>
5097
- <a id="__codelineno-0-554" name="__codelineno-0-554"></a> <span class="c1"># The field name tells us the side of the relationship that it is providing peer objects(s) to link into.</span>
5098
- <a id="__codelineno-0-555" name="__codelineno-0-555"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">field_name</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="o">-</span><span class="mi">1</span><span class="p">]</span>
5099
- <a id="__codelineno-0-556" name="__codelineno-0-556"></a> <span class="c1"># Based on the side of the relationship that our local object represents,</span>
5100
- <a id="__codelineno-0-557" name="__codelineno-0-557"></a> <span class="c1"># find the list of existing RelationshipAssociations it already has for this Relationship.</span>
5101
- <a id="__codelineno-0-558" name="__codelineno-0-558"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">peer_side</span><span class="p">]</span>
5102
- <a id="__codelineno-0-559" name="__codelineno-0-559"></a> <span class="n">filters</span> <span class="o">=</span> <span class="p">{</span>
5103
- <a id="__codelineno-0-560" name="__codelineno-0-560"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">model</span><span class="p">,</span>
5104
- <a id="__codelineno-0-561" name="__codelineno-0-561"></a> <span class="p">}</span>
5105
- <a id="__codelineno-0-562" name="__codelineno-0-562"></a> <span class="k">if</span> <span class="n">side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
5106
- <a id="__codelineno-0-563" name="__codelineno-0-563"></a> <span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>
5107
- <a id="__codelineno-0-564" name="__codelineno-0-564"></a> <span class="n">existing_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">**</span><span class="n">filters</span><span class="p">)</span>
5108
- <a id="__codelineno-0-565" name="__codelineno-0-565"></a> <span class="k">else</span><span class="p">:</span>
5109
- <a id="__codelineno-0-566" name="__codelineno-0-566"></a> <span class="n">existing_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5110
- <a id="__codelineno-0-567" name="__codelineno-0-567"></a> <span class="p">(</span>
5111
- <a id="__codelineno-0-568" name="__codelineno-0-568"></a> <span class="n">Q</span><span class="p">(</span><span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
5112
- <a id="__codelineno-0-569" name="__codelineno-0-569"></a> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">destination_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
5113
- <a id="__codelineno-0-570" name="__codelineno-0-570"></a> <span class="p">),</span>
5114
- <a id="__codelineno-0-571" name="__codelineno-0-571"></a> <span class="o">**</span><span class="n">filters</span><span class="p">,</span>
5115
- <a id="__codelineno-0-572" name="__codelineno-0-572"></a> <span class="p">)</span>
5116
- <a id="__codelineno-0-573" name="__codelineno-0-573"></a>
5117
- <a id="__codelineno-0-574" name="__codelineno-0-574"></a> <span class="c1"># Get the list of target peer ids (PKs) that are specified in the form</span>
5118
- <a id="__codelineno-0-575" name="__codelineno-0-575"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[]</span>
5119
- <a id="__codelineno-0-576" name="__codelineno-0-576"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">],</span> <span class="s2">&quot;__iter__&quot;</span><span class="p">):</span>
5120
- <a id="__codelineno-0-577" name="__codelineno-0-577"></a> <span class="c1"># One-to-many or many-to-many association</span>
5121
- <a id="__codelineno-0-578" name="__codelineno-0-578"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[</span><span class="n">item</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]]</span>
5122
- <a id="__codelineno-0-579" name="__codelineno-0-579"></a> <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]:</span>
5123
- <a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="c1"># Many-to-one or one-to-one association</span>
5124
- <a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">pk</span><span class="p">]</span>
5125
- <a id="__codelineno-0-582" name="__codelineno-0-582"></a> <span class="k">else</span><span class="p">:</span>
5126
- <a id="__codelineno-0-583" name="__codelineno-0-583"></a> <span class="c1"># Unset/delete case</span>
5127
- <a id="__codelineno-0-584" name="__codelineno-0-584"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[]</span>
6284
+ <a id="__codelineno-0-548" name="__codelineno-0-548"></a> <span class="k">def</span> <span class="nf">_save_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
6285
+ <a id="__codelineno-0-549" name="__codelineno-0-549"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Update RelationshipAssociations for all Relationships on form save.&quot;&quot;&quot;</span>
6286
+ <a id="__codelineno-0-550" name="__codelineno-0-550"></a>
6287
+ <a id="__codelineno-0-551" name="__codelineno-0-551"></a> <span class="k">for</span> <span class="n">field_name</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="p">:</span>
6288
+ <a id="__codelineno-0-552" name="__codelineno-0-552"></a> <span class="c1"># The field name tells us the side of the relationship that it is providing peer objects(s) to link into.</span>
6289
+ <a id="__codelineno-0-553" name="__codelineno-0-553"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">field_name</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="o">-</span><span class="mi">1</span><span class="p">]</span>
6290
+ <a id="__codelineno-0-554" name="__codelineno-0-554"></a> <span class="c1"># Based on the side of the relationship that our local object represents,</span>
6291
+ <a id="__codelineno-0-555" name="__codelineno-0-555"></a> <span class="c1"># find the list of existing RelationshipAssociations it already has for this Relationship.</span>
6292
+ <a id="__codelineno-0-556" name="__codelineno-0-556"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">peer_side</span><span class="p">]</span>
6293
+ <a id="__codelineno-0-557" name="__codelineno-0-557"></a> <span class="n">filters</span> <span class="o">=</span> <span class="p">{</span>
6294
+ <a id="__codelineno-0-558" name="__codelineno-0-558"></a> <span class="s2">&quot;relationship&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">model</span><span class="p">,</span>
6295
+ <a id="__codelineno-0-559" name="__codelineno-0-559"></a> <span class="p">}</span>
6296
+ <a id="__codelineno-0-560" name="__codelineno-0-560"></a> <span class="k">if</span> <span class="n">side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
6297
+ <a id="__codelineno-0-561" name="__codelineno-0-561"></a> <span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">({</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>
6298
+ <a id="__codelineno-0-562" name="__codelineno-0-562"></a> <span class="n">existing_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="o">**</span><span class="n">filters</span><span class="p">)</span>
6299
+ <a id="__codelineno-0-563" name="__codelineno-0-563"></a> <span class="k">else</span><span class="p">:</span>
6300
+ <a id="__codelineno-0-564" name="__codelineno-0-564"></a> <span class="n">existing_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
6301
+ <a id="__codelineno-0-565" name="__codelineno-0-565"></a> <span class="p">(</span>
6302
+ <a id="__codelineno-0-566" name="__codelineno-0-566"></a> <span class="n">Q</span><span class="p">(</span><span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
6303
+ <a id="__codelineno-0-567" name="__codelineno-0-567"></a> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span><span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">destination_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
6304
+ <a id="__codelineno-0-568" name="__codelineno-0-568"></a> <span class="p">),</span>
6305
+ <a id="__codelineno-0-569" name="__codelineno-0-569"></a> <span class="o">**</span><span class="n">filters</span><span class="p">,</span>
6306
+ <a id="__codelineno-0-570" name="__codelineno-0-570"></a> <span class="p">)</span>
6307
+ <a id="__codelineno-0-571" name="__codelineno-0-571"></a>
6308
+ <a id="__codelineno-0-572" name="__codelineno-0-572"></a> <span class="c1"># Get the list of target peer ids (PKs) that are specified in the form</span>
6309
+ <a id="__codelineno-0-573" name="__codelineno-0-573"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[]</span>
6310
+ <a id="__codelineno-0-574" name="__codelineno-0-574"></a> <span class="k">if</span> <span class="nb">hasattr</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">],</span> <span class="s2">&quot;__iter__&quot;</span><span class="p">):</span>
6311
+ <a id="__codelineno-0-575" name="__codelineno-0-575"></a> <span class="c1"># One-to-many or many-to-many association</span>
6312
+ <a id="__codelineno-0-576" name="__codelineno-0-576"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[</span><span class="n">item</span><span class="o">.</span><span class="n">pk</span> <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]]</span>
6313
+ <a id="__codelineno-0-577" name="__codelineno-0-577"></a> <span class="k">elif</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]:</span>
6314
+ <a id="__codelineno-0-578" name="__codelineno-0-578"></a> <span class="c1"># Many-to-one or one-to-one association</span>
6315
+ <a id="__codelineno-0-579" name="__codelineno-0-579"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">pk</span><span class="p">]</span>
6316
+ <a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="k">else</span><span class="p">:</span>
6317
+ <a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="c1"># Unset/delete case</span>
6318
+ <a id="__codelineno-0-582" name="__codelineno-0-582"></a> <span class="n">target_peer_ids</span> <span class="o">=</span> <span class="p">[]</span>
6319
+ <a id="__codelineno-0-583" name="__codelineno-0-583"></a>
6320
+ <a id="__codelineno-0-584" name="__codelineno-0-584"></a> <span class="c1"># Create/delete RelationshipAssociations as needed to match the target_peer_ids list</span>
5128
6321
  <a id="__codelineno-0-585" name="__codelineno-0-585"></a>
5129
- <a id="__codelineno-0-586" name="__codelineno-0-586"></a> <span class="c1"># Create/delete RelationshipAssociations as needed to match the target_peer_ids list</span>
5130
- <a id="__codelineno-0-587" name="__codelineno-0-587"></a>
5131
- <a id="__codelineno-0-588" name="__codelineno-0-588"></a> <span class="c1"># First, for each existing association, if it&#39;s one that&#39;s already in target_peer_ids,</span>
5132
- <a id="__codelineno-0-589" name="__codelineno-0-589"></a> <span class="c1"># we can discard it from target_peer_ids (no update needed to this association).</span>
5133
- <a id="__codelineno-0-590" name="__codelineno-0-590"></a> <span class="c1"># Conversely, if it&#39;s *not* in target_peer_ids, we should delete it.</span>
5134
- <a id="__codelineno-0-591" name="__codelineno-0-591"></a> <span class="k">for</span> <span class="n">association</span> <span class="ow">in</span> <span class="n">existing_associations</span><span class="p">:</span>
5135
- <a id="__codelineno-0-592" name="__codelineno-0-592"></a> <span class="k">for</span> <span class="n">peer_id</span> <span class="ow">in</span> <span class="n">target_peer_ids</span><span class="p">:</span>
5136
- <a id="__codelineno-0-593" name="__codelineno-0-593"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
5137
- <a id="__codelineno-0-594" name="__codelineno-0-594"></a> <span class="k">if</span> <span class="n">peer_id</span> <span class="o">==</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">association</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">):</span>
5138
- <a id="__codelineno-0-595" name="__codelineno-0-595"></a> <span class="c1"># This association already exists, so we can ignore it</span>
5139
- <a id="__codelineno-0-596" name="__codelineno-0-596"></a> <span class="n">target_peer_ids</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">peer_id</span><span class="p">)</span>
5140
- <a id="__codelineno-0-597" name="__codelineno-0-597"></a> <span class="k">break</span>
5141
- <a id="__codelineno-0-598" name="__codelineno-0-598"></a> <span class="k">else</span><span class="p">:</span>
5142
- <a id="__codelineno-0-599" name="__codelineno-0-599"></a> <span class="k">if</span> <span class="n">peer_id</span> <span class="o">==</span> <span class="n">association</span><span class="o">.</span><span class="n">source_id</span> <span class="ow">or</span> <span class="n">peer_id</span> <span class="o">==</span> <span class="n">association</span><span class="o">.</span><span class="n">destination_id</span><span class="p">:</span>
5143
- <a id="__codelineno-0-600" name="__codelineno-0-600"></a> <span class="c1"># This association already exists, so we can ignore it</span>
5144
- <a id="__codelineno-0-601" name="__codelineno-0-601"></a> <span class="n">target_peer_ids</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">peer_id</span><span class="p">)</span>
5145
- <a id="__codelineno-0-602" name="__codelineno-0-602"></a> <span class="k">break</span>
5146
- <a id="__codelineno-0-603" name="__codelineno-0-603"></a> <span class="k">else</span><span class="p">:</span>
5147
- <a id="__codelineno-0-604" name="__codelineno-0-604"></a> <span class="c1"># This association is not in target_peer_ids, so delete it</span>
5148
- <a id="__codelineno-0-605" name="__codelineno-0-605"></a> <span class="n">association</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
5149
- <a id="__codelineno-0-606" name="__codelineno-0-606"></a>
5150
- <a id="__codelineno-0-607" name="__codelineno-0-607"></a> <span class="c1"># Anything remaining in target_peer_ids now does not exist yet and needs to be created.</span>
5151
- <a id="__codelineno-0-608" name="__codelineno-0-608"></a> <span class="k">for</span> <span class="n">peer_id</span> <span class="ow">in</span> <span class="n">target_peer_ids</span><span class="p">:</span>
5152
- <a id="__codelineno-0-609" name="__codelineno-0-609"></a> <span class="n">relationship</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">model</span>
5153
- <a id="__codelineno-0-610" name="__codelineno-0-610"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
5154
- <a id="__codelineno-0-611" name="__codelineno-0-611"></a> <span class="n">association</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="p">(</span>
5155
- <a id="__codelineno-0-612" name="__codelineno-0-612"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5156
- <a id="__codelineno-0-613" name="__codelineno-0-613"></a> <span class="o">**</span><span class="p">{</span>
5157
- <a id="__codelineno-0-614" name="__codelineno-0-614"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span>
5158
- <a id="__codelineno-0-615" name="__codelineno-0-615"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5159
- <a id="__codelineno-0-616" name="__codelineno-0-616"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">relationship</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">),</span>
5160
- <a id="__codelineno-0-617" name="__codelineno-0-617"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">peer_id</span><span class="p">,</span>
5161
- <a id="__codelineno-0-618" name="__codelineno-0-618"></a> <span class="p">},</span>
5162
- <a id="__codelineno-0-619" name="__codelineno-0-619"></a> <span class="p">)</span>
5163
- <a id="__codelineno-0-620" name="__codelineno-0-620"></a> <span class="k">else</span><span class="p">:</span>
5164
- <a id="__codelineno-0-621" name="__codelineno-0-621"></a> <span class="c1"># Symmetric association - source/destination are interchangeable</span>
5165
- <a id="__codelineno-0-622" name="__codelineno-0-622"></a> <span class="n">association</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="p">(</span>
5166
- <a id="__codelineno-0-623" name="__codelineno-0-623"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5167
- <a id="__codelineno-0-624" name="__codelineno-0-624"></a> <span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span>
5168
- <a id="__codelineno-0-625" name="__codelineno-0-625"></a> <span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5169
- <a id="__codelineno-0-626" name="__codelineno-0-626"></a> <span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="c1"># since this is a symmetric relationship this is OK</span>
5170
- <a id="__codelineno-0-627" name="__codelineno-0-627"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">peer_id</span><span class="p">,</span>
5171
- <a id="__codelineno-0-628" name="__codelineno-0-628"></a> <span class="p">)</span>
5172
- <a id="__codelineno-0-629" name="__codelineno-0-629"></a>
5173
- <a id="__codelineno-0-630" name="__codelineno-0-630"></a> <span class="n">association</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
5174
- <a id="__codelineno-0-631" name="__codelineno-0-631"></a> <span class="n">association</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
5175
- <a id="__codelineno-0-632" name="__codelineno-0-632"></a>
5176
- <a id="__codelineno-0-633" name="__codelineno-0-633"></a> <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
5177
- <a id="__codelineno-0-634" name="__codelineno-0-634"></a> <span class="n">obj</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">commit</span><span class="p">)</span>
5178
- <a id="__codelineno-0-635" name="__codelineno-0-635"></a> <span class="k">if</span> <span class="n">commit</span><span class="p">:</span>
5179
- <a id="__codelineno-0-636" name="__codelineno-0-636"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_save_relationships</span><span class="p">()</span>
5180
- <a id="__codelineno-0-637" name="__codelineno-0-637"></a>
5181
- <a id="__codelineno-0-638" name="__codelineno-0-638"></a> <span class="k">return</span> <span class="n">obj</span>
6322
+ <a id="__codelineno-0-586" name="__codelineno-0-586"></a> <span class="c1"># First, for each existing association, if it&#39;s one that&#39;s already in target_peer_ids,</span>
6323
+ <a id="__codelineno-0-587" name="__codelineno-0-587"></a> <span class="c1"># we can discard it from target_peer_ids (no update needed to this association).</span>
6324
+ <a id="__codelineno-0-588" name="__codelineno-0-588"></a> <span class="c1"># Conversely, if it&#39;s *not* in target_peer_ids, we should delete it.</span>
6325
+ <a id="__codelineno-0-589" name="__codelineno-0-589"></a> <span class="k">for</span> <span class="n">association</span> <span class="ow">in</span> <span class="n">existing_associations</span><span class="p">:</span>
6326
+ <a id="__codelineno-0-590" name="__codelineno-0-590"></a> <span class="k">for</span> <span class="n">peer_id</span> <span class="ow">in</span> <span class="n">target_peer_ids</span><span class="p">:</span>
6327
+ <a id="__codelineno-0-591" name="__codelineno-0-591"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">!=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span><span class="p">:</span>
6328
+ <a id="__codelineno-0-592" name="__codelineno-0-592"></a> <span class="k">if</span> <span class="n">peer_id</span> <span class="o">==</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">association</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">):</span>
6329
+ <a id="__codelineno-0-593" name="__codelineno-0-593"></a> <span class="c1"># This association already exists, so we can ignore it</span>
6330
+ <a id="__codelineno-0-594" name="__codelineno-0-594"></a> <span class="n">target_peer_ids</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">peer_id</span><span class="p">)</span>
6331
+ <a id="__codelineno-0-595" name="__codelineno-0-595"></a> <span class="k">break</span>
6332
+ <a id="__codelineno-0-596" name="__codelineno-0-596"></a> <span class="k">else</span><span class="p">:</span>
6333
+ <a id="__codelineno-0-597" name="__codelineno-0-597"></a> <span class="k">if</span> <span class="n">peer_id</span> <span class="o">==</span> <span class="n">association</span><span class="o">.</span><span class="n">source_id</span> <span class="ow">or</span> <span class="n">peer_id</span> <span class="o">==</span> <span class="n">association</span><span class="o">.</span><span class="n">destination_id</span><span class="p">:</span>
6334
+ <a id="__codelineno-0-598" name="__codelineno-0-598"></a> <span class="c1"># This association already exists, so we can ignore it</span>
6335
+ <a id="__codelineno-0-599" name="__codelineno-0-599"></a> <span class="n">target_peer_ids</span><span class="o">.</span><span class="n">remove</span><span class="p">(</span><span class="n">peer_id</span><span class="p">)</span>
6336
+ <a id="__codelineno-0-600" name="__codelineno-0-600"></a> <span class="k">break</span>
6337
+ <a id="__codelineno-0-601" name="__codelineno-0-601"></a> <span class="k">else</span><span class="p">:</span>
6338
+ <a id="__codelineno-0-602" name="__codelineno-0-602"></a> <span class="c1"># This association is not in target_peer_ids, so delete it</span>
6339
+ <a id="__codelineno-0-603" name="__codelineno-0-603"></a> <span class="n">association</span><span class="o">.</span><span class="n">delete</span><span class="p">()</span>
6340
+ <a id="__codelineno-0-604" name="__codelineno-0-604"></a>
6341
+ <a id="__codelineno-0-605" name="__codelineno-0-605"></a> <span class="c1"># Anything remaining in target_peer_ids now does not exist yet and needs to be created.</span>
6342
+ <a id="__codelineno-0-606" name="__codelineno-0-606"></a> <span class="k">for</span> <span class="n">peer_id</span> <span class="ow">in</span> <span class="n">target_peer_ids</span><span class="p">:</span>
6343
+ <a id="__codelineno-0-607" name="__codelineno-0-607"></a> <span class="n">relationship</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span><span class="o">.</span><span class="n">model</span>
6344
+ <a id="__codelineno-0-608" name="__codelineno-0-608"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
6345
+ <a id="__codelineno-0-609" name="__codelineno-0-609"></a> <span class="n">association</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="p">(</span>
6346
+ <a id="__codelineno-0-610" name="__codelineno-0-610"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
6347
+ <a id="__codelineno-0-611" name="__codelineno-0-611"></a> <span class="o">**</span><span class="p">{</span>
6348
+ <a id="__codelineno-0-612" name="__codelineno-0-612"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span>
6349
+ <a id="__codelineno-0-613" name="__codelineno-0-613"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
6350
+ <a id="__codelineno-0-614" name="__codelineno-0-614"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">:</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">relationship</span><span class="p">,</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_type&quot;</span><span class="p">),</span>
6351
+ <a id="__codelineno-0-615" name="__codelineno-0-615"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">peer_id</span><span class="p">,</span>
6352
+ <a id="__codelineno-0-616" name="__codelineno-0-616"></a> <span class="p">},</span>
6353
+ <a id="__codelineno-0-617" name="__codelineno-0-617"></a> <span class="p">)</span>
6354
+ <a id="__codelineno-0-618" name="__codelineno-0-618"></a> <span class="k">else</span><span class="p">:</span>
6355
+ <a id="__codelineno-0-619" name="__codelineno-0-619"></a> <span class="c1"># Symmetric association - source/destination are interchangeable</span>
6356
+ <a id="__codelineno-0-620" name="__codelineno-0-620"></a> <span class="n">association</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="p">(</span>
6357
+ <a id="__codelineno-0-621" name="__codelineno-0-621"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
6358
+ <a id="__codelineno-0-622" name="__codelineno-0-622"></a> <span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span>
6359
+ <a id="__codelineno-0-623" name="__codelineno-0-623"></a> <span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
6360
+ <a id="__codelineno-0-624" name="__codelineno-0-624"></a> <span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="c1"># since this is a symmetric relationship this is OK</span>
6361
+ <a id="__codelineno-0-625" name="__codelineno-0-625"></a> <span class="n">destination_id</span><span class="o">=</span><span class="n">peer_id</span><span class="p">,</span>
6362
+ <a id="__codelineno-0-626" name="__codelineno-0-626"></a> <span class="p">)</span>
6363
+ <a id="__codelineno-0-627" name="__codelineno-0-627"></a>
6364
+ <a id="__codelineno-0-628" name="__codelineno-0-628"></a> <span class="n">association</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
6365
+ <a id="__codelineno-0-629" name="__codelineno-0-629"></a> <span class="n">association</span><span class="o">.</span><span class="n">save</span><span class="p">()</span>
6366
+ <a id="__codelineno-0-630" name="__codelineno-0-630"></a>
6367
+ <a id="__codelineno-0-631" name="__codelineno-0-631"></a> <span class="k">def</span> <span class="nf">save</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">commit</span><span class="o">=</span><span class="kc">True</span><span class="p">):</span>
6368
+ <a id="__codelineno-0-632" name="__codelineno-0-632"></a> <span class="n">obj</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">commit</span><span class="p">)</span>
6369
+ <a id="__codelineno-0-633" name="__codelineno-0-633"></a> <span class="k">if</span> <span class="n">commit</span><span class="p">:</span>
6370
+ <a id="__codelineno-0-634" name="__codelineno-0-634"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_save_relationships</span><span class="p">()</span>
6371
+ <a id="__codelineno-0-635" name="__codelineno-0-635"></a>
6372
+ <a id="__codelineno-0-636" name="__codelineno-0-636"></a> <span class="k">return</span> <span class="n">obj</span>
5182
6373
  </code></pre></div></td></tr></table></div>
5183
6374
  </details>
5184
6375
 
@@ -5219,7 +6410,9 @@ Then verify that any requested RelationshipAssociations do not violate relations
5219
6410
 
5220
6411
  <details class="quote">
5221
6412
  <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
5222
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-482">482</a></span>
6413
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-480">480</a></span>
6414
+ <span class="normal"><a href="#__codelineno-0-481">481</a></span>
6415
+ <span class="normal"><a href="#__codelineno-0-482">482</a></span>
5223
6416
  <span class="normal"><a href="#__codelineno-0-483">483</a></span>
5224
6417
  <span class="normal"><a href="#__codelineno-0-484">484</a></span>
5225
6418
  <span class="normal"><a href="#__codelineno-0-485">485</a></span>
@@ -5283,75 +6476,73 @@ Then verify that any requested RelationshipAssociations do not violate relations
5283
6476
  <span class="normal"><a href="#__codelineno-0-543">543</a></span>
5284
6477
  <span class="normal"><a href="#__codelineno-0-544">544</a></span>
5285
6478
  <span class="normal"><a href="#__codelineno-0-545">545</a></span>
5286
- <span class="normal"><a href="#__codelineno-0-546">546</a></span>
5287
- <span class="normal"><a href="#__codelineno-0-547">547</a></span>
5288
- <span class="normal"><a href="#__codelineno-0-548">548</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-482" name="__codelineno-0-482"></a><span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5289
- <a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5290
- <a id="__codelineno-0-484" name="__codelineno-0-484"></a><span class="sd"> First check for any required relationships errors and if there are any, add them via form field errors.</span>
5291
- <a id="__codelineno-0-485" name="__codelineno-0-485"></a><span class="sd"> Then verify that any requested RelationshipAssociations do not violate relationship cardinality restrictions.</span>
5292
- <a id="__codelineno-0-486" name="__codelineno-0-486"></a>
5293
- <a id="__codelineno-0-487" name="__codelineno-0-487"></a><span class="sd"> - For TYPE_ONE_TO_MANY and TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;source&quot; side of</span>
5294
- <a id="__codelineno-0-488" name="__codelineno-0-488"></a><span class="sd"> the relationship, verify that the requested &quot;destination&quot; object(s) do not already have any existing</span>
5295
- <a id="__codelineno-0-489" name="__codelineno-0-489"></a><span class="sd"> RelationshipAssociation to a different source object.</span>
5296
- <a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="sd"> - For TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;destination&quot; side of the relationship,</span>
5297
- <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="sd"> verify that the requested &quot;source&quot; object does not have an existing RelationshipAssociation to</span>
5298
- <a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> a different destination object.</span>
5299
- <a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> &quot;&quot;&quot;</span>
5300
- <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="n">required_relationships_errors</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Meta</span><span class="p">()</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">required_related_objects_errors</span><span class="p">(</span>
5301
- <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="n">output_for</span><span class="o">=</span><span class="s2">&quot;ui&quot;</span><span class="p">,</span> <span class="n">initial_data</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">,</span> <span class="n">instance</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span>
5302
- <a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="p">)</span>
5303
- <a id="__codelineno-0-497" name="__codelineno-0-497"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">errors</span> <span class="ow">in</span> <span class="n">required_relationships_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5304
- <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span>
5305
- <a id="__codelineno-0-499" name="__codelineno-0-499"></a>
5306
- <a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
5307
- <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
5308
- <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="c1"># The form field name reflects what it provides, i.e. the peer object(s) to link via this relationship.</span>
5309
- <a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
5310
- <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">slug</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
5311
- <a id="__codelineno-0-505" name="__codelineno-0-505"></a>
5312
- <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="c1"># Is the form trying to set this field (create/update a RelationshipAssociation(s))?</span>
5313
- <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="c1"># If not (that is, clearing the field / deleting RelationshipAssociation(s)), we don&#39;t need to check.</span>
5314
- <a id="__codelineno-0-508" name="__codelineno-0-508"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]:</span>
5315
- <a id="__codelineno-0-509" name="__codelineno-0-509"></a> <span class="k">continue</span>
5316
- <a id="__codelineno-0-510" name="__codelineno-0-510"></a>
5317
- <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="c1"># Are any of the objects we want a relationship with already entangled with another object?</span>
5318
- <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
5319
- <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">])</span>
5320
- <a id="__codelineno-0-514" name="__codelineno-0-514"></a> <span class="k">else</span><span class="p">:</span>
5321
- <a id="__codelineno-0-515" name="__codelineno-0-515"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]]</span>
5322
- <a id="__codelineno-0-516" name="__codelineno-0-516"></a>
5323
- <a id="__codelineno-0-517" name="__codelineno-0-517"></a> <span class="k">for</span> <span class="n">target_peer</span> <span class="ow">in</span> <span class="n">target_peers</span><span class="p">:</span>
5324
- <a id="__codelineno-0-518" name="__codelineno-0-518"></a> <span class="k">if</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">:</span>
5325
- <a id="__codelineno-0-519" name="__codelineno-0-519"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
5326
- <a id="__codelineno-0-520" name="__codelineno-0-520"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;Object </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="si">}</span><span class="s2"> cannot form a relationship to itself!&quot;</span><span class="p">}</span>
5327
- <a id="__codelineno-0-521" name="__codelineno-0-521"></a> <span class="p">)</span>
5328
- <a id="__codelineno-0-522" name="__codelineno-0-522"></a>
5329
- <a id="__codelineno-0-523" name="__codelineno-0-523"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">side</span><span class="p">):</span>
5330
- <a id="__codelineno-0-524" name="__codelineno-0-524"></a> <span class="c1"># No need to check for existing RelationshipAssociations since this is a &quot;many&quot; relationship</span>
5331
- <a id="__codelineno-0-525" name="__codelineno-0-525"></a> <span class="k">continue</span>
5332
- <a id="__codelineno-0-526" name="__codelineno-0-526"></a>
5333
- <a id="__codelineno-0-527" name="__codelineno-0-527"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
5334
- <a id="__codelineno-0-528" name="__codelineno-0-528"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5335
- <a id="__codelineno-0-529" name="__codelineno-0-529"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5336
- <a id="__codelineno-0-530" name="__codelineno-0-530"></a> <span class="o">**</span><span class="p">{</span>
5337
- <a id="__codelineno-0-531" name="__codelineno-0-531"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
5338
- <a id="__codelineno-0-532" name="__codelineno-0-532"></a> <span class="p">},</span>
5339
- <a id="__codelineno-0-533" name="__codelineno-0-533"></a> <span class="p">)</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>
5340
- <a id="__codelineno-0-534" name="__codelineno-0-534"></a> <span class="k">else</span><span class="p">:</span>
5341
- <a id="__codelineno-0-535" name="__codelineno-0-535"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5342
- <a id="__codelineno-0-536" name="__codelineno-0-536"></a> <span class="p">(</span>
5343
- <a id="__codelineno-0-537" name="__codelineno-0-537"></a> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
5344
- <a id="__codelineno-0-538" name="__codelineno-0-538"></a> <span class="o">|</span> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
5345
- <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="p">),</span>
5346
- <a id="__codelineno-0-540" name="__codelineno-0-540"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5347
- <a id="__codelineno-0-541" name="__codelineno-0-541"></a> <span class="p">)</span>
5348
- <a id="__codelineno-0-542" name="__codelineno-0-542"></a>
5349
- <a id="__codelineno-0-543" name="__codelineno-0-543"></a> <span class="k">if</span> <span class="n">existing_peer_associations</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
5350
- <a id="__codelineno-0-544" name="__codelineno-0-544"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
5351
- <a id="__codelineno-0-545" name="__codelineno-0-545"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">target_peer</span><span class="si">}</span><span class="s2"> is already involved in a </span><span class="si">{</span><span class="n">relationship</span><span class="si">}</span><span class="s2"> relationship&quot;</span><span class="p">}</span>
5352
- <a id="__codelineno-0-546" name="__codelineno-0-546"></a> <span class="p">)</span>
5353
- <a id="__codelineno-0-547" name="__codelineno-0-547"></a>
5354
- <a id="__codelineno-0-548" name="__codelineno-0-548"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
6479
+ <span class="normal"><a href="#__codelineno-0-546">546</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-480" name="__codelineno-0-480"></a><span class="k">def</span> <span class="nf">clean</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
6480
+ <a id="__codelineno-0-481" name="__codelineno-0-481"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6481
+ <a id="__codelineno-0-482" name="__codelineno-0-482"></a><span class="sd"> First check for any required relationships errors and if there are any, add them via form field errors.</span>
6482
+ <a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="sd"> Then verify that any requested RelationshipAssociations do not violate relationship cardinality restrictions.</span>
6483
+ <a id="__codelineno-0-484" name="__codelineno-0-484"></a>
6484
+ <a id="__codelineno-0-485" name="__codelineno-0-485"></a><span class="sd"> - For TYPE_ONE_TO_MANY and TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;source&quot; side of</span>
6485
+ <a id="__codelineno-0-486" name="__codelineno-0-486"></a><span class="sd"> the relationship, verify that the requested &quot;destination&quot; object(s) do not already have any existing</span>
6486
+ <a id="__codelineno-0-487" name="__codelineno-0-487"></a><span class="sd"> RelationshipAssociation to a different source object.</span>
6487
+ <a id="__codelineno-0-488" name="__codelineno-0-488"></a><span class="sd"> - For TYPE_ONE_TO_ONE relations, if the form&#39;s object is on the &quot;destination&quot; side of the relationship,</span>
6488
+ <a id="__codelineno-0-489" name="__codelineno-0-489"></a><span class="sd"> verify that the requested &quot;source&quot; object does not have an existing RelationshipAssociation to</span>
6489
+ <a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="sd"> a different destination object.</span>
6490
+ <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="sd"> &quot;&quot;&quot;</span>
6491
+ <a id="__codelineno-0-492" name="__codelineno-0-492"></a> <span class="n">required_relationships_errors</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">Meta</span><span class="p">()</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">required_related_objects_errors</span><span class="p">(</span>
6492
+ <a id="__codelineno-0-493" name="__codelineno-0-493"></a> <span class="n">output_for</span><span class="o">=</span><span class="s2">&quot;ui&quot;</span><span class="p">,</span> <span class="n">initial_data</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">,</span> <span class="n">instance</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span>
6493
+ <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="p">)</span>
6494
+ <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="k">for</span> <span class="n">field</span><span class="p">,</span> <span class="n">errors</span> <span class="ow">in</span> <span class="n">required_relationships_errors</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
6495
+ <a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="bp">self</span><span class="o">.</span><span class="n">add_error</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">errors</span><span class="p">)</span>
6496
+ <a id="__codelineno-0-497" name="__codelineno-0-497"></a>
6497
+ <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="k">for</span> <span class="n">side</span><span class="p">,</span> <span class="n">relationships</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">get_relationships</span><span class="p">()</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
6498
+ <a id="__codelineno-0-499" name="__codelineno-0-499"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
6499
+ <a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="c1"># The form field name reflects what it provides, i.e. the peer object(s) to link via this relationship.</span>
6500
+ <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
6501
+ <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;cr_</span><span class="si">{</span><span class="n">relationship</span><span class="o">.</span><span class="n">key</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">&quot;</span>
6502
+ <a id="__codelineno-0-503" name="__codelineno-0-503"></a>
6503
+ <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="c1"># Is the form trying to set this field (create/update a RelationshipAssociation(s))?</span>
6504
+ <a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="c1"># If not (that is, clearing the field / deleting RelationshipAssociation(s)), we don&#39;t need to check.</span>
6505
+ <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span> <span class="ow">or</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]:</span>
6506
+ <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="k">continue</span>
6507
+ <a id="__codelineno-0-508" name="__codelineno-0-508"></a>
6508
+ <a id="__codelineno-0-509" name="__codelineno-0-509"></a> <span class="c1"># Are any of the objects we want a relationship with already entangled with another object?</span>
6509
+ <a id="__codelineno-0-510" name="__codelineno-0-510"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">peer_side</span><span class="p">):</span>
6510
+ <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">])</span>
6511
+ <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="k">else</span><span class="p">:</span>
6512
+ <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="n">target_peers</span> <span class="o">=</span> <span class="p">[</span><span class="bp">self</span><span class="o">.</span><span class="n">cleaned_data</span><span class="p">[</span><span class="n">field_name</span><span class="p">]]</span>
6513
+ <a id="__codelineno-0-514" name="__codelineno-0-514"></a>
6514
+ <a id="__codelineno-0-515" name="__codelineno-0-515"></a> <span class="k">for</span> <span class="n">target_peer</span> <span class="ow">in</span> <span class="n">target_peers</span><span class="p">:</span>
6515
+ <a id="__codelineno-0-516" name="__codelineno-0-516"></a> <span class="k">if</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">:</span>
6516
+ <a id="__codelineno-0-517" name="__codelineno-0-517"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
6517
+ <a id="__codelineno-0-518" name="__codelineno-0-518"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;Object </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="si">}</span><span class="s2"> cannot form a relationship to itself!&quot;</span><span class="p">}</span>
6518
+ <a id="__codelineno-0-519" name="__codelineno-0-519"></a> <span class="p">)</span>
6519
+ <a id="__codelineno-0-520" name="__codelineno-0-520"></a>
6520
+ <a id="__codelineno-0-521" name="__codelineno-0-521"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">has_many</span><span class="p">(</span><span class="n">side</span><span class="p">):</span>
6521
+ <a id="__codelineno-0-522" name="__codelineno-0-522"></a> <span class="c1"># No need to check for existing RelationshipAssociations since this is a &quot;many&quot; relationship</span>
6522
+ <a id="__codelineno-0-523" name="__codelineno-0-523"></a> <span class="k">continue</span>
6523
+ <a id="__codelineno-0-524" name="__codelineno-0-524"></a>
6524
+ <a id="__codelineno-0-525" name="__codelineno-0-525"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
6525
+ <a id="__codelineno-0-526" name="__codelineno-0-526"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
6526
+ <a id="__codelineno-0-527" name="__codelineno-0-527"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
6527
+ <a id="__codelineno-0-528" name="__codelineno-0-528"></a> <span class="o">**</span><span class="p">{</span>
6528
+ <a id="__codelineno-0-529" name="__codelineno-0-529"></a> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">peer_side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">,</span>
6529
+ <a id="__codelineno-0-530" name="__codelineno-0-530"></a> <span class="p">},</span>
6530
+ <a id="__codelineno-0-531" name="__codelineno-0-531"></a> <span class="p">)</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="o">**</span><span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">side</span><span class="si">}</span><span class="s2">_id&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">})</span>
6531
+ <a id="__codelineno-0-532" name="__codelineno-0-532"></a> <span class="k">else</span><span class="p">:</span>
6532
+ <a id="__codelineno-0-533" name="__codelineno-0-533"></a> <span class="n">existing_peer_associations</span> <span class="o">=</span> <span class="n">RelationshipAssociation</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
6533
+ <a id="__codelineno-0-534" name="__codelineno-0-534"></a> <span class="p">(</span>
6534
+ <a id="__codelineno-0-535" name="__codelineno-0-535"></a> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
6535
+ <a id="__codelineno-0-536" name="__codelineno-0-536"></a> <span class="o">|</span> <span class="p">(</span><span class="n">Q</span><span class="p">(</span><span class="n">destination_id</span><span class="o">=</span><span class="n">target_peer</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span> <span class="o">&amp;</span> <span class="o">~</span><span class="n">Q</span><span class="p">(</span><span class="n">source_id</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">instance</span><span class="o">.</span><span class="n">pk</span><span class="p">))</span>
6536
+ <a id="__codelineno-0-537" name="__codelineno-0-537"></a> <span class="p">),</span>
6537
+ <a id="__codelineno-0-538" name="__codelineno-0-538"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
6538
+ <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="p">)</span>
6539
+ <a id="__codelineno-0-540" name="__codelineno-0-540"></a>
6540
+ <a id="__codelineno-0-541" name="__codelineno-0-541"></a> <span class="k">if</span> <span class="n">existing_peer_associations</span><span class="o">.</span><span class="n">exists</span><span class="p">():</span>
6541
+ <a id="__codelineno-0-542" name="__codelineno-0-542"></a> <span class="k">raise</span> <span class="n">ValidationError</span><span class="p">(</span>
6542
+ <a id="__codelineno-0-543" name="__codelineno-0-543"></a> <span class="p">{</span><span class="n">field_name</span><span class="p">:</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">target_peer</span><span class="si">}</span><span class="s2"> is already involved in a </span><span class="si">{</span><span class="n">relationship</span><span class="si">}</span><span class="s2"> relationship&quot;</span><span class="p">}</span>
6543
+ <a id="__codelineno-0-544" name="__codelineno-0-544"></a> <span class="p">)</span>
6544
+ <a id="__codelineno-0-545" name="__codelineno-0-545"></a>
6545
+ <a id="__codelineno-0-546" name="__codelineno-0-546"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">clean</span><span class="p">()</span>
5355
6546
  </code></pre></div></td></tr></table></div>
5356
6547
  </details>
5357
6548
  </div>
@@ -5387,86 +6578,27 @@ Then verify that any requested RelationshipAssociations do not violate relations
5387
6578
 
5388
6579
  <details class="quote">
5389
6580
  <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
5390
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-739">739</a></span>
5391
- <span class="normal"><a href="#__codelineno-0-740">740</a></span>
5392
- <span class="normal"><a href="#__codelineno-0-741">741</a></span>
5393
- <span class="normal"><a href="#__codelineno-0-742">742</a></span>
5394
- <span class="normal"><a href="#__codelineno-0-743">743</a></span>
5395
- <span class="normal"><a href="#__codelineno-0-744">744</a></span>
5396
- <span class="normal"><a href="#__codelineno-0-745">745</a></span>
5397
- <span class="normal"><a href="#__codelineno-0-746">746</a></span>
5398
- <span class="normal"><a href="#__codelineno-0-747">747</a></span>
5399
- <span class="normal"><a href="#__codelineno-0-748">748</a></span>
5400
- <span class="normal"><a href="#__codelineno-0-749">749</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-739" name="__codelineno-0-739"></a><span class="k">class</span> <span class="nc">StatusModelBulkEditFormMixin</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
5401
- <a id="__codelineno-0-740" name="__codelineno-0-740"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Mixin to add non-required `status` choice field to forms.&quot;&quot;&quot;</span>
5402
- <a id="__codelineno-0-741" name="__codelineno-0-741"></a>
5403
- <a id="__codelineno-0-742" name="__codelineno-0-742"></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>
5404
- <a id="__codelineno-0-743" name="__codelineno-0-743"></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>
5405
- <a id="__codelineno-0-744" name="__codelineno-0-744"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">DynamicModelChoiceField</span><span class="p">(</span>
5406
- <a id="__codelineno-0-745" name="__codelineno-0-745"></a> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
5407
- <a id="__codelineno-0-746" name="__codelineno-0-746"></a> <span class="n">queryset</span><span class="o">=</span><span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
5408
- <a id="__codelineno-0-747" name="__codelineno-0-747"></a> <span class="n">query_params</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;content_types&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">label_lower</span><span class="p">},</span>
5409
- <a id="__codelineno-0-748" name="__codelineno-0-748"></a> <span class="p">)</span>
5410
- <a id="__codelineno-0-749" name="__codelineno-0-749"></a> <span class="bp">self</span><span class="o">.</span><span class="n">order_fields</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">field_order</span><span class="p">)</span> <span class="c1"># Reorder fields again</span>
5411
- </code></pre></div></td></tr></table></div>
5412
- </details>
5413
-
5414
-
5415
-
5416
- <div class="doc doc-children">
5417
-
5418
-
5419
-
5420
-
5421
-
5422
-
5423
-
5424
-
5425
-
5426
-
5427
-
5428
- </div>
5429
-
5430
- </div>
5431
-
5432
- </div>
5433
-
5434
- <div class="doc doc-object doc-class">
5435
-
5436
-
5437
-
5438
- <h2 id="nautobot.apps.forms.StatusModelCSVFormMixin" class="doc doc-heading">
5439
- <code>nautobot.apps.forms.StatusModelCSVFormMixin</code>
5440
-
5441
-
5442
- <a href="#nautobot.apps.forms.StatusModelCSVFormMixin" class="headerlink" title="Permanent link">&para;</a></h2>
5443
-
5444
-
5445
- <div class="doc doc-contents ">
5446
- <p class="doc doc-class-bases">
5447
- Bases: <code><a class="autorefs autorefs-internal" title="nautobot.core.forms.CSVModelForm" href="#nautobot.apps.forms.CSVModelForm">CSVModelForm</a></code></p>
5448
-
5449
-
5450
- <p>Mixin to add a required <code>status</code> choice field to CSV import forms.</p>
5451
-
5452
-
5453
- <details class="quote">
5454
- <summary>Source code in <code>nautobot/extras/forms/mixins.py</code></summary>
5455
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-768">768</a></span>
5456
- <span class="normal"><a href="#__codelineno-0-769">769</a></span>
5457
- <span class="normal"><a href="#__codelineno-0-770">770</a></span>
5458
- <span class="normal"><a href="#__codelineno-0-771">771</a></span>
5459
- <span class="normal"><a href="#__codelineno-0-772">772</a></span>
5460
- <span class="normal"><a href="#__codelineno-0-773">773</a></span>
5461
- <span class="normal"><a href="#__codelineno-0-774">774</a></span>
5462
- <span class="normal"><a href="#__codelineno-0-775">775</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-768" name="__codelineno-0-768"></a><span class="k">class</span> <span class="nc">StatusModelCSVFormMixin</span><span class="p">(</span><span class="n">CSVModelForm</span><span class="p">):</span>
5463
- <a id="__codelineno-0-769" name="__codelineno-0-769"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Mixin to add a required `status` choice field to CSV import forms.&quot;&quot;&quot;</span>
5464
- <a id="__codelineno-0-770" name="__codelineno-0-770"></a>
5465
- <a id="__codelineno-0-771" name="__codelineno-0-771"></a> <span class="n">status</span> <span class="o">=</span> <span class="n">CSVModelChoiceField</span><span class="p">(</span>
5466
- <a id="__codelineno-0-772" name="__codelineno-0-772"></a> <span class="n">queryset</span><span class="o">=</span><span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
5467
- <a id="__codelineno-0-773" name="__codelineno-0-773"></a> <span class="n">to_field_name</span><span class="o">=</span><span class="s2">&quot;name&quot;</span><span class="p">,</span>
5468
- <a id="__codelineno-0-774" name="__codelineno-0-774"></a> <span class="n">help_text</span><span class="o">=</span><span class="s2">&quot;Operational status&quot;</span><span class="p">,</span>
5469
- <a id="__codelineno-0-775" name="__codelineno-0-775"></a> <span class="p">)</span>
6581
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-721">721</a></span>
6582
+ <span class="normal"><a href="#__codelineno-0-722">722</a></span>
6583
+ <span class="normal"><a href="#__codelineno-0-723">723</a></span>
6584
+ <span class="normal"><a href="#__codelineno-0-724">724</a></span>
6585
+ <span class="normal"><a href="#__codelineno-0-725">725</a></span>
6586
+ <span class="normal"><a href="#__codelineno-0-726">726</a></span>
6587
+ <span class="normal"><a href="#__codelineno-0-727">727</a></span>
6588
+ <span class="normal"><a href="#__codelineno-0-728">728</a></span>
6589
+ <span class="normal"><a href="#__codelineno-0-729">729</a></span>
6590
+ <span class="normal"><a href="#__codelineno-0-730">730</a></span>
6591
+ <span class="normal"><a href="#__codelineno-0-731">731</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-721" name="__codelineno-0-721"></a><span class="k">class</span> <span class="nc">StatusModelBulkEditFormMixin</span><span class="p">(</span><span class="n">forms</span><span class="o">.</span><span class="n">Form</span><span class="p">):</span>
6592
+ <a id="__codelineno-0-722" name="__codelineno-0-722"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Mixin to add non-required `status` choice field to forms.&quot;&quot;&quot;</span>
6593
+ <a id="__codelineno-0-723" name="__codelineno-0-723"></a>
6594
+ <a id="__codelineno-0-724" name="__codelineno-0-724"></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>
6595
+ <a id="__codelineno-0-725" name="__codelineno-0-725"></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>
6596
+ <a id="__codelineno-0-726" name="__codelineno-0-726"></a> <span class="bp">self</span><span class="o">.</span><span class="n">fields</span><span class="p">[</span><span class="s2">&quot;status&quot;</span><span class="p">]</span> <span class="o">=</span> <span class="n">DynamicModelChoiceField</span><span class="p">(</span>
6597
+ <a id="__codelineno-0-727" name="__codelineno-0-727"></a> <span class="n">required</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span>
6598
+ <a id="__codelineno-0-728" name="__codelineno-0-728"></a> <span class="n">queryset</span><span class="o">=</span><span class="n">Status</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
6599
+ <a id="__codelineno-0-729" name="__codelineno-0-729"></a> <span class="n">query_params</span><span class="o">=</span><span class="p">{</span><span class="s2">&quot;content_types&quot;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">model</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">label_lower</span><span class="p">},</span>
6600
+ <a id="__codelineno-0-730" name="__codelineno-0-730"></a> <span class="p">)</span>
6601
+ <a id="__codelineno-0-731" name="__codelineno-0-731"></a> <span class="bp">self</span><span class="o">.</span><span class="n">order_fields</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">field_order</span><span class="p">)</span> <span class="c1"># Reorder fields again</span>
5470
6602
  </code></pre></div></td></tr></table></div>
5471
6603
  </details>
5472
6604
 
@@ -5512,37 +6644,37 @@ Then verify that any requested RelationshipAssociations do not violate relations
5512
6644
 
5513
6645
  <details class="quote">
5514
6646
  <summary>Source code in <code>nautobot/core/forms/fields.py</code></summary>
5515
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-460">460</a></span>
5516
- <span class="normal"><a href="#__codelineno-0-461">461</a></span>
5517
- <span class="normal"><a href="#__codelineno-0-462">462</a></span>
5518
- <span class="normal"><a href="#__codelineno-0-463">463</a></span>
5519
- <span class="normal"><a href="#__codelineno-0-464">464</a></span>
5520
- <span class="normal"><a href="#__codelineno-0-465">465</a></span>
5521
- <span class="normal"><a href="#__codelineno-0-466">466</a></span>
5522
- <span class="normal"><a href="#__codelineno-0-467">467</a></span>
5523
- <span class="normal"><a href="#__codelineno-0-468">468</a></span>
5524
- <span class="normal"><a href="#__codelineno-0-469">469</a></span>
5525
- <span class="normal"><a href="#__codelineno-0-470">470</a></span>
5526
- <span class="normal"><a href="#__codelineno-0-471">471</a></span>
5527
- <span class="normal"><a href="#__codelineno-0-472">472</a></span>
5528
- <span class="normal"><a href="#__codelineno-0-473">473</a></span>
5529
- <span class="normal"><a href="#__codelineno-0-474">474</a></span>
5530
- <span class="normal"><a href="#__codelineno-0-475">475</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-460" name="__codelineno-0-460"></a><span class="k">class</span> <span class="nc">TagFilterField</span><span class="p">(</span><span class="n">django_forms</span><span class="o">.</span><span class="n">MultipleChoiceField</span><span class="p">):</span>
5531
- <a id="__codelineno-0-461" name="__codelineno-0-461"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5532
- <a id="__codelineno-0-462" name="__codelineno-0-462"></a><span class="sd"> A filter field for the tags of a model. Only the tags used by a model are displayed.</span>
5533
- <a id="__codelineno-0-463" name="__codelineno-0-463"></a>
5534
- <a id="__codelineno-0-464" name="__codelineno-0-464"></a><span class="sd"> :param model: The model of the filter</span>
5535
- <a id="__codelineno-0-465" name="__codelineno-0-465"></a><span class="sd"> &quot;&quot;&quot;</span>
5536
- <a id="__codelineno-0-466" name="__codelineno-0-466"></a>
5537
- <a id="__codelineno-0-467" name="__codelineno-0-467"></a> <span class="n">widget</span> <span class="o">=</span> <span class="n">widgets</span><span class="o">.</span><span class="n">StaticSelect2Multiple</span>
5538
- <a id="__codelineno-0-468" name="__codelineno-0-468"></a>
5539
- <a id="__codelineno-0-469" name="__codelineno-0-469"></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">model</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>
5540
- <a id="__codelineno-0-470" name="__codelineno-0-470"></a> <span class="k">def</span> <span class="nf">get_choices</span><span class="p">():</span>
5541
- <a id="__codelineno-0-471" name="__codelineno-0-471"></a> <span class="n">tags</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="n">count</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s2">&quot;extras_taggeditem_items&quot;</span><span class="p">))</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span>
5542
- <a id="__codelineno-0-472" name="__codelineno-0-472"></a> <span class="k">return</span> <span class="p">[(</span><span class="nb">str</span><span class="p">(</span><span class="n">tag</span><span class="o">.</span><span class="n">slug</span><span class="p">),</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">tag</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">tag</span><span class="o">.</span><span class="n">count</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">tag</span> <span class="ow">in</span> <span class="n">tags</span><span class="p">]</span>
5543
- <a id="__codelineno-0-473" name="__codelineno-0-473"></a>
5544
- <a id="__codelineno-0-474" name="__codelineno-0-474"></a> <span class="c1"># Choices are fetched each time the form is initialized</span>
5545
- <a id="__codelineno-0-475" name="__codelineno-0-475"></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="n">label</span><span class="o">=</span><span class="s2">&quot;Tags&quot;</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="n">get_choices</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</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>
6647
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-434">434</a></span>
6648
+ <span class="normal"><a href="#__codelineno-0-435">435</a></span>
6649
+ <span class="normal"><a href="#__codelineno-0-436">436</a></span>
6650
+ <span class="normal"><a href="#__codelineno-0-437">437</a></span>
6651
+ <span class="normal"><a href="#__codelineno-0-438">438</a></span>
6652
+ <span class="normal"><a href="#__codelineno-0-439">439</a></span>
6653
+ <span class="normal"><a href="#__codelineno-0-440">440</a></span>
6654
+ <span class="normal"><a href="#__codelineno-0-441">441</a></span>
6655
+ <span class="normal"><a href="#__codelineno-0-442">442</a></span>
6656
+ <span class="normal"><a href="#__codelineno-0-443">443</a></span>
6657
+ <span class="normal"><a href="#__codelineno-0-444">444</a></span>
6658
+ <span class="normal"><a href="#__codelineno-0-445">445</a></span>
6659
+ <span class="normal"><a href="#__codelineno-0-446">446</a></span>
6660
+ <span class="normal"><a href="#__codelineno-0-447">447</a></span>
6661
+ <span class="normal"><a href="#__codelineno-0-448">448</a></span>
6662
+ <span class="normal"><a href="#__codelineno-0-449">449</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-434" name="__codelineno-0-434"></a><span class="k">class</span> <span class="nc">TagFilterField</span><span class="p">(</span><span class="n">django_forms</span><span class="o">.</span><span class="n">MultipleChoiceField</span><span class="p">):</span>
6663
+ <a id="__codelineno-0-435" name="__codelineno-0-435"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6664
+ <a id="__codelineno-0-436" name="__codelineno-0-436"></a><span class="sd"> A filter field for the tags of a model. Only the tags used by a model are displayed.</span>
6665
+ <a id="__codelineno-0-437" name="__codelineno-0-437"></a>
6666
+ <a id="__codelineno-0-438" name="__codelineno-0-438"></a><span class="sd"> :param model: The model of the filter</span>
6667
+ <a id="__codelineno-0-439" name="__codelineno-0-439"></a><span class="sd"> &quot;&quot;&quot;</span>
6668
+ <a id="__codelineno-0-440" name="__codelineno-0-440"></a>
6669
+ <a id="__codelineno-0-441" name="__codelineno-0-441"></a> <span class="n">widget</span> <span class="o">=</span> <span class="n">widgets</span><span class="o">.</span><span class="n">StaticSelect2Multiple</span>
6670
+ <a id="__codelineno-0-442" name="__codelineno-0-442"></a>
6671
+ <a id="__codelineno-0-443" name="__codelineno-0-443"></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">model</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>
6672
+ <a id="__codelineno-0-444" name="__codelineno-0-444"></a> <span class="k">def</span> <span class="nf">get_choices</span><span class="p">():</span>
6673
+ <a id="__codelineno-0-445" name="__codelineno-0-445"></a> <span class="n">tags</span> <span class="o">=</span> <span class="n">model</span><span class="o">.</span><span class="n">tags</span><span class="o">.</span><span class="n">annotate</span><span class="p">(</span><span class="n">count</span><span class="o">=</span><span class="n">Count</span><span class="p">(</span><span class="s2">&quot;extras_taggeditem_items&quot;</span><span class="p">))</span><span class="o">.</span><span class="n">order_by</span><span class="p">(</span><span class="s2">&quot;name&quot;</span><span class="p">)</span>
6674
+ <a id="__codelineno-0-446" name="__codelineno-0-446"></a> <span class="k">return</span> <span class="p">[(</span><span class="nb">str</span><span class="p">(</span><span class="n">tag</span><span class="o">.</span><span class="n">slug</span><span class="p">),</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">tag</span><span class="o">.</span><span class="n">name</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">tag</span><span class="o">.</span><span class="n">count</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">)</span> <span class="k">for</span> <span class="n">tag</span> <span class="ow">in</span> <span class="n">tags</span><span class="p">]</span>
6675
+ <a id="__codelineno-0-447" name="__codelineno-0-447"></a>
6676
+ <a id="__codelineno-0-448" name="__codelineno-0-448"></a> <span class="c1"># Choices are fetched each time the form is initialized</span>
6677
+ <a id="__codelineno-0-449" name="__codelineno-0-449"></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="n">label</span><span class="o">=</span><span class="s2">&quot;Tags&quot;</span><span class="p">,</span> <span class="n">choices</span><span class="o">=</span><span class="n">get_choices</span><span class="p">,</span> <span class="n">required</span><span class="o">=</span><span class="kc">False</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>
5546
6678
  </code></pre></div></td></tr></table></div>
5547
6679
  </details>
5548
6680
 
@@ -5644,15 +6776,15 @@ Then verify that any requested RelationshipAssociations do not violate relations
5644
6776
 
5645
6777
  <details class="quote">
5646
6778
  <summary>Source code in <code>nautobot/core/forms/utils.py</code></summary>
5647
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-112">112</a></span>
6779
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-110">110</a></span>
6780
+ <span class="normal"><a href="#__codelineno-0-111">111</a></span>
6781
+ <span class="normal"><a href="#__codelineno-0-112">112</a></span>
5648
6782
  <span class="normal"><a href="#__codelineno-0-113">113</a></span>
5649
- <span class="normal"><a href="#__codelineno-0-114">114</a></span>
5650
- <span class="normal"><a href="#__codelineno-0-115">115</a></span>
5651
- <span class="normal"><a href="#__codelineno-0-116">116</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-112" name="__codelineno-0-112"></a><span class="k">def</span> <span class="nf">add_blank_choice</span><span class="p">(</span><span class="n">choices</span><span class="p">):</span>
5652
- <a id="__codelineno-0-113" name="__codelineno-0-113"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5653
- <a id="__codelineno-0-114" name="__codelineno-0-114"></a><span class="sd"> Add a blank choice to the beginning of a choices list.</span>
5654
- <a id="__codelineno-0-115" name="__codelineno-0-115"></a><span class="sd"> &quot;&quot;&quot;</span>
5655
- <a id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="k">return</span> <span class="p">((</span><span class="kc">None</span><span class="p">,</span> <span class="s2">&quot;---------&quot;</span><span class="p">),)</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">choices</span><span class="p">)</span>
6783
+ <span class="normal"><a href="#__codelineno-0-114">114</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-110" name="__codelineno-0-110"></a><span class="k">def</span> <span class="nf">add_blank_choice</span><span class="p">(</span><span class="n">choices</span><span class="p">):</span>
6784
+ <a id="__codelineno-0-111" name="__codelineno-0-111"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6785
+ <a id="__codelineno-0-112" name="__codelineno-0-112"></a><span class="sd"> Add a blank choice to the beginning of a choices list.</span>
6786
+ <a id="__codelineno-0-113" name="__codelineno-0-113"></a><span class="sd"> &quot;&quot;&quot;</span>
6787
+ <a id="__codelineno-0-114" name="__codelineno-0-114"></a> <span class="k">return</span> <span class="p">((</span><span class="kc">None</span><span class="p">,</span> <span class="s2">&quot;---------&quot;</span><span class="p">),)</span> <span class="o">+</span> <span class="nb">tuple</span><span class="p">(</span><span class="n">choices</span><span class="p">)</span>
5656
6788
  </code></pre></div></td></tr></table></div>
5657
6789
  </details>
5658
6790
  </div>