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>
@@ -3141,7 +4309,8 @@
3141
4309
 
3142
4310
  <details class="quote">
3143
4311
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3144
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-532">532</a></span>
4312
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-531">531</a></span>
4313
+ <span class="normal"><a href="#__codelineno-0-532">532</a></span>
3145
4314
  <span class="normal"><a href="#__codelineno-0-533">533</a></span>
3146
4315
  <span class="normal"><a href="#__codelineno-0-534">534</a></span>
3147
4316
  <span class="normal"><a href="#__codelineno-0-535">535</a></span>
@@ -3366,234 +4535,233 @@
3366
4535
  <span class="normal"><a href="#__codelineno-0-754">754</a></span>
3367
4536
  <span class="normal"><a href="#__codelineno-0-755">755</a></span>
3368
4537
  <span class="normal"><a href="#__codelineno-0-756">756</a></span>
3369
- <span class="normal"><a href="#__codelineno-0-757">757</a></span>
3370
- <span class="normal"><a href="#__codelineno-0-758">758</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-532" name="__codelineno-0-532"></a><span class="k">class</span> <span class="nc">BaseFilterSet</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
3371
- <a id="__codelineno-0-533" name="__codelineno-0-533"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3372
- <a id="__codelineno-0-534" name="__codelineno-0-534"></a><span class="sd"> A base filterset which provides common functionality to all Nautobot filtersets.</span>
3373
- <a id="__codelineno-0-535" name="__codelineno-0-535"></a><span class="sd"> &quot;&quot;&quot;</span>
3374
- <a id="__codelineno-0-536" name="__codelineno-0-536"></a>
3375
- <a id="__codelineno-0-537" name="__codelineno-0-537"></a> <span class="n">FILTER_DEFAULTS</span> <span class="o">=</span> <span class="n">deepcopy</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">filterset</span><span class="o">.</span><span class="n">FILTER_FOR_DBFIELD_DEFAULTS</span><span class="p">)</span>
3376
- <a id="__codelineno-0-538" name="__codelineno-0-538"></a> <span class="n">FILTER_DEFAULTS</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
3377
- <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="p">{</span>
3378
- <a id="__codelineno-0-540" name="__codelineno-0-540"></a> <span class="n">models</span><span class="o">.</span><span class="n">AutoField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
3379
- <a id="__codelineno-0-541" name="__codelineno-0-541"></a> <span class="n">models</span><span class="o">.</span><span class="n">BigIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueBigNumberFilter</span><span class="p">},</span>
3380
- <a id="__codelineno-0-542" name="__codelineno-0-542"></a> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
3381
- <a id="__codelineno-0-543" name="__codelineno-0-543"></a> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueDateFilter</span><span class="p">},</span>
3382
- <a id="__codelineno-0-544" name="__codelineno-0-544"></a> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueDateTimeFilter</span><span class="p">},</span>
3383
- <a id="__codelineno-0-545" name="__codelineno-0-545"></a> <span class="n">models</span><span class="o">.</span><span class="n">DecimalField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueDecimalFilter</span><span class="p">},</span>
3384
- <a id="__codelineno-0-546" name="__codelineno-0-546"></a> <span class="n">models</span><span class="o">.</span><span class="n">EmailField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
3385
- <a id="__codelineno-0-547" name="__codelineno-0-547"></a> <span class="n">models</span><span class="o">.</span><span class="n">FloatField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueFloatFilter</span><span class="p">},</span>
3386
- <a id="__codelineno-0-548" name="__codelineno-0-548"></a> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
3387
- <a id="__codelineno-0-549" name="__codelineno-0-549"></a> <span class="c1"># Ref: https://github.com/carltongibson/django-filter/issues/1107</span>
3388
- <a id="__codelineno-0-550" name="__codelineno-0-550"></a> <span class="n">models</span><span class="o">.</span><span class="n">JSONField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">,</span> <span class="s2">&quot;extra&quot;</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;lookup_expr&quot;</span><span class="p">:</span> <span class="s2">&quot;icontains&quot;</span><span class="p">}},</span>
3389
- <a id="__codelineno-0-551" name="__codelineno-0-551"></a> <span class="n">models</span><span class="o">.</span><span class="n">PositiveIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
3390
- <a id="__codelineno-0-552" name="__codelineno-0-552"></a> <span class="n">models</span><span class="o">.</span><span class="n">PositiveSmallIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
3391
- <a id="__codelineno-0-553" name="__codelineno-0-553"></a> <span class="n">models</span><span class="o">.</span><span class="n">SlugField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
3392
- <a id="__codelineno-0-554" name="__codelineno-0-554"></a> <span class="n">models</span><span class="o">.</span><span class="n">SmallIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
3393
- <a id="__codelineno-0-555" name="__codelineno-0-555"></a> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
3394
- <a id="__codelineno-0-556" name="__codelineno-0-556"></a> <span class="n">models</span><span class="o">.</span><span class="n">TimeField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueTimeFilter</span><span class="p">},</span>
3395
- <a id="__codelineno-0-557" name="__codelineno-0-557"></a> <span class="n">models</span><span class="o">.</span><span class="n">URLField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
3396
- <a id="__codelineno-0-558" name="__codelineno-0-558"></a> <span class="n">models</span><span class="o">.</span><span class="n">UUIDField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueUUIDFilter</span><span class="p">},</span>
3397
- <a id="__codelineno-0-559" name="__codelineno-0-559"></a> <span class="n">core_fields</span><span class="o">.</span><span class="n">MACAddressCharField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueMACAddressFilter</span><span class="p">},</span>
3398
- <a id="__codelineno-0-560" name="__codelineno-0-560"></a> <span class="n">TaggableManager</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">TagFilter</span><span class="p">},</span>
3399
- <a id="__codelineno-0-561" name="__codelineno-0-561"></a> <span class="p">}</span>
3400
- <a id="__codelineno-0-562" name="__codelineno-0-562"></a> <span class="p">)</span>
3401
- <a id="__codelineno-0-563" name="__codelineno-0-563"></a>
3402
- <a id="__codelineno-0-564" name="__codelineno-0-564"></a> <span class="nd">@staticmethod</span>
3403
- <a id="__codelineno-0-565" name="__codelineno-0-565"></a> <span class="k">def</span> <span class="nf">_get_filter_lookup_dict</span><span class="p">(</span><span class="n">existing_filter</span><span class="p">):</span>
3404
- <a id="__codelineno-0-566" name="__codelineno-0-566"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
3405
- <a id="__codelineno-0-567" name="__codelineno-0-567"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span>
3406
- <a id="__codelineno-0-568" name="__codelineno-0-568"></a> <span class="n">existing_filter</span><span class="p">,</span>
3407
- <a id="__codelineno-0-569" name="__codelineno-0-569"></a> <span class="p">(</span>
3408
- <a id="__codelineno-0-570" name="__codelineno-0-570"></a> <span class="n">MultiValueDateFilter</span><span class="p">,</span>
3409
- <a id="__codelineno-0-571" name="__codelineno-0-571"></a> <span class="n">MultiValueDateTimeFilter</span><span class="p">,</span>
3410
- <a id="__codelineno-0-572" name="__codelineno-0-572"></a> <span class="n">MultiValueDecimalFilter</span><span class="p">,</span>
3411
- <a id="__codelineno-0-573" name="__codelineno-0-573"></a> <span class="n">MultiValueFloatFilter</span><span class="p">,</span>
3412
- <a id="__codelineno-0-574" name="__codelineno-0-574"></a> <span class="n">MultiValueNumberFilter</span><span class="p">,</span>
3413
- <a id="__codelineno-0-575" name="__codelineno-0-575"></a> <span class="n">MultiValueTimeFilter</span><span class="p">,</span>
3414
- <a id="__codelineno-0-576" name="__codelineno-0-576"></a> <span class="p">),</span>
3415
- <a id="__codelineno-0-577" name="__codelineno-0-577"></a> <span class="p">):</span>
3416
- <a id="__codelineno-0-578" name="__codelineno-0-578"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">constants</span><span class="o">.</span><span class="n">FILTER_NUMERIC_BASED_LOOKUP_MAP</span>
3417
- <a id="__codelineno-0-579" name="__codelineno-0-579"></a>
3418
- <a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="c1"># These filter types support only negation</span>
3419
- <a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span>
3420
- <a id="__codelineno-0-582" name="__codelineno-0-582"></a> <span class="n">existing_filter</span><span class="p">,</span>
3421
- <a id="__codelineno-0-583" name="__codelineno-0-583"></a> <span class="p">(</span>
3422
- <a id="__codelineno-0-584" name="__codelineno-0-584"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">ModelChoiceFilter</span><span class="p">,</span>
3423
- <a id="__codelineno-0-585" name="__codelineno-0-585"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">ModelMultipleChoiceFilter</span><span class="p">,</span>
3424
- <a id="__codelineno-0-586" name="__codelineno-0-586"></a> <span class="n">TagFilter</span><span class="p">,</span>
3425
- <a id="__codelineno-0-587" name="__codelineno-0-587"></a> <span class="n">TreeNodeMultipleChoiceFilter</span><span class="p">,</span>
3426
- <a id="__codelineno-0-588" name="__codelineno-0-588"></a> <span class="p">),</span>
3427
- <a id="__codelineno-0-589" name="__codelineno-0-589"></a> <span class="p">):</span>
3428
- <a id="__codelineno-0-590" name="__codelineno-0-590"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">constants</span><span class="o">.</span><span class="n">FILTER_NEGATION_LOOKUP_MAP</span>
3429
- <a id="__codelineno-0-591" name="__codelineno-0-591"></a>
3430
- <a id="__codelineno-0-592" name="__codelineno-0-592"></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span>
3431
- <a id="__codelineno-0-593" name="__codelineno-0-593"></a> <span class="n">existing_filter</span><span class="p">,</span>
3432
- <a id="__codelineno-0-594" name="__codelineno-0-594"></a> <span class="p">(</span>
3433
- <a id="__codelineno-0-595" name="__codelineno-0-595"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">filters</span><span class="o">.</span><span class="n">CharFilter</span><span class="p">,</span>
3434
- <a id="__codelineno-0-596" name="__codelineno-0-596"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">MultipleChoiceFilter</span><span class="p">,</span>
3435
- <a id="__codelineno-0-597" name="__codelineno-0-597"></a> <span class="n">MultiValueCharFilter</span><span class="p">,</span>
3436
- <a id="__codelineno-0-598" name="__codelineno-0-598"></a> <span class="n">MultiValueMACAddressFilter</span><span class="p">,</span>
3437
- <a id="__codelineno-0-599" name="__codelineno-0-599"></a> <span class="p">),</span>
3438
- <a id="__codelineno-0-600" name="__codelineno-0-600"></a> <span class="p">):</span>
3439
- <a id="__codelineno-0-601" name="__codelineno-0-601"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">constants</span><span class="o">.</span><span class="n">FILTER_CHAR_BASED_LOOKUP_MAP</span>
3440
- <a id="__codelineno-0-602" name="__codelineno-0-602"></a>
3441
- <a id="__codelineno-0-603" name="__codelineno-0-603"></a> <span class="k">else</span><span class="p">:</span>
3442
- <a id="__codelineno-0-604" name="__codelineno-0-604"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="kc">None</span>
3443
- <a id="__codelineno-0-605" name="__codelineno-0-605"></a>
3444
- <a id="__codelineno-0-606" name="__codelineno-0-606"></a> <span class="k">return</span> <span class="n">lookup_map</span>
3445
- <a id="__codelineno-0-607" name="__codelineno-0-607"></a>
3446
- <a id="__codelineno-0-608" name="__codelineno-0-608"></a> <span class="nd">@classmethod</span>
3447
- <a id="__codelineno-0-609" name="__codelineno-0-609"></a> <span class="k">def</span> <span class="nf">_generate_lookup_expression_filters</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">filter_name</span><span class="p">,</span> <span class="n">filter_field</span><span class="p">):</span>
3448
- <a id="__codelineno-0-610" name="__codelineno-0-610"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3449
- <a id="__codelineno-0-611" name="__codelineno-0-611"></a><span class="sd"> For specific filter types, new filters are created based on defined lookup expressions in</span>
3450
- <a id="__codelineno-0-612" name="__codelineno-0-612"></a><span class="sd"> the form `&lt;field_name&gt;__&lt;lookup_expr&gt;`</span>
3451
- <a id="__codelineno-0-613" name="__codelineno-0-613"></a><span class="sd"> &quot;&quot;&quot;</span>
3452
- <a id="__codelineno-0-614" name="__codelineno-0-614"></a> <span class="n">magic_filters</span> <span class="o">=</span> <span class="p">{}</span>
3453
- <a id="__codelineno-0-615" name="__codelineno-0-615"></a> <span class="k">if</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">method</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">lookup_expr</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;exact&quot;</span><span class="p">,</span> <span class="s2">&quot;in&quot;</span><span class="p">]:</span>
3454
- <a id="__codelineno-0-616" name="__codelineno-0-616"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3455
- <a id="__codelineno-0-617" name="__codelineno-0-617"></a>
3456
- <a id="__codelineno-0-618" name="__codelineno-0-618"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
3457
- <a id="__codelineno-0-619" name="__codelineno-0-619"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_get_filter_lookup_dict</span><span class="p">(</span><span class="n">filter_field</span><span class="p">)</span>
3458
- <a id="__codelineno-0-620" name="__codelineno-0-620"></a> <span class="k">if</span> <span class="n">lookup_map</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3459
- <a id="__codelineno-0-621" name="__codelineno-0-621"></a> <span class="c1"># Do not augment this filter type with more lookup expressions</span>
3460
- <a id="__codelineno-0-622" name="__codelineno-0-622"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3461
- <a id="__codelineno-0-623" name="__codelineno-0-623"></a>
3462
- <a id="__codelineno-0-624" name="__codelineno-0-624"></a> <span class="c1"># Get properties of the existing filter for later use</span>
3463
- <a id="__codelineno-0-625" name="__codelineno-0-625"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">field_name</span>
3464
- <a id="__codelineno-0-626" name="__codelineno-0-626"></a> <span class="n">field</span> <span class="o">=</span> <span class="n">get_model_field</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">,</span> <span class="n">field_name</span><span class="p">)</span>
3465
- <a id="__codelineno-0-627" name="__codelineno-0-627"></a>
3466
- <a id="__codelineno-0-628" name="__codelineno-0-628"></a> <span class="c1"># If there isn&#39;t a model field, return.</span>
3467
- <a id="__codelineno-0-629" name="__codelineno-0-629"></a> <span class="k">if</span> <span class="n">field</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3468
- <a id="__codelineno-0-630" name="__codelineno-0-630"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3469
- <a id="__codelineno-0-631" name="__codelineno-0-631"></a>
3470
- <a id="__codelineno-0-632" name="__codelineno-0-632"></a> <span class="c1"># Create new filters for each lookup expression in the map</span>
3471
- <a id="__codelineno-0-633" name="__codelineno-0-633"></a> <span class="k">for</span> <span class="n">lookup_name</span><span class="p">,</span> <span class="n">lookup_expr</span> <span class="ow">in</span> <span class="n">lookup_map</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
3472
- <a id="__codelineno-0-634" name="__codelineno-0-634"></a> <span class="n">new_filter_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">filter_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">lookup_name</span><span class="si">}</span><span class="s2">&quot;</span>
3473
- <a id="__codelineno-0-635" name="__codelineno-0-635"></a>
3474
- <a id="__codelineno-0-636" name="__codelineno-0-636"></a> <span class="k">try</span><span class="p">:</span>
3475
- <a id="__codelineno-0-637" name="__codelineno-0-637"></a> <span class="k">if</span> <span class="n">filter_name</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">declared_filters</span><span class="p">:</span>
3476
- <a id="__codelineno-0-638" name="__codelineno-0-638"></a> <span class="c1"># The filter field has been explicity defined on the filterset class so we must manually</span>
3477
- <a id="__codelineno-0-639" name="__codelineno-0-639"></a> <span class="c1"># create the new filter with the same type because there is no guarantee the defined type</span>
3478
- <a id="__codelineno-0-640" name="__codelineno-0-640"></a> <span class="c1"># is the same as the default type for the field</span>
3479
- <a id="__codelineno-0-641" name="__codelineno-0-641"></a> <span class="n">resolve_field</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">lookup_expr</span><span class="p">)</span> <span class="c1"># Will raise FieldLookupError if the lookup is invalid</span>
3480
- <a id="__codelineno-0-642" name="__codelineno-0-642"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">filter_field</span><span class="p">)(</span>
3481
- <a id="__codelineno-0-643" name="__codelineno-0-643"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">field_name</span><span class="p">,</span>
3482
- <a id="__codelineno-0-644" name="__codelineno-0-644"></a> <span class="n">lookup_expr</span><span class="o">=</span><span class="n">lookup_expr</span><span class="p">,</span>
3483
- <a id="__codelineno-0-645" name="__codelineno-0-645"></a> <span class="n">label</span><span class="o">=</span><span class="n">filter_field</span><span class="o">.</span><span class="n">label</span><span class="p">,</span>
3484
- <a id="__codelineno-0-646" name="__codelineno-0-646"></a> <span class="n">exclude</span><span class="o">=</span><span class="n">filter_field</span><span class="o">.</span><span class="n">exclude</span><span class="p">,</span>
3485
- <a id="__codelineno-0-647" name="__codelineno-0-647"></a> <span class="n">distinct</span><span class="o">=</span><span class="n">filter_field</span><span class="o">.</span><span class="n">distinct</span><span class="p">,</span>
3486
- <a id="__codelineno-0-648" name="__codelineno-0-648"></a> <span class="o">**</span><span class="n">filter_field</span><span class="o">.</span><span class="n">extra</span><span class="p">,</span>
3487
- <a id="__codelineno-0-649" name="__codelineno-0-649"></a> <span class="p">)</span>
3488
- <a id="__codelineno-0-650" name="__codelineno-0-650"></a> <span class="k">else</span><span class="p">:</span>
3489
- <a id="__codelineno-0-651" name="__codelineno-0-651"></a> <span class="c1"># The filter field is listed in Meta.fields so we can safely rely on default behaviour</span>
3490
- <a id="__codelineno-0-652" name="__codelineno-0-652"></a> <span class="c1"># Will raise FieldLookupError if the lookup is invalid</span>
3491
- <a id="__codelineno-0-653" name="__codelineno-0-653"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">filter_for_field</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">field_name</span><span class="p">,</span> <span class="n">lookup_expr</span><span class="p">)</span>
3492
- <a id="__codelineno-0-654" name="__codelineno-0-654"></a> <span class="k">except</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">FieldLookupError</span><span class="p">:</span>
3493
- <a id="__codelineno-0-655" name="__codelineno-0-655"></a> <span class="c1"># The filter could not be created because the lookup expression is not supported on the field</span>
3494
- <a id="__codelineno-0-656" name="__codelineno-0-656"></a> <span class="k">continue</span>
3495
- <a id="__codelineno-0-657" name="__codelineno-0-657"></a>
3496
- <a id="__codelineno-0-658" name="__codelineno-0-658"></a> <span class="k">if</span> <span class="n">lookup_name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;n&quot;</span><span class="p">):</span>
3497
- <a id="__codelineno-0-659" name="__codelineno-0-659"></a> <span class="c1"># This is a negation filter which requires a queryset.exclude() clause</span>
3498
- <a id="__codelineno-0-660" name="__codelineno-0-660"></a> <span class="c1"># Of course setting the negation of the existing filter&#39;s exclude attribute handles both cases</span>
3499
- <a id="__codelineno-0-661" name="__codelineno-0-661"></a> <span class="n">new_filter</span><span class="o">.</span><span class="n">exclude</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">exclude</span>
3500
- <a id="__codelineno-0-662" name="__codelineno-0-662"></a>
3501
- <a id="__codelineno-0-663" name="__codelineno-0-663"></a> <span class="n">magic_filters</span><span class="p">[</span><span class="n">new_filter_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_filter</span>
3502
- <a id="__codelineno-0-664" name="__codelineno-0-664"></a>
3503
- <a id="__codelineno-0-665" name="__codelineno-0-665"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3504
- <a id="__codelineno-0-666" name="__codelineno-0-666"></a>
3505
- <a id="__codelineno-0-667" name="__codelineno-0-667"></a> <span class="nd">@classmethod</span>
3506
- <a id="__codelineno-0-668" name="__codelineno-0-668"></a> <span class="k">def</span> <span class="nf">add_filter</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">new_filter_name</span><span class="p">,</span> <span class="n">new_filter_field</span><span class="p">):</span>
3507
- <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3508
- <a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="sd"> Allow filters to be added post-generation on import.</span>
3509
- <a id="__codelineno-0-671" name="__codelineno-0-671"></a>
3510
- <a id="__codelineno-0-672" name="__codelineno-0-672"></a><span class="sd"> Will provide `&lt;field_name&gt;__&lt;lookup_expr&gt;` generation automagically.</span>
3511
- <a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> &quot;&quot;&quot;</span>
3512
- <a id="__codelineno-0-674" name="__codelineno-0-674"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">new_filter_field</span><span class="p">,</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">Filter</span><span class="p">):</span>
3513
- <a id="__codelineno-0-675" name="__codelineno-0-675"></a> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Tried to add filter (</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">) which is not an instance of Django Filter&quot;</span><span class="p">)</span>
3514
- <a id="__codelineno-0-676" name="__codelineno-0-676"></a>
3515
- <a id="__codelineno-0-677" name="__codelineno-0-677"></a> <span class="k">if</span> <span class="n">new_filter_name</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">:</span>
3516
- <a id="__codelineno-0-678" name="__codelineno-0-678"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3517
- <a id="__codelineno-0-679" name="__codelineno-0-679"></a> <span class="sa">f</span><span class="s2">&quot;There was a conflict with filter `</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">`, the custom filter was ignored.&quot;</span>
3518
- <a id="__codelineno-0-680" name="__codelineno-0-680"></a> <span class="p">)</span>
3519
- <a id="__codelineno-0-681" name="__codelineno-0-681"></a>
3520
- <a id="__codelineno-0-682" name="__codelineno-0-682"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">[</span><span class="n">new_filter_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_filter_field</span>
3521
- <a id="__codelineno-0-683" name="__codelineno-0-683"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
3522
- <a id="__codelineno-0-684" name="__codelineno-0-684"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
3523
- <a id="__codelineno-0-685" name="__codelineno-0-685"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
3524
- <a id="__codelineno-0-686" name="__codelineno-0-686"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span><span class="n">filter_name</span><span class="o">=</span><span class="n">new_filter_name</span><span class="p">,</span> <span class="n">filter_field</span><span class="o">=</span><span class="n">new_filter_field</span><span class="p">)</span>
3525
- <a id="__codelineno-0-687" name="__codelineno-0-687"></a> <span class="p">)</span>
3526
- <a id="__codelineno-0-688" name="__codelineno-0-688"></a>
3527
- <a id="__codelineno-0-689" name="__codelineno-0-689"></a> <span class="nd">@classmethod</span>
3528
- <a id="__codelineno-0-690" name="__codelineno-0-690"></a> <span class="k">def</span> <span class="nf">get_fields</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
3529
- <a id="__codelineno-0-691" name="__codelineno-0-691"></a> <span class="n">fields</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_fields</span><span class="p">()</span>
3530
- <a id="__codelineno-0-692" name="__codelineno-0-692"></a> <span class="k">if</span> <span class="s2">&quot;id&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">fields</span> <span class="ow">and</span> <span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">exclude</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="s2">&quot;id&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">exclude</span><span class="p">):</span>
3531
- <a id="__codelineno-0-693" name="__codelineno-0-693"></a> <span class="c1"># Add &quot;id&quot; as the first key in the `fields` OrderedDict</span>
3532
- <a id="__codelineno-0-694" name="__codelineno-0-694"></a> <span class="n">fields</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="p">[</span><span class="n">django_filters</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_LOOKUP_EXPR</span><span class="p">],</span> <span class="o">**</span><span class="n">fields</span><span class="p">)</span>
3533
- <a id="__codelineno-0-695" name="__codelineno-0-695"></a> <span class="k">return</span> <span class="n">fields</span>
3534
- <a id="__codelineno-0-696" name="__codelineno-0-696"></a>
3535
- <a id="__codelineno-0-697" name="__codelineno-0-697"></a> <span class="nd">@classmethod</span>
3536
- <a id="__codelineno-0-698" name="__codelineno-0-698"></a> <span class="k">def</span> <span class="nf">get_filters</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
3537
- <a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3538
- <a id="__codelineno-0-700" name="__codelineno-0-700"></a><span class="sd"> Override filter generation to support dynamic lookup expressions for certain filter types.</span>
3539
- <a id="__codelineno-0-701" name="__codelineno-0-701"></a><span class="sd"> &quot;&quot;&quot;</span>
3540
- <a id="__codelineno-0-702" name="__codelineno-0-702"></a> <span class="n">filters</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_filters</span><span class="p">()</span>
3541
- <a id="__codelineno-0-703" name="__codelineno-0-703"></a>
3542
- <a id="__codelineno-0-704" name="__codelineno-0-704"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
3543
- <a id="__codelineno-0-705" name="__codelineno-0-705"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
3544
- <a id="__codelineno-0-706" name="__codelineno-0-706"></a> <span class="n">new_filters</span> <span class="o">=</span> <span class="p">{}</span>
3545
- <a id="__codelineno-0-707" name="__codelineno-0-707"></a> <span class="k">for</span> <span class="n">existing_filter_name</span><span class="p">,</span> <span class="n">existing_filter</span> <span class="ow">in</span> <span class="n">filters</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
3546
- <a id="__codelineno-0-708" name="__codelineno-0-708"></a> <span class="n">new_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
3547
- <a id="__codelineno-0-709" name="__codelineno-0-709"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span>
3548
- <a id="__codelineno-0-710" name="__codelineno-0-710"></a> <span class="n">filter_name</span><span class="o">=</span><span class="n">existing_filter_name</span><span class="p">,</span>
3549
- <a id="__codelineno-0-711" name="__codelineno-0-711"></a> <span class="n">filter_field</span><span class="o">=</span><span class="n">existing_filter</span><span class="p">,</span>
3550
- <a id="__codelineno-0-712" name="__codelineno-0-712"></a> <span class="p">)</span>
3551
- <a id="__codelineno-0-713" name="__codelineno-0-713"></a> <span class="p">)</span>
3552
- <a id="__codelineno-0-714" name="__codelineno-0-714"></a>
3553
- <a id="__codelineno-0-715" name="__codelineno-0-715"></a> <span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">new_filters</span><span class="p">)</span>
3554
- <a id="__codelineno-0-716" name="__codelineno-0-716"></a>
3555
- <a id="__codelineno-0-717" name="__codelineno-0-717"></a> <span class="k">return</span> <span class="n">filters</span>
3556
- <a id="__codelineno-0-718" name="__codelineno-0-718"></a>
3557
- <a id="__codelineno-0-719" name="__codelineno-0-719"></a> <span class="nd">@classmethod</span>
3558
- <a id="__codelineno-0-720" name="__codelineno-0-720"></a> <span class="k">def</span> <span class="nf">filter_for_lookup</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">):</span>
3559
- <a id="__codelineno-0-721" name="__codelineno-0-721"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Override filter_for_lookup method to set ChoiceField Filter to MultipleChoiceFilter.</span>
3560
- <a id="__codelineno-0-722" name="__codelineno-0-722"></a>
3561
- <a id="__codelineno-0-723" name="__codelineno-0-723"></a><span class="sd"> Note: Any CharField or IntegerField with choices set is a ChoiceField.</span>
3562
- <a id="__codelineno-0-724" name="__codelineno-0-724"></a><span class="sd"> &quot;&quot;&quot;</span>
3563
- <a id="__codelineno-0-725" name="__codelineno-0-725"></a> <span class="k">if</span> <span class="n">lookup_type</span> <span class="o">==</span> <span class="s2">&quot;exact&quot;</span> <span class="ow">and</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;choices&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
3564
- <a id="__codelineno-0-726" name="__codelineno-0-726"></a> <span class="k">return</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">MultipleChoiceFilter</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;choices&quot;</span><span class="p">:</span> <span class="n">field</span><span class="o">.</span><span class="n">choices</span><span class="p">}</span>
3565
- <a id="__codelineno-0-727" name="__codelineno-0-727"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">filter_for_lookup</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">)</span>
3566
- <a id="__codelineno-0-728" name="__codelineno-0-728"></a>
3567
- <a id="__codelineno-0-729" name="__codelineno-0-729"></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">data</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">queryset</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">request</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
3568
- <a id="__codelineno-0-730" name="__codelineno-0-730"></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">data</span><span class="p">,</span> <span class="n">queryset</span><span class="p">,</span> <span class="n">request</span><span class="o">=</span><span class="n">request</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="n">prefix</span><span class="p">)</span>
3569
- <a id="__codelineno-0-731" name="__codelineno-0-731"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="kc">None</span>
3570
- <a id="__codelineno-0-732" name="__codelineno-0-732"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span> <span class="o">=</span> <span class="kc">None</span>
3571
- <a id="__codelineno-0-733" name="__codelineno-0-733"></a>
3572
- <a id="__codelineno-0-734" name="__codelineno-0-734"></a> <span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3573
- <a id="__codelineno-0-735" name="__codelineno-0-735"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Extend FilterSet.is_valid() to potentially enforce settings.STRICT_FILTERING.&quot;&quot;&quot;</span>
3574
- <a id="__codelineno-0-736" name="__codelineno-0-736"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3575
- <a id="__codelineno-0-737" name="__codelineno-0-737"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span>
3576
- <a id="__codelineno-0-738" name="__codelineno-0-738"></a> <span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">STRICT_FILTERING</span><span class="p">:</span>
3577
- <a id="__codelineno-0-739" name="__codelineno-0-739"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">and</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="o">.</span><span class="n">issubset</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
3578
- <a id="__codelineno-0-740" name="__codelineno-0-740"></a> <span class="k">else</span><span class="p">:</span>
3579
- <a id="__codelineno-0-741" name="__codelineno-0-741"></a> <span class="c1"># Trigger warning logs associated with generating self.errors</span>
3580
- <a id="__codelineno-0-742" name="__codelineno-0-742"></a> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span>
3581
- <a id="__codelineno-0-743" name="__codelineno-0-743"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span>
3582
- <a id="__codelineno-0-744" name="__codelineno-0-744"></a>
3583
- <a id="__codelineno-0-745" name="__codelineno-0-745"></a> <span class="nd">@property</span>
3584
- <a id="__codelineno-0-746" name="__codelineno-0-746"></a> <span class="k">def</span> <span class="nf">errors</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3585
- <a id="__codelineno-0-747" name="__codelineno-0-747"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Extend FilterSet.errors to potentially include additional errors from settings.STRICT_FILTERING.&quot;&quot;&quot;</span>
3586
- <a id="__codelineno-0-748" name="__codelineno-0-748"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3587
- <a id="__codelineno-0-749" name="__codelineno-0-749"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span> <span class="o">=</span> <span class="n">ErrorDict</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">errors</span><span class="p">)</span>
3588
- <a id="__codelineno-0-750" name="__codelineno-0-750"></a> <span class="k">for</span> <span class="n">extra_key</span> <span class="ow">in</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">keys</span><span class="p">()):</span>
3589
- <a id="__codelineno-0-751" name="__codelineno-0-751"></a> <span class="c1"># If a given field was invalid, it will be omitted from cleaned_data; don&#39;t report extra errors</span>
3590
- <a id="__codelineno-0-752" name="__codelineno-0-752"></a> <span class="k">if</span> <span class="n">extra_key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span><span class="p">:</span>
3591
- <a id="__codelineno-0-753" name="__codelineno-0-753"></a> <span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">STRICT_FILTERING</span><span class="p">:</span>
3592
- <a id="__codelineno-0-754" name="__codelineno-0-754"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">extra_key</span><span class="p">,</span> <span class="n">ErrorList</span><span class="p">())</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;Unknown filter field&quot;</span><span class="p">)</span>
3593
- <a id="__codelineno-0-755" name="__codelineno-0-755"></a> <span class="k">else</span><span class="p">:</span>
3594
- <a id="__codelineno-0-756" name="__codelineno-0-756"></a> <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1">: Unknown filter field &quot;</span><span class="si">%s</span><span class="s1">&quot;&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">extra_key</span><span class="p">)</span>
3595
- <a id="__codelineno-0-757" name="__codelineno-0-757"></a>
3596
- <a id="__codelineno-0-758" name="__codelineno-0-758"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span>
4538
+ <span class="normal"><a href="#__codelineno-0-757">757</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-531" name="__codelineno-0-531"></a><span class="k">class</span> <span class="nc">BaseFilterSet</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
4539
+ <a id="__codelineno-0-532" name="__codelineno-0-532"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4540
+ <a id="__codelineno-0-533" name="__codelineno-0-533"></a><span class="sd"> A base filterset which provides common functionality to all Nautobot filtersets.</span>
4541
+ <a id="__codelineno-0-534" name="__codelineno-0-534"></a><span class="sd"> &quot;&quot;&quot;</span>
4542
+ <a id="__codelineno-0-535" name="__codelineno-0-535"></a>
4543
+ <a id="__codelineno-0-536" name="__codelineno-0-536"></a> <span class="n">FILTER_DEFAULTS</span> <span class="o">=</span> <span class="n">deepcopy</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">filterset</span><span class="o">.</span><span class="n">FILTER_FOR_DBFIELD_DEFAULTS</span><span class="p">)</span>
4544
+ <a id="__codelineno-0-537" name="__codelineno-0-537"></a> <span class="n">FILTER_DEFAULTS</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
4545
+ <a id="__codelineno-0-538" name="__codelineno-0-538"></a> <span class="p">{</span>
4546
+ <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="n">models</span><span class="o">.</span><span class="n">AutoField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
4547
+ <a id="__codelineno-0-540" name="__codelineno-0-540"></a> <span class="n">models</span><span class="o">.</span><span class="n">BigIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueBigNumberFilter</span><span class="p">},</span>
4548
+ <a id="__codelineno-0-541" name="__codelineno-0-541"></a> <span class="n">models</span><span class="o">.</span><span class="n">CharField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
4549
+ <a id="__codelineno-0-542" name="__codelineno-0-542"></a> <span class="n">models</span><span class="o">.</span><span class="n">DateField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueDateFilter</span><span class="p">},</span>
4550
+ <a id="__codelineno-0-543" name="__codelineno-0-543"></a> <span class="n">models</span><span class="o">.</span><span class="n">DateTimeField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueDateTimeFilter</span><span class="p">},</span>
4551
+ <a id="__codelineno-0-544" name="__codelineno-0-544"></a> <span class="n">models</span><span class="o">.</span><span class="n">DecimalField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueDecimalFilter</span><span class="p">},</span>
4552
+ <a id="__codelineno-0-545" name="__codelineno-0-545"></a> <span class="n">models</span><span class="o">.</span><span class="n">EmailField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
4553
+ <a id="__codelineno-0-546" name="__codelineno-0-546"></a> <span class="n">models</span><span class="o">.</span><span class="n">FloatField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueFloatFilter</span><span class="p">},</span>
4554
+ <a id="__codelineno-0-547" name="__codelineno-0-547"></a> <span class="n">models</span><span class="o">.</span><span class="n">IntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
4555
+ <a id="__codelineno-0-548" name="__codelineno-0-548"></a> <span class="c1"># Ref: https://github.com/carltongibson/django-filter/issues/1107</span>
4556
+ <a id="__codelineno-0-549" name="__codelineno-0-549"></a> <span class="n">models</span><span class="o">.</span><span class="n">JSONField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">,</span> <span class="s2">&quot;extra&quot;</span><span class="p">:</span> <span class="k">lambda</span> <span class="n">f</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;lookup_expr&quot;</span><span class="p">:</span> <span class="s2">&quot;icontains&quot;</span><span class="p">}},</span>
4557
+ <a id="__codelineno-0-550" name="__codelineno-0-550"></a> <span class="n">models</span><span class="o">.</span><span class="n">PositiveIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
4558
+ <a id="__codelineno-0-551" name="__codelineno-0-551"></a> <span class="n">models</span><span class="o">.</span><span class="n">PositiveSmallIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
4559
+ <a id="__codelineno-0-552" name="__codelineno-0-552"></a> <span class="n">models</span><span class="o">.</span><span class="n">SlugField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
4560
+ <a id="__codelineno-0-553" name="__codelineno-0-553"></a> <span class="n">models</span><span class="o">.</span><span class="n">SmallIntegerField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueNumberFilter</span><span class="p">},</span>
4561
+ <a id="__codelineno-0-554" name="__codelineno-0-554"></a> <span class="n">models</span><span class="o">.</span><span class="n">TextField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
4562
+ <a id="__codelineno-0-555" name="__codelineno-0-555"></a> <span class="n">models</span><span class="o">.</span><span class="n">TimeField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueTimeFilter</span><span class="p">},</span>
4563
+ <a id="__codelineno-0-556" name="__codelineno-0-556"></a> <span class="n">models</span><span class="o">.</span><span class="n">URLField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueCharFilter</span><span class="p">},</span>
4564
+ <a id="__codelineno-0-557" name="__codelineno-0-557"></a> <span class="n">models</span><span class="o">.</span><span class="n">UUIDField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueUUIDFilter</span><span class="p">},</span>
4565
+ <a id="__codelineno-0-558" name="__codelineno-0-558"></a> <span class="n">core_fields</span><span class="o">.</span><span class="n">MACAddressCharField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">MultiValueMACAddressFilter</span><span class="p">},</span>
4566
+ <a id="__codelineno-0-559" name="__codelineno-0-559"></a> <span class="n">core_fields</span><span class="o">.</span><span class="n">TagsField</span><span class="p">:</span> <span class="p">{</span><span class="s2">&quot;filter_class&quot;</span><span class="p">:</span> <span class="n">TagFilter</span><span class="p">},</span>
4567
+ <a id="__codelineno-0-560" name="__codelineno-0-560"></a> <span class="p">}</span>
4568
+ <a id="__codelineno-0-561" name="__codelineno-0-561"></a> <span class="p">)</span>
4569
+ <a id="__codelineno-0-562" name="__codelineno-0-562"></a>
4570
+ <a id="__codelineno-0-563" name="__codelineno-0-563"></a> <span class="nd">@staticmethod</span>
4571
+ <a id="__codelineno-0-564" name="__codelineno-0-564"></a> <span class="k">def</span> <span class="nf">_get_filter_lookup_dict</span><span class="p">(</span><span class="n">existing_filter</span><span class="p">):</span>
4572
+ <a id="__codelineno-0-565" name="__codelineno-0-565"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
4573
+ <a id="__codelineno-0-566" name="__codelineno-0-566"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span>
4574
+ <a id="__codelineno-0-567" name="__codelineno-0-567"></a> <span class="n">existing_filter</span><span class="p">,</span>
4575
+ <a id="__codelineno-0-568" name="__codelineno-0-568"></a> <span class="p">(</span>
4576
+ <a id="__codelineno-0-569" name="__codelineno-0-569"></a> <span class="n">MultiValueDateFilter</span><span class="p">,</span>
4577
+ <a id="__codelineno-0-570" name="__codelineno-0-570"></a> <span class="n">MultiValueDateTimeFilter</span><span class="p">,</span>
4578
+ <a id="__codelineno-0-571" name="__codelineno-0-571"></a> <span class="n">MultiValueDecimalFilter</span><span class="p">,</span>
4579
+ <a id="__codelineno-0-572" name="__codelineno-0-572"></a> <span class="n">MultiValueFloatFilter</span><span class="p">,</span>
4580
+ <a id="__codelineno-0-573" name="__codelineno-0-573"></a> <span class="n">MultiValueNumberFilter</span><span class="p">,</span>
4581
+ <a id="__codelineno-0-574" name="__codelineno-0-574"></a> <span class="n">MultiValueTimeFilter</span><span class="p">,</span>
4582
+ <a id="__codelineno-0-575" name="__codelineno-0-575"></a> <span class="p">),</span>
4583
+ <a id="__codelineno-0-576" name="__codelineno-0-576"></a> <span class="p">):</span>
4584
+ <a id="__codelineno-0-577" name="__codelineno-0-577"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">constants</span><span class="o">.</span><span class="n">FILTER_NUMERIC_BASED_LOOKUP_MAP</span>
4585
+ <a id="__codelineno-0-578" name="__codelineno-0-578"></a>
4586
+ <a id="__codelineno-0-579" name="__codelineno-0-579"></a> <span class="c1"># These filter types support only negation</span>
4587
+ <a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span>
4588
+ <a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="n">existing_filter</span><span class="p">,</span>
4589
+ <a id="__codelineno-0-582" name="__codelineno-0-582"></a> <span class="p">(</span>
4590
+ <a id="__codelineno-0-583" name="__codelineno-0-583"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">ModelChoiceFilter</span><span class="p">,</span>
4591
+ <a id="__codelineno-0-584" name="__codelineno-0-584"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">ModelMultipleChoiceFilter</span><span class="p">,</span>
4592
+ <a id="__codelineno-0-585" name="__codelineno-0-585"></a> <span class="n">TagFilter</span><span class="p">,</span>
4593
+ <a id="__codelineno-0-586" name="__codelineno-0-586"></a> <span class="n">TreeNodeMultipleChoiceFilter</span><span class="p">,</span>
4594
+ <a id="__codelineno-0-587" name="__codelineno-0-587"></a> <span class="p">),</span>
4595
+ <a id="__codelineno-0-588" name="__codelineno-0-588"></a> <span class="p">):</span>
4596
+ <a id="__codelineno-0-589" name="__codelineno-0-589"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">constants</span><span class="o">.</span><span class="n">FILTER_NEGATION_LOOKUP_MAP</span>
4597
+ <a id="__codelineno-0-590" name="__codelineno-0-590"></a>
4598
+ <a id="__codelineno-0-591" name="__codelineno-0-591"></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span>
4599
+ <a id="__codelineno-0-592" name="__codelineno-0-592"></a> <span class="n">existing_filter</span><span class="p">,</span>
4600
+ <a id="__codelineno-0-593" name="__codelineno-0-593"></a> <span class="p">(</span>
4601
+ <a id="__codelineno-0-594" name="__codelineno-0-594"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">filters</span><span class="o">.</span><span class="n">CharFilter</span><span class="p">,</span>
4602
+ <a id="__codelineno-0-595" name="__codelineno-0-595"></a> <span class="n">django_filters</span><span class="o">.</span><span class="n">MultipleChoiceFilter</span><span class="p">,</span>
4603
+ <a id="__codelineno-0-596" name="__codelineno-0-596"></a> <span class="n">MultiValueCharFilter</span><span class="p">,</span>
4604
+ <a id="__codelineno-0-597" name="__codelineno-0-597"></a> <span class="n">MultiValueMACAddressFilter</span><span class="p">,</span>
4605
+ <a id="__codelineno-0-598" name="__codelineno-0-598"></a> <span class="p">),</span>
4606
+ <a id="__codelineno-0-599" name="__codelineno-0-599"></a> <span class="p">):</span>
4607
+ <a id="__codelineno-0-600" name="__codelineno-0-600"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">constants</span><span class="o">.</span><span class="n">FILTER_CHAR_BASED_LOOKUP_MAP</span>
4608
+ <a id="__codelineno-0-601" name="__codelineno-0-601"></a>
4609
+ <a id="__codelineno-0-602" name="__codelineno-0-602"></a> <span class="k">else</span><span class="p">:</span>
4610
+ <a id="__codelineno-0-603" name="__codelineno-0-603"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="kc">None</span>
4611
+ <a id="__codelineno-0-604" name="__codelineno-0-604"></a>
4612
+ <a id="__codelineno-0-605" name="__codelineno-0-605"></a> <span class="k">return</span> <span class="n">lookup_map</span>
4613
+ <a id="__codelineno-0-606" name="__codelineno-0-606"></a>
4614
+ <a id="__codelineno-0-607" name="__codelineno-0-607"></a> <span class="nd">@classmethod</span>
4615
+ <a id="__codelineno-0-608" name="__codelineno-0-608"></a> <span class="k">def</span> <span class="nf">_generate_lookup_expression_filters</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">filter_name</span><span class="p">,</span> <span class="n">filter_field</span><span class="p">):</span>
4616
+ <a id="__codelineno-0-609" name="__codelineno-0-609"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4617
+ <a id="__codelineno-0-610" name="__codelineno-0-610"></a><span class="sd"> For specific filter types, new filters are created based on defined lookup expressions in</span>
4618
+ <a id="__codelineno-0-611" name="__codelineno-0-611"></a><span class="sd"> the form `&lt;field_name&gt;__&lt;lookup_expr&gt;`</span>
4619
+ <a id="__codelineno-0-612" name="__codelineno-0-612"></a><span class="sd"> &quot;&quot;&quot;</span>
4620
+ <a id="__codelineno-0-613" name="__codelineno-0-613"></a> <span class="n">magic_filters</span> <span class="o">=</span> <span class="p">{}</span>
4621
+ <a id="__codelineno-0-614" name="__codelineno-0-614"></a> <span class="k">if</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">method</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span> <span class="ow">or</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">lookup_expr</span> <span class="ow">not</span> <span class="ow">in</span> <span class="p">[</span><span class="s2">&quot;exact&quot;</span><span class="p">,</span> <span class="s2">&quot;in&quot;</span><span class="p">]:</span>
4622
+ <a id="__codelineno-0-615" name="__codelineno-0-615"></a> <span class="k">return</span> <span class="n">magic_filters</span>
4623
+ <a id="__codelineno-0-616" name="__codelineno-0-616"></a>
4624
+ <a id="__codelineno-0-617" name="__codelineno-0-617"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
4625
+ <a id="__codelineno-0-618" name="__codelineno-0-618"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_get_filter_lookup_dict</span><span class="p">(</span><span class="n">filter_field</span><span class="p">)</span>
4626
+ <a id="__codelineno-0-619" name="__codelineno-0-619"></a> <span class="k">if</span> <span class="n">lookup_map</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4627
+ <a id="__codelineno-0-620" name="__codelineno-0-620"></a> <span class="c1"># Do not augment this filter type with more lookup expressions</span>
4628
+ <a id="__codelineno-0-621" name="__codelineno-0-621"></a> <span class="k">return</span> <span class="n">magic_filters</span>
4629
+ <a id="__codelineno-0-622" name="__codelineno-0-622"></a>
4630
+ <a id="__codelineno-0-623" name="__codelineno-0-623"></a> <span class="c1"># Get properties of the existing filter for later use</span>
4631
+ <a id="__codelineno-0-624" name="__codelineno-0-624"></a> <span class="n">field_name</span> <span class="o">=</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">field_name</span>
4632
+ <a id="__codelineno-0-625" name="__codelineno-0-625"></a> <span class="n">field</span> <span class="o">=</span> <span class="n">get_model_field</span><span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">,</span> <span class="n">field_name</span><span class="p">)</span>
4633
+ <a id="__codelineno-0-626" name="__codelineno-0-626"></a>
4634
+ <a id="__codelineno-0-627" name="__codelineno-0-627"></a> <span class="c1"># If there isn&#39;t a model field, return.</span>
4635
+ <a id="__codelineno-0-628" name="__codelineno-0-628"></a> <span class="k">if</span> <span class="n">field</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4636
+ <a id="__codelineno-0-629" name="__codelineno-0-629"></a> <span class="k">return</span> <span class="n">magic_filters</span>
4637
+ <a id="__codelineno-0-630" name="__codelineno-0-630"></a>
4638
+ <a id="__codelineno-0-631" name="__codelineno-0-631"></a> <span class="c1"># Create new filters for each lookup expression in the map</span>
4639
+ <a id="__codelineno-0-632" name="__codelineno-0-632"></a> <span class="k">for</span> <span class="n">lookup_name</span><span class="p">,</span> <span class="n">lookup_expr</span> <span class="ow">in</span> <span class="n">lookup_map</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4640
+ <a id="__codelineno-0-633" name="__codelineno-0-633"></a> <span class="n">new_filter_name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">filter_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="n">lookup_name</span><span class="si">}</span><span class="s2">&quot;</span>
4641
+ <a id="__codelineno-0-634" name="__codelineno-0-634"></a>
4642
+ <a id="__codelineno-0-635" name="__codelineno-0-635"></a> <span class="k">try</span><span class="p">:</span>
4643
+ <a id="__codelineno-0-636" name="__codelineno-0-636"></a> <span class="k">if</span> <span class="n">filter_name</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">declared_filters</span><span class="p">:</span>
4644
+ <a id="__codelineno-0-637" name="__codelineno-0-637"></a> <span class="c1"># The filter field has been explicity defined on the filterset class so we must manually</span>
4645
+ <a id="__codelineno-0-638" name="__codelineno-0-638"></a> <span class="c1"># create the new filter with the same type because there is no guarantee the defined type</span>
4646
+ <a id="__codelineno-0-639" name="__codelineno-0-639"></a> <span class="c1"># is the same as the default type for the field</span>
4647
+ <a id="__codelineno-0-640" name="__codelineno-0-640"></a> <span class="n">resolve_field</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">lookup_expr</span><span class="p">)</span> <span class="c1"># Will raise FieldLookupError if the lookup is invalid</span>
4648
+ <a id="__codelineno-0-641" name="__codelineno-0-641"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="nb">type</span><span class="p">(</span><span class="n">filter_field</span><span class="p">)(</span>
4649
+ <a id="__codelineno-0-642" name="__codelineno-0-642"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">field_name</span><span class="p">,</span>
4650
+ <a id="__codelineno-0-643" name="__codelineno-0-643"></a> <span class="n">lookup_expr</span><span class="o">=</span><span class="n">lookup_expr</span><span class="p">,</span>
4651
+ <a id="__codelineno-0-644" name="__codelineno-0-644"></a> <span class="n">label</span><span class="o">=</span><span class="n">filter_field</span><span class="o">.</span><span class="n">label</span><span class="p">,</span>
4652
+ <a id="__codelineno-0-645" name="__codelineno-0-645"></a> <span class="n">exclude</span><span class="o">=</span><span class="n">filter_field</span><span class="o">.</span><span class="n">exclude</span><span class="p">,</span>
4653
+ <a id="__codelineno-0-646" name="__codelineno-0-646"></a> <span class="n">distinct</span><span class="o">=</span><span class="n">filter_field</span><span class="o">.</span><span class="n">distinct</span><span class="p">,</span>
4654
+ <a id="__codelineno-0-647" name="__codelineno-0-647"></a> <span class="o">**</span><span class="n">filter_field</span><span class="o">.</span><span class="n">extra</span><span class="p">,</span>
4655
+ <a id="__codelineno-0-648" name="__codelineno-0-648"></a> <span class="p">)</span>
4656
+ <a id="__codelineno-0-649" name="__codelineno-0-649"></a> <span class="k">else</span><span class="p">:</span>
4657
+ <a id="__codelineno-0-650" name="__codelineno-0-650"></a> <span class="c1"># The filter field is listed in Meta.fields so we can safely rely on default behaviour</span>
4658
+ <a id="__codelineno-0-651" name="__codelineno-0-651"></a> <span class="c1"># Will raise FieldLookupError if the lookup is invalid</span>
4659
+ <a id="__codelineno-0-652" name="__codelineno-0-652"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">filter_for_field</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">field_name</span><span class="p">,</span> <span class="n">lookup_expr</span><span class="p">)</span>
4660
+ <a id="__codelineno-0-653" name="__codelineno-0-653"></a> <span class="k">except</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">exceptions</span><span class="o">.</span><span class="n">FieldLookupError</span><span class="p">:</span>
4661
+ <a id="__codelineno-0-654" name="__codelineno-0-654"></a> <span class="c1"># The filter could not be created because the lookup expression is not supported on the field</span>
4662
+ <a id="__codelineno-0-655" name="__codelineno-0-655"></a> <span class="k">continue</span>
4663
+ <a id="__codelineno-0-656" name="__codelineno-0-656"></a>
4664
+ <a id="__codelineno-0-657" name="__codelineno-0-657"></a> <span class="k">if</span> <span class="n">lookup_name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">&quot;n&quot;</span><span class="p">):</span>
4665
+ <a id="__codelineno-0-658" name="__codelineno-0-658"></a> <span class="c1"># This is a negation filter which requires a queryset.exclude() clause</span>
4666
+ <a id="__codelineno-0-659" name="__codelineno-0-659"></a> <span class="c1"># Of course setting the negation of the existing filter&#39;s exclude attribute handles both cases</span>
4667
+ <a id="__codelineno-0-660" name="__codelineno-0-660"></a> <span class="n">new_filter</span><span class="o">.</span><span class="n">exclude</span> <span class="o">=</span> <span class="ow">not</span> <span class="n">filter_field</span><span class="o">.</span><span class="n">exclude</span>
4668
+ <a id="__codelineno-0-661" name="__codelineno-0-661"></a>
4669
+ <a id="__codelineno-0-662" name="__codelineno-0-662"></a> <span class="n">magic_filters</span><span class="p">[</span><span class="n">new_filter_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_filter</span>
4670
+ <a id="__codelineno-0-663" name="__codelineno-0-663"></a>
4671
+ <a id="__codelineno-0-664" name="__codelineno-0-664"></a> <span class="k">return</span> <span class="n">magic_filters</span>
4672
+ <a id="__codelineno-0-665" name="__codelineno-0-665"></a>
4673
+ <a id="__codelineno-0-666" name="__codelineno-0-666"></a> <span class="nd">@classmethod</span>
4674
+ <a id="__codelineno-0-667" name="__codelineno-0-667"></a> <span class="k">def</span> <span class="nf">add_filter</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">new_filter_name</span><span class="p">,</span> <span class="n">new_filter_field</span><span class="p">):</span>
4675
+ <a id="__codelineno-0-668" name="__codelineno-0-668"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4676
+ <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="sd"> Allow filters to be added post-generation on import.</span>
4677
+ <a id="__codelineno-0-670" name="__codelineno-0-670"></a>
4678
+ <a id="__codelineno-0-671" name="__codelineno-0-671"></a><span class="sd"> Will provide `&lt;field_name&gt;__&lt;lookup_expr&gt;` generation automagically.</span>
4679
+ <a id="__codelineno-0-672" name="__codelineno-0-672"></a><span class="sd"> &quot;&quot;&quot;</span>
4680
+ <a id="__codelineno-0-673" name="__codelineno-0-673"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">new_filter_field</span><span class="p">,</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">Filter</span><span class="p">):</span>
4681
+ <a id="__codelineno-0-674" name="__codelineno-0-674"></a> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Tried to add filter (</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">) which is not an instance of Django Filter&quot;</span><span class="p">)</span>
4682
+ <a id="__codelineno-0-675" name="__codelineno-0-675"></a>
4683
+ <a id="__codelineno-0-676" name="__codelineno-0-676"></a> <span class="k">if</span> <span class="n">new_filter_name</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">:</span>
4684
+ <a id="__codelineno-0-677" name="__codelineno-0-677"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
4685
+ <a id="__codelineno-0-678" name="__codelineno-0-678"></a> <span class="sa">f</span><span class="s2">&quot;There was a conflict with filter `</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">`, the custom filter was ignored.&quot;</span>
4686
+ <a id="__codelineno-0-679" name="__codelineno-0-679"></a> <span class="p">)</span>
4687
+ <a id="__codelineno-0-680" name="__codelineno-0-680"></a>
4688
+ <a id="__codelineno-0-681" name="__codelineno-0-681"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">[</span><span class="n">new_filter_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_filter_field</span>
4689
+ <a id="__codelineno-0-682" name="__codelineno-0-682"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
4690
+ <a id="__codelineno-0-683" name="__codelineno-0-683"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
4691
+ <a id="__codelineno-0-684" name="__codelineno-0-684"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
4692
+ <a id="__codelineno-0-685" name="__codelineno-0-685"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span><span class="n">filter_name</span><span class="o">=</span><span class="n">new_filter_name</span><span class="p">,</span> <span class="n">filter_field</span><span class="o">=</span><span class="n">new_filter_field</span><span class="p">)</span>
4693
+ <a id="__codelineno-0-686" name="__codelineno-0-686"></a> <span class="p">)</span>
4694
+ <a id="__codelineno-0-687" name="__codelineno-0-687"></a>
4695
+ <a id="__codelineno-0-688" name="__codelineno-0-688"></a> <span class="nd">@classmethod</span>
4696
+ <a id="__codelineno-0-689" name="__codelineno-0-689"></a> <span class="k">def</span> <span class="nf">get_fields</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
4697
+ <a id="__codelineno-0-690" name="__codelineno-0-690"></a> <span class="n">fields</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_fields</span><span class="p">()</span>
4698
+ <a id="__codelineno-0-691" name="__codelineno-0-691"></a> <span class="k">if</span> <span class="s2">&quot;id&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="n">fields</span> <span class="ow">and</span> <span class="p">(</span><span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">exclude</span> <span class="ow">is</span> <span class="kc">None</span> <span class="ow">or</span> <span class="s2">&quot;id&quot;</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">exclude</span><span class="p">):</span>
4699
+ <a id="__codelineno-0-692" name="__codelineno-0-692"></a> <span class="c1"># Add &quot;id&quot; as the first key in the `fields` OrderedDict</span>
4700
+ <a id="__codelineno-0-693" name="__codelineno-0-693"></a> <span class="n">fields</span> <span class="o">=</span> <span class="n">OrderedDict</span><span class="p">(</span><span class="nb">id</span><span class="o">=</span><span class="p">[</span><span class="n">django_filters</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_LOOKUP_EXPR</span><span class="p">],</span> <span class="o">**</span><span class="n">fields</span><span class="p">)</span>
4701
+ <a id="__codelineno-0-694" name="__codelineno-0-694"></a> <span class="k">return</span> <span class="n">fields</span>
4702
+ <a id="__codelineno-0-695" name="__codelineno-0-695"></a>
4703
+ <a id="__codelineno-0-696" name="__codelineno-0-696"></a> <span class="nd">@classmethod</span>
4704
+ <a id="__codelineno-0-697" name="__codelineno-0-697"></a> <span class="k">def</span> <span class="nf">get_filters</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
4705
+ <a id="__codelineno-0-698" name="__codelineno-0-698"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4706
+ <a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="sd"> Override filter generation to support dynamic lookup expressions for certain filter types.</span>
4707
+ <a id="__codelineno-0-700" name="__codelineno-0-700"></a><span class="sd"> &quot;&quot;&quot;</span>
4708
+ <a id="__codelineno-0-701" name="__codelineno-0-701"></a> <span class="n">filters</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_filters</span><span class="p">()</span>
4709
+ <a id="__codelineno-0-702" name="__codelineno-0-702"></a>
4710
+ <a id="__codelineno-0-703" name="__codelineno-0-703"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
4711
+ <a id="__codelineno-0-704" name="__codelineno-0-704"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
4712
+ <a id="__codelineno-0-705" name="__codelineno-0-705"></a> <span class="n">new_filters</span> <span class="o">=</span> <span class="p">{}</span>
4713
+ <a id="__codelineno-0-706" name="__codelineno-0-706"></a> <span class="k">for</span> <span class="n">existing_filter_name</span><span class="p">,</span> <span class="n">existing_filter</span> <span class="ow">in</span> <span class="n">filters</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4714
+ <a id="__codelineno-0-707" name="__codelineno-0-707"></a> <span class="n">new_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
4715
+ <a id="__codelineno-0-708" name="__codelineno-0-708"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span>
4716
+ <a id="__codelineno-0-709" name="__codelineno-0-709"></a> <span class="n">filter_name</span><span class="o">=</span><span class="n">existing_filter_name</span><span class="p">,</span>
4717
+ <a id="__codelineno-0-710" name="__codelineno-0-710"></a> <span class="n">filter_field</span><span class="o">=</span><span class="n">existing_filter</span><span class="p">,</span>
4718
+ <a id="__codelineno-0-711" name="__codelineno-0-711"></a> <span class="p">)</span>
4719
+ <a id="__codelineno-0-712" name="__codelineno-0-712"></a> <span class="p">)</span>
4720
+ <a id="__codelineno-0-713" name="__codelineno-0-713"></a>
4721
+ <a id="__codelineno-0-714" name="__codelineno-0-714"></a> <span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">new_filters</span><span class="p">)</span>
4722
+ <a id="__codelineno-0-715" name="__codelineno-0-715"></a>
4723
+ <a id="__codelineno-0-716" name="__codelineno-0-716"></a> <span class="k">return</span> <span class="n">filters</span>
4724
+ <a id="__codelineno-0-717" name="__codelineno-0-717"></a>
4725
+ <a id="__codelineno-0-718" name="__codelineno-0-718"></a> <span class="nd">@classmethod</span>
4726
+ <a id="__codelineno-0-719" name="__codelineno-0-719"></a> <span class="k">def</span> <span class="nf">filter_for_lookup</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">):</span>
4727
+ <a id="__codelineno-0-720" name="__codelineno-0-720"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Override filter_for_lookup method to set ChoiceField Filter to MultipleChoiceFilter.</span>
4728
+ <a id="__codelineno-0-721" name="__codelineno-0-721"></a>
4729
+ <a id="__codelineno-0-722" name="__codelineno-0-722"></a><span class="sd"> Note: Any CharField or IntegerField with choices set is a ChoiceField.</span>
4730
+ <a id="__codelineno-0-723" name="__codelineno-0-723"></a><span class="sd"> &quot;&quot;&quot;</span>
4731
+ <a id="__codelineno-0-724" name="__codelineno-0-724"></a> <span class="k">if</span> <span class="n">lookup_type</span> <span class="o">==</span> <span class="s2">&quot;exact&quot;</span> <span class="ow">and</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;choices&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
4732
+ <a id="__codelineno-0-725" name="__codelineno-0-725"></a> <span class="k">return</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">MultipleChoiceFilter</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;choices&quot;</span><span class="p">:</span> <span class="n">field</span><span class="o">.</span><span class="n">choices</span><span class="p">}</span>
4733
+ <a id="__codelineno-0-726" name="__codelineno-0-726"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">filter_for_lookup</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">)</span>
4734
+ <a id="__codelineno-0-727" name="__codelineno-0-727"></a>
4735
+ <a id="__codelineno-0-728" name="__codelineno-0-728"></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">data</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">queryset</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">request</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
4736
+ <a id="__codelineno-0-729" name="__codelineno-0-729"></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">data</span><span class="p">,</span> <span class="n">queryset</span><span class="p">,</span> <span class="n">request</span><span class="o">=</span><span class="n">request</span><span class="p">,</span> <span class="n">prefix</span><span class="o">=</span><span class="n">prefix</span><span class="p">)</span>
4737
+ <a id="__codelineno-0-730" name="__codelineno-0-730"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="kc">None</span>
4738
+ <a id="__codelineno-0-731" name="__codelineno-0-731"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span> <span class="o">=</span> <span class="kc">None</span>
4739
+ <a id="__codelineno-0-732" name="__codelineno-0-732"></a>
4740
+ <a id="__codelineno-0-733" name="__codelineno-0-733"></a> <span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4741
+ <a id="__codelineno-0-734" name="__codelineno-0-734"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Extend FilterSet.is_valid() to potentially enforce settings.STRICT_FILTERING.&quot;&quot;&quot;</span>
4742
+ <a id="__codelineno-0-735" name="__codelineno-0-735"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4743
+ <a id="__codelineno-0-736" name="__codelineno-0-736"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span>
4744
+ <a id="__codelineno-0-737" name="__codelineno-0-737"></a> <span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">STRICT_FILTERING</span><span class="p">:</span>
4745
+ <a id="__codelineno-0-738" name="__codelineno-0-738"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">and</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="o">.</span><span class="n">issubset</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
4746
+ <a id="__codelineno-0-739" name="__codelineno-0-739"></a> <span class="k">else</span><span class="p">:</span>
4747
+ <a id="__codelineno-0-740" name="__codelineno-0-740"></a> <span class="c1"># Trigger warning logs associated with generating self.errors</span>
4748
+ <a id="__codelineno-0-741" name="__codelineno-0-741"></a> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span>
4749
+ <a id="__codelineno-0-742" name="__codelineno-0-742"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span>
4750
+ <a id="__codelineno-0-743" name="__codelineno-0-743"></a>
4751
+ <a id="__codelineno-0-744" name="__codelineno-0-744"></a> <span class="nd">@property</span>
4752
+ <a id="__codelineno-0-745" name="__codelineno-0-745"></a> <span class="k">def</span> <span class="nf">errors</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
4753
+ <a id="__codelineno-0-746" name="__codelineno-0-746"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Extend FilterSet.errors to potentially include additional errors from settings.STRICT_FILTERING.&quot;&quot;&quot;</span>
4754
+ <a id="__codelineno-0-747" name="__codelineno-0-747"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4755
+ <a id="__codelineno-0-748" name="__codelineno-0-748"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span> <span class="o">=</span> <span class="n">ErrorDict</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">errors</span><span class="p">)</span>
4756
+ <a id="__codelineno-0-749" name="__codelineno-0-749"></a> <span class="k">for</span> <span class="n">extra_key</span> <span class="ow">in</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="o">.</span><span class="n">difference</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">keys</span><span class="p">()):</span>
4757
+ <a id="__codelineno-0-750" name="__codelineno-0-750"></a> <span class="c1"># If a given field was invalid, it will be omitted from cleaned_data; don&#39;t report extra errors</span>
4758
+ <a id="__codelineno-0-751" name="__codelineno-0-751"></a> <span class="k">if</span> <span class="n">extra_key</span> <span class="ow">not</span> <span class="ow">in</span> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span><span class="p">:</span>
4759
+ <a id="__codelineno-0-752" name="__codelineno-0-752"></a> <span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">STRICT_FILTERING</span><span class="p">:</span>
4760
+ <a id="__codelineno-0-753" name="__codelineno-0-753"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">extra_key</span><span class="p">,</span> <span class="n">ErrorList</span><span class="p">())</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="s2">&quot;Unknown filter field&quot;</span><span class="p">)</span>
4761
+ <a id="__codelineno-0-754" name="__codelineno-0-754"></a> <span class="k">else</span><span class="p">:</span>
4762
+ <a id="__codelineno-0-755" name="__codelineno-0-755"></a> <span class="n">logger</span><span class="o">.</span><span class="n">warning</span><span class="p">(</span><span class="s1">&#39;</span><span class="si">%s</span><span class="s1">: Unknown filter field &quot;</span><span class="si">%s</span><span class="s1">&quot;&#39;</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="p">,</span> <span class="n">extra_key</span><span class="p">)</span>
4763
+ <a id="__codelineno-0-756" name="__codelineno-0-756"></a>
4764
+ <a id="__codelineno-0-757" name="__codelineno-0-757"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_errors</span>
3597
4765
  </code></pre></div></td></tr></table></div>
3598
4766
  </details>
3599
4767
 
@@ -3651,7 +4819,8 @@
3651
4819
 
3652
4820
  <details class="quote">
3653
4821
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3654
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-667">667</a></span>
4822
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-666">666</a></span>
4823
+ <span class="normal"><a href="#__codelineno-0-667">667</a></span>
3655
4824
  <span class="normal"><a href="#__codelineno-0-668">668</a></span>
3656
4825
  <span class="normal"><a href="#__codelineno-0-669">669</a></span>
3657
4826
  <span class="normal"><a href="#__codelineno-0-670">670</a></span>
@@ -3670,28 +4839,27 @@
3670
4839
  <span class="normal"><a href="#__codelineno-0-683">683</a></span>
3671
4840
  <span class="normal"><a href="#__codelineno-0-684">684</a></span>
3672
4841
  <span class="normal"><a href="#__codelineno-0-685">685</a></span>
3673
- <span class="normal"><a href="#__codelineno-0-686">686</a></span>
3674
- <span class="normal"><a href="#__codelineno-0-687">687</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-667" name="__codelineno-0-667"></a><span class="nd">@classmethod</span>
3675
- <a id="__codelineno-0-668" name="__codelineno-0-668"></a><span class="k">def</span> <span class="nf">add_filter</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">new_filter_name</span><span class="p">,</span> <span class="n">new_filter_field</span><span class="p">):</span>
3676
- <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3677
- <a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="sd"> Allow filters to be added post-generation on import.</span>
3678
- <a id="__codelineno-0-671" name="__codelineno-0-671"></a>
3679
- <a id="__codelineno-0-672" name="__codelineno-0-672"></a><span class="sd"> Will provide `&lt;field_name&gt;__&lt;lookup_expr&gt;` generation automagically.</span>
3680
- <a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> &quot;&quot;&quot;</span>
3681
- <a id="__codelineno-0-674" name="__codelineno-0-674"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">new_filter_field</span><span class="p">,</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">Filter</span><span class="p">):</span>
3682
- <a id="__codelineno-0-675" name="__codelineno-0-675"></a> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Tried to add filter (</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">) which is not an instance of Django Filter&quot;</span><span class="p">)</span>
3683
- <a id="__codelineno-0-676" name="__codelineno-0-676"></a>
3684
- <a id="__codelineno-0-677" name="__codelineno-0-677"></a> <span class="k">if</span> <span class="n">new_filter_name</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">:</span>
3685
- <a id="__codelineno-0-678" name="__codelineno-0-678"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3686
- <a id="__codelineno-0-679" name="__codelineno-0-679"></a> <span class="sa">f</span><span class="s2">&quot;There was a conflict with filter `</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">`, the custom filter was ignored.&quot;</span>
3687
- <a id="__codelineno-0-680" name="__codelineno-0-680"></a> <span class="p">)</span>
3688
- <a id="__codelineno-0-681" name="__codelineno-0-681"></a>
3689
- <a id="__codelineno-0-682" name="__codelineno-0-682"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">[</span><span class="n">new_filter_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_filter_field</span>
3690
- <a id="__codelineno-0-683" name="__codelineno-0-683"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
3691
- <a id="__codelineno-0-684" name="__codelineno-0-684"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
3692
- <a id="__codelineno-0-685" name="__codelineno-0-685"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
3693
- <a id="__codelineno-0-686" name="__codelineno-0-686"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span><span class="n">filter_name</span><span class="o">=</span><span class="n">new_filter_name</span><span class="p">,</span> <span class="n">filter_field</span><span class="o">=</span><span class="n">new_filter_field</span><span class="p">)</span>
3694
- <a id="__codelineno-0-687" name="__codelineno-0-687"></a> <span class="p">)</span>
4842
+ <span class="normal"><a href="#__codelineno-0-686">686</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-666" name="__codelineno-0-666"></a><span class="nd">@classmethod</span>
4843
+ <a id="__codelineno-0-667" name="__codelineno-0-667"></a><span class="k">def</span> <span class="nf">add_filter</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">new_filter_name</span><span class="p">,</span> <span class="n">new_filter_field</span><span class="p">):</span>
4844
+ <a id="__codelineno-0-668" name="__codelineno-0-668"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4845
+ <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="sd"> Allow filters to be added post-generation on import.</span>
4846
+ <a id="__codelineno-0-670" name="__codelineno-0-670"></a>
4847
+ <a id="__codelineno-0-671" name="__codelineno-0-671"></a><span class="sd"> Will provide `&lt;field_name&gt;__&lt;lookup_expr&gt;` generation automagically.</span>
4848
+ <a id="__codelineno-0-672" name="__codelineno-0-672"></a><span class="sd"> &quot;&quot;&quot;</span>
4849
+ <a id="__codelineno-0-673" name="__codelineno-0-673"></a> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">new_filter_field</span><span class="p">,</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">Filter</span><span class="p">):</span>
4850
+ <a id="__codelineno-0-674" name="__codelineno-0-674"></a> <span class="k">raise</span> <span class="ne">TypeError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Tried to add filter (</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">) which is not an instance of Django Filter&quot;</span><span class="p">)</span>
4851
+ <a id="__codelineno-0-675" name="__codelineno-0-675"></a>
4852
+ <a id="__codelineno-0-676" name="__codelineno-0-676"></a> <span class="k">if</span> <span class="n">new_filter_name</span> <span class="ow">in</span> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">:</span>
4853
+ <a id="__codelineno-0-677" name="__codelineno-0-677"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
4854
+ <a id="__codelineno-0-678" name="__codelineno-0-678"></a> <span class="sa">f</span><span class="s2">&quot;There was a conflict with filter `</span><span class="si">{</span><span class="n">new_filter_name</span><span class="si">}</span><span class="s2">`, the custom filter was ignored.&quot;</span>
4855
+ <a id="__codelineno-0-679" name="__codelineno-0-679"></a> <span class="p">)</span>
4856
+ <a id="__codelineno-0-680" name="__codelineno-0-680"></a>
4857
+ <a id="__codelineno-0-681" name="__codelineno-0-681"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="p">[</span><span class="n">new_filter_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">new_filter_field</span>
4858
+ <a id="__codelineno-0-682" name="__codelineno-0-682"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
4859
+ <a id="__codelineno-0-683" name="__codelineno-0-683"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
4860
+ <a id="__codelineno-0-684" name="__codelineno-0-684"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">base_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
4861
+ <a id="__codelineno-0-685" name="__codelineno-0-685"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span><span class="n">filter_name</span><span class="o">=</span><span class="n">new_filter_name</span><span class="p">,</span> <span class="n">filter_field</span><span class="o">=</span><span class="n">new_filter_field</span><span class="p">)</span>
4862
+ <a id="__codelineno-0-686" name="__codelineno-0-686"></a> <span class="p">)</span>
3695
4863
  </code></pre></div></td></tr></table></div>
3696
4864
  </details>
3697
4865
  </div>
@@ -3719,23 +4887,23 @@
3719
4887
 
3720
4888
  <details class="quote">
3721
4889
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3722
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-719">719</a></span>
4890
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-718">718</a></span>
4891
+ <span class="normal"><a href="#__codelineno-0-719">719</a></span>
3723
4892
  <span class="normal"><a href="#__codelineno-0-720">720</a></span>
3724
4893
  <span class="normal"><a href="#__codelineno-0-721">721</a></span>
3725
4894
  <span class="normal"><a href="#__codelineno-0-722">722</a></span>
3726
4895
  <span class="normal"><a href="#__codelineno-0-723">723</a></span>
3727
4896
  <span class="normal"><a href="#__codelineno-0-724">724</a></span>
3728
4897
  <span class="normal"><a href="#__codelineno-0-725">725</a></span>
3729
- <span class="normal"><a href="#__codelineno-0-726">726</a></span>
3730
- <span class="normal"><a href="#__codelineno-0-727">727</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-719" name="__codelineno-0-719"></a><span class="nd">@classmethod</span>
3731
- <a id="__codelineno-0-720" name="__codelineno-0-720"></a><span class="k">def</span> <span class="nf">filter_for_lookup</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">):</span>
3732
- <a id="__codelineno-0-721" name="__codelineno-0-721"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Override filter_for_lookup method to set ChoiceField Filter to MultipleChoiceFilter.</span>
3733
- <a id="__codelineno-0-722" name="__codelineno-0-722"></a>
3734
- <a id="__codelineno-0-723" name="__codelineno-0-723"></a><span class="sd"> Note: Any CharField or IntegerField with choices set is a ChoiceField.</span>
3735
- <a id="__codelineno-0-724" name="__codelineno-0-724"></a><span class="sd"> &quot;&quot;&quot;</span>
3736
- <a id="__codelineno-0-725" name="__codelineno-0-725"></a> <span class="k">if</span> <span class="n">lookup_type</span> <span class="o">==</span> <span class="s2">&quot;exact&quot;</span> <span class="ow">and</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;choices&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
3737
- <a id="__codelineno-0-726" name="__codelineno-0-726"></a> <span class="k">return</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">MultipleChoiceFilter</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;choices&quot;</span><span class="p">:</span> <span class="n">field</span><span class="o">.</span><span class="n">choices</span><span class="p">}</span>
3738
- <a id="__codelineno-0-727" name="__codelineno-0-727"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">filter_for_lookup</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">)</span>
4898
+ <span class="normal"><a href="#__codelineno-0-726">726</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-718" name="__codelineno-0-718"></a><span class="nd">@classmethod</span>
4899
+ <a id="__codelineno-0-719" name="__codelineno-0-719"></a><span class="k">def</span> <span class="nf">filter_for_lookup</span><span class="p">(</span><span class="bp">cls</span><span class="p">,</span> <span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">):</span>
4900
+ <a id="__codelineno-0-720" name="__codelineno-0-720"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Override filter_for_lookup method to set ChoiceField Filter to MultipleChoiceFilter.</span>
4901
+ <a id="__codelineno-0-721" name="__codelineno-0-721"></a>
4902
+ <a id="__codelineno-0-722" name="__codelineno-0-722"></a><span class="sd"> Note: Any CharField or IntegerField with choices set is a ChoiceField.</span>
4903
+ <a id="__codelineno-0-723" name="__codelineno-0-723"></a><span class="sd"> &quot;&quot;&quot;</span>
4904
+ <a id="__codelineno-0-724" name="__codelineno-0-724"></a> <span class="k">if</span> <span class="n">lookup_type</span> <span class="o">==</span> <span class="s2">&quot;exact&quot;</span> <span class="ow">and</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="s2">&quot;choices&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">):</span>
4905
+ <a id="__codelineno-0-725" name="__codelineno-0-725"></a> <span class="k">return</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">MultipleChoiceFilter</span><span class="p">,</span> <span class="p">{</span><span class="s2">&quot;choices&quot;</span><span class="p">:</span> <span class="n">field</span><span class="o">.</span><span class="n">choices</span><span class="p">}</span>
4906
+ <a id="__codelineno-0-726" name="__codelineno-0-726"></a> <span class="k">return</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">filter_for_lookup</span><span class="p">(</span><span class="n">field</span><span class="p">,</span> <span class="n">lookup_type</span><span class="p">)</span>
3739
4907
  </code></pre></div></td></tr></table></div>
3740
4908
  </details>
3741
4909
  </div>
@@ -3762,7 +4930,8 @@
3762
4930
 
3763
4931
  <details class="quote">
3764
4932
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3765
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-697">697</a></span>
4933
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-696">696</a></span>
4934
+ <span class="normal"><a href="#__codelineno-0-697">697</a></span>
3766
4935
  <span class="normal"><a href="#__codelineno-0-698">698</a></span>
3767
4936
  <span class="normal"><a href="#__codelineno-0-699">699</a></span>
3768
4937
  <span class="normal"><a href="#__codelineno-0-700">700</a></span>
@@ -3781,28 +4950,27 @@
3781
4950
  <span class="normal"><a href="#__codelineno-0-713">713</a></span>
3782
4951
  <span class="normal"><a href="#__codelineno-0-714">714</a></span>
3783
4952
  <span class="normal"><a href="#__codelineno-0-715">715</a></span>
3784
- <span class="normal"><a href="#__codelineno-0-716">716</a></span>
3785
- <span class="normal"><a href="#__codelineno-0-717">717</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-697" name="__codelineno-0-697"></a><span class="nd">@classmethod</span>
3786
- <a id="__codelineno-0-698" name="__codelineno-0-698"></a><span class="k">def</span> <span class="nf">get_filters</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
3787
- <a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3788
- <a id="__codelineno-0-700" name="__codelineno-0-700"></a><span class="sd"> Override filter generation to support dynamic lookup expressions for certain filter types.</span>
3789
- <a id="__codelineno-0-701" name="__codelineno-0-701"></a><span class="sd"> &quot;&quot;&quot;</span>
3790
- <a id="__codelineno-0-702" name="__codelineno-0-702"></a> <span class="n">filters</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_filters</span><span class="p">()</span>
3791
- <a id="__codelineno-0-703" name="__codelineno-0-703"></a>
3792
- <a id="__codelineno-0-704" name="__codelineno-0-704"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
3793
- <a id="__codelineno-0-705" name="__codelineno-0-705"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
3794
- <a id="__codelineno-0-706" name="__codelineno-0-706"></a> <span class="n">new_filters</span> <span class="o">=</span> <span class="p">{}</span>
3795
- <a id="__codelineno-0-707" name="__codelineno-0-707"></a> <span class="k">for</span> <span class="n">existing_filter_name</span><span class="p">,</span> <span class="n">existing_filter</span> <span class="ow">in</span> <span class="n">filters</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
3796
- <a id="__codelineno-0-708" name="__codelineno-0-708"></a> <span class="n">new_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
3797
- <a id="__codelineno-0-709" name="__codelineno-0-709"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span>
3798
- <a id="__codelineno-0-710" name="__codelineno-0-710"></a> <span class="n">filter_name</span><span class="o">=</span><span class="n">existing_filter_name</span><span class="p">,</span>
3799
- <a id="__codelineno-0-711" name="__codelineno-0-711"></a> <span class="n">filter_field</span><span class="o">=</span><span class="n">existing_filter</span><span class="p">,</span>
3800
- <a id="__codelineno-0-712" name="__codelineno-0-712"></a> <span class="p">)</span>
3801
- <a id="__codelineno-0-713" name="__codelineno-0-713"></a> <span class="p">)</span>
3802
- <a id="__codelineno-0-714" name="__codelineno-0-714"></a>
3803
- <a id="__codelineno-0-715" name="__codelineno-0-715"></a> <span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">new_filters</span><span class="p">)</span>
3804
- <a id="__codelineno-0-716" name="__codelineno-0-716"></a>
3805
- <a id="__codelineno-0-717" name="__codelineno-0-717"></a> <span class="k">return</span> <span class="n">filters</span>
4953
+ <span class="normal"><a href="#__codelineno-0-716">716</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-696" name="__codelineno-0-696"></a><span class="nd">@classmethod</span>
4954
+ <a id="__codelineno-0-697" name="__codelineno-0-697"></a><span class="k">def</span> <span class="nf">get_filters</span><span class="p">(</span><span class="bp">cls</span><span class="p">):</span>
4955
+ <a id="__codelineno-0-698" name="__codelineno-0-698"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4956
+ <a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="sd"> Override filter generation to support dynamic lookup expressions for certain filter types.</span>
4957
+ <a id="__codelineno-0-700" name="__codelineno-0-700"></a><span class="sd"> &quot;&quot;&quot;</span>
4958
+ <a id="__codelineno-0-701" name="__codelineno-0-701"></a> <span class="n">filters</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">get_filters</span><span class="p">()</span>
4959
+ <a id="__codelineno-0-702" name="__codelineno-0-702"></a>
4960
+ <a id="__codelineno-0-703" name="__codelineno-0-703"></a> <span class="c1"># django-filters has no concept of &quot;abstract&quot; filtersets, so we have to fake it</span>
4961
+ <a id="__codelineno-0-704" name="__codelineno-0-704"></a> <span class="k">if</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
4962
+ <a id="__codelineno-0-705" name="__codelineno-0-705"></a> <span class="n">new_filters</span> <span class="o">=</span> <span class="p">{}</span>
4963
+ <a id="__codelineno-0-706" name="__codelineno-0-706"></a> <span class="k">for</span> <span class="n">existing_filter_name</span><span class="p">,</span> <span class="n">existing_filter</span> <span class="ow">in</span> <span class="n">filters</span><span class="o">.</span><span class="n">items</span><span class="p">():</span>
4964
+ <a id="__codelineno-0-707" name="__codelineno-0-707"></a> <span class="n">new_filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
4965
+ <a id="__codelineno-0-708" name="__codelineno-0-708"></a> <span class="bp">cls</span><span class="o">.</span><span class="n">_generate_lookup_expression_filters</span><span class="p">(</span>
4966
+ <a id="__codelineno-0-709" name="__codelineno-0-709"></a> <span class="n">filter_name</span><span class="o">=</span><span class="n">existing_filter_name</span><span class="p">,</span>
4967
+ <a id="__codelineno-0-710" name="__codelineno-0-710"></a> <span class="n">filter_field</span><span class="o">=</span><span class="n">existing_filter</span><span class="p">,</span>
4968
+ <a id="__codelineno-0-711" name="__codelineno-0-711"></a> <span class="p">)</span>
4969
+ <a id="__codelineno-0-712" name="__codelineno-0-712"></a> <span class="p">)</span>
4970
+ <a id="__codelineno-0-713" name="__codelineno-0-713"></a>
4971
+ <a id="__codelineno-0-714" name="__codelineno-0-714"></a> <span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">new_filters</span><span class="p">)</span>
4972
+ <a id="__codelineno-0-715" name="__codelineno-0-715"></a>
4973
+ <a id="__codelineno-0-716" name="__codelineno-0-716"></a> <span class="k">return</span> <span class="n">filters</span>
3806
4974
  </code></pre></div></td></tr></table></div>
3807
4975
  </details>
3808
4976
  </div>
@@ -3825,7 +4993,8 @@
3825
4993
 
3826
4994
  <details class="quote">
3827
4995
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3828
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-734">734</a></span>
4996
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-733">733</a></span>
4997
+ <span class="normal"><a href="#__codelineno-0-734">734</a></span>
3829
4998
  <span class="normal"><a href="#__codelineno-0-735">735</a></span>
3830
4999
  <span class="normal"><a href="#__codelineno-0-736">736</a></span>
3831
5000
  <span class="normal"><a href="#__codelineno-0-737">737</a></span>
@@ -3833,17 +5002,16 @@
3833
5002
  <span class="normal"><a href="#__codelineno-0-739">739</a></span>
3834
5003
  <span class="normal"><a href="#__codelineno-0-740">740</a></span>
3835
5004
  <span class="normal"><a href="#__codelineno-0-741">741</a></span>
3836
- <span class="normal"><a href="#__codelineno-0-742">742</a></span>
3837
- <span class="normal"><a href="#__codelineno-0-743">743</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-734" name="__codelineno-0-734"></a><span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
3838
- <a id="__codelineno-0-735" name="__codelineno-0-735"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Extend FilterSet.is_valid() to potentially enforce settings.STRICT_FILTERING.&quot;&quot;&quot;</span>
3839
- <a id="__codelineno-0-736" name="__codelineno-0-736"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
3840
- <a id="__codelineno-0-737" name="__codelineno-0-737"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span>
3841
- <a id="__codelineno-0-738" name="__codelineno-0-738"></a> <span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">STRICT_FILTERING</span><span class="p">:</span>
3842
- <a id="__codelineno-0-739" name="__codelineno-0-739"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">and</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="o">.</span><span class="n">issubset</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
3843
- <a id="__codelineno-0-740" name="__codelineno-0-740"></a> <span class="k">else</span><span class="p">:</span>
3844
- <a id="__codelineno-0-741" name="__codelineno-0-741"></a> <span class="c1"># Trigger warning logs associated with generating self.errors</span>
3845
- <a id="__codelineno-0-742" name="__codelineno-0-742"></a> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span>
3846
- <a id="__codelineno-0-743" name="__codelineno-0-743"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span>
5005
+ <span class="normal"><a href="#__codelineno-0-742">742</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-733" name="__codelineno-0-733"></a><span class="k">def</span> <span class="nf">is_valid</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
5006
+ <a id="__codelineno-0-734" name="__codelineno-0-734"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Extend FilterSet.is_valid() to potentially enforce settings.STRICT_FILTERING.&quot;&quot;&quot;</span>
5007
+ <a id="__codelineno-0-735" name="__codelineno-0-735"></a> <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
5008
+ <a id="__codelineno-0-736" name="__codelineno-0-736"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="n">is_valid</span><span class="p">()</span>
5009
+ <a id="__codelineno-0-737" name="__codelineno-0-737"></a> <span class="k">if</span> <span class="n">settings</span><span class="o">.</span><span class="n">STRICT_FILTERING</span><span class="p">:</span>
5010
+ <a id="__codelineno-0-738" name="__codelineno-0-738"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span> <span class="ow">and</span> <span class="nb">set</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span><span class="o">.</span><span class="n">issubset</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">form</span><span class="o">.</span><span class="n">cleaned_data</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
5011
+ <a id="__codelineno-0-739" name="__codelineno-0-739"></a> <span class="k">else</span><span class="p">:</span>
5012
+ <a id="__codelineno-0-740" name="__codelineno-0-740"></a> <span class="c1"># Trigger warning logs associated with generating self.errors</span>
5013
+ <a id="__codelineno-0-741" name="__codelineno-0-741"></a> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span>
5014
+ <a id="__codelineno-0-742" name="__codelineno-0-742"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">_is_valid</span>
3847
5015
  </code></pre></div></td></tr></table></div>
3848
5016
  </details>
3849
5017
  </div>
@@ -4089,21 +5257,21 @@ extra lookup expressions on supported CustomField types.</p>
4089
5257
 
4090
5258
  <details class="quote">
4091
5259
  <summary>Source code in <code>nautobot/extras/plugins/__init__.py</code></summary>
4092
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-456">456</a></span>
4093
- <span class="normal"><a href="#__codelineno-0-457">457</a></span>
4094
- <span class="normal"><a href="#__codelineno-0-458">458</a></span>
4095
- <span class="normal"><a href="#__codelineno-0-459">459</a></span>
4096
- <span class="normal"><a href="#__codelineno-0-460">460</a></span>
4097
- <span class="normal"><a href="#__codelineno-0-461">461</a></span>
4098
- <span class="normal"><a href="#__codelineno-0-462">462</a></span>
4099
- <span class="normal"><a href="#__codelineno-0-463">463</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-456" name="__codelineno-0-456"></a><span class="k">class</span> <span class="nc">FilterExtension</span><span class="p">:</span>
4100
- <a id="__codelineno-0-457" name="__codelineno-0-457"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Class that may be returned by a registered Filter Extension function.&quot;&quot;&quot;</span>
4101
- <a id="__codelineno-0-458" name="__codelineno-0-458"></a>
4102
- <a id="__codelineno-0-459" name="__codelineno-0-459"></a> <span class="n">model</span> <span class="o">=</span> <span class="kc">None</span>
4103
- <a id="__codelineno-0-460" name="__codelineno-0-460"></a>
4104
- <a id="__codelineno-0-461" name="__codelineno-0-461"></a> <span class="n">filterset_fields</span> <span class="o">=</span> <span class="p">{}</span>
4105
- <a id="__codelineno-0-462" name="__codelineno-0-462"></a>
4106
- <a id="__codelineno-0-463" name="__codelineno-0-463"></a> <span class="n">filterform_fields</span> <span class="o">=</span> <span class="p">{}</span>
5260
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-446">446</a></span>
5261
+ <span class="normal"><a href="#__codelineno-0-447">447</a></span>
5262
+ <span class="normal"><a href="#__codelineno-0-448">448</a></span>
5263
+ <span class="normal"><a href="#__codelineno-0-449">449</a></span>
5264
+ <span class="normal"><a href="#__codelineno-0-450">450</a></span>
5265
+ <span class="normal"><a href="#__codelineno-0-451">451</a></span>
5266
+ <span class="normal"><a href="#__codelineno-0-452">452</a></span>
5267
+ <span class="normal"><a href="#__codelineno-0-453">453</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-446" name="__codelineno-0-446"></a><span class="k">class</span> <span class="nc">FilterExtension</span><span class="p">:</span>
5268
+ <a id="__codelineno-0-447" name="__codelineno-0-447"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;Class that may be returned by a registered Filter Extension function.&quot;&quot;&quot;</span>
5269
+ <a id="__codelineno-0-448" name="__codelineno-0-448"></a>
5270
+ <a id="__codelineno-0-449" name="__codelineno-0-449"></a> <span class="n">model</span> <span class="o">=</span> <span class="kc">None</span>
5271
+ <a id="__codelineno-0-450" name="__codelineno-0-450"></a>
5272
+ <a id="__codelineno-0-451" name="__codelineno-0-451"></a> <span class="n">filterset_fields</span> <span class="o">=</span> <span class="p">{}</span>
5273
+ <a id="__codelineno-0-452" name="__codelineno-0-452"></a>
5274
+ <a id="__codelineno-0-453" name="__codelineno-0-453"></a> <span class="n">filterform_fields</span> <span class="o">=</span> <span class="p">{}</span>
4107
5275
  </code></pre></div></td></tr></table></div>
4108
5276
  </details>
4109
5277
 
@@ -4150,7 +5318,8 @@ keyword argument on filter initialization (defaults to <code>slug</code>).</p>
4150
5318
 
4151
5319
  <details class="quote">
4152
5320
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4153
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-390">390</a></span>
5321
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-389">389</a></span>
5322
+ <span class="normal"><a href="#__codelineno-0-390">390</a></span>
4154
5323
  <span class="normal"><a href="#__codelineno-0-391">391</a></span>
4155
5324
  <span class="normal"><a href="#__codelineno-0-392">392</a></span>
4156
5325
  <span class="normal"><a href="#__codelineno-0-393">393</a></span>
@@ -4199,58 +5368,57 @@ keyword argument on filter initialization (defaults to <code>slug</code>).</p>
4199
5368
  <span class="normal"><a href="#__codelineno-0-436">436</a></span>
4200
5369
  <span class="normal"><a href="#__codelineno-0-437">437</a></span>
4201
5370
  <span class="normal"><a href="#__codelineno-0-438">438</a></span>
4202
- <span class="normal"><a href="#__codelineno-0-439">439</a></span>
4203
- <span class="normal"><a href="#__codelineno-0-440">440</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-390" name="__codelineno-0-390"></a><span class="nd">@extend_schema_field</span><span class="p">(</span><span class="n">OpenApiTypes</span><span class="o">.</span><span class="n">STR</span><span class="p">)</span>
4204
- <a id="__codelineno-0-391" name="__codelineno-0-391"></a><span class="k">class</span> <span class="nc">NaturalKeyOrPKMultipleChoiceFilter</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">ModelMultipleChoiceFilter</span><span class="p">):</span>
4205
- <a id="__codelineno-0-392" name="__codelineno-0-392"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4206
- <a id="__codelineno-0-393" name="__codelineno-0-393"></a><span class="sd"> Filter that supports filtering on values matching the `pk` field and another</span>
4207
- <a id="__codelineno-0-394" name="__codelineno-0-394"></a><span class="sd"> field of a foreign-key related object. The desired field is set using the `to_field_name`</span>
4208
- <a id="__codelineno-0-395" name="__codelineno-0-395"></a><span class="sd"> keyword argument on filter initialization (defaults to `slug`).</span>
4209
- <a id="__codelineno-0-396" name="__codelineno-0-396"></a><span class="sd"> &quot;&quot;&quot;</span>
4210
- <a id="__codelineno-0-397" name="__codelineno-0-397"></a>
4211
- <a id="__codelineno-0-398" name="__codelineno-0-398"></a> <span class="n">field_class</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">MultiMatchModelMultipleChoiceField</span>
4212
- <a id="__codelineno-0-399" name="__codelineno-0-399"></a>
4213
- <a id="__codelineno-0-400" name="__codelineno-0-400"></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>
4214
- <a id="__codelineno-0-401" name="__codelineno-0-401"></a> <span class="bp">self</span><span class="o">.</span><span class="n">natural_key</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s2">&quot;to_field_name&quot;</span><span class="p">,</span> <span class="s2">&quot;slug&quot;</span><span class="p">)</span>
4215
- <a id="__codelineno-0-402" name="__codelineno-0-402"></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>
4216
- <a id="__codelineno-0-403" name="__codelineno-0-403"></a>
4217
- <a id="__codelineno-0-404" name="__codelineno-0-404"></a> <span class="k">def</span> <span class="nf">get_filter_predicate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
4218
- <a id="__codelineno-0-405" name="__codelineno-0-405"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4219
- <a id="__codelineno-0-406" name="__codelineno-0-406"></a><span class="sd"> Override base filter behavior to force the filter to use the `pk` field instead of</span>
4220
- <a id="__codelineno-0-407" name="__codelineno-0-407"></a><span class="sd"> the natural key in the generated filter.</span>
4221
- <a id="__codelineno-0-408" name="__codelineno-0-408"></a><span class="sd"> &quot;&quot;&quot;</span>
4222
- <a id="__codelineno-0-409" name="__codelineno-0-409"></a>
4223
- <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="c1"># Null value filtering</span>
4224
- <a id="__codelineno-0-411" name="__codelineno-0-411"></a> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4225
- <a id="__codelineno-0-412" name="__codelineno-0-412"></a> <span class="k">return</span> <span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__isnull&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
4226
- <a id="__codelineno-0-413" name="__codelineno-0-413"></a>
4227
- <a id="__codelineno-0-414" name="__codelineno-0-414"></a> <span class="c1"># If value is a model instance, stringify it to a pk.</span>
4228
- <a id="__codelineno-0-415" name="__codelineno-0-415"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
4229
- <a id="__codelineno-0-416" name="__codelineno-0-416"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Model instance detected. Casting to a PK.&quot;</span><span class="p">)</span>
4230
- <a id="__codelineno-0-417" name="__codelineno-0-417"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
4231
- <a id="__codelineno-0-418" name="__codelineno-0-418"></a>
4232
- <a id="__codelineno-0-419" name="__codelineno-0-419"></a> <span class="c1"># Try to cast the value to a UUID and set `is_pk` boolean.</span>
4233
- <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="k">try</span><span class="p">:</span>
4234
- <a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="n">uuid</span><span class="o">.</span><span class="n">UUID</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
4235
- <a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="k">except</span> <span class="p">(</span><span class="ne">AttributeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="ne">ValueError</span><span class="p">):</span>
4236
- <a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Non-UUID value detected: Filtering using natural key&quot;</span><span class="p">)</span>
4237
- <a id="__codelineno-0-424" name="__codelineno-0-424"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">False</span>
4238
- <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="k">else</span><span class="p">:</span>
4239
- <a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="c1"># Cast possible UUID instance to a string</span>
4240
- <a id="__codelineno-0-427" name="__codelineno-0-427"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">True</span>
4241
- <a id="__codelineno-0-428" name="__codelineno-0-428"></a>
4242
- <a id="__codelineno-0-429" name="__codelineno-0-429"></a> <span class="c1"># If it&#39;s not a pk, then it&#39;s a slug and the filter predicate needs to be nested (e.g.</span>
4243
- <a id="__codelineno-0-430" name="__codelineno-0-430"></a> <span class="c1"># `{&quot;site__slug&quot;: &quot;ams01&quot;}`) so that it can be usable in `Q` objects.</span>
4244
- <a id="__codelineno-0-431" name="__codelineno-0-431"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">is_pk</span><span class="p">:</span>
4245
- <a id="__codelineno-0-432" name="__codelineno-0-432"></a> <span class="n">name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="si">}</span><span class="s2">&quot;</span>
4246
- <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="k">else</span><span class="p">:</span>
4247
- <a id="__codelineno-0-434" name="__codelineno-0-434"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;UUID detected: Filtering using field name&quot;</span><span class="p">)</span>
4248
- <a id="__codelineno-0-435" name="__codelineno-0-435"></a> <span class="n">name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">field_name</span>
4249
- <a id="__codelineno-0-436" name="__codelineno-0-436"></a>
4250
- <a id="__codelineno-0-437" name="__codelineno-0-437"></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span> <span class="o">!=</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_LOOKUP_EXPR</span><span class="p">:</span>
4251
- <a id="__codelineno-0-438" name="__codelineno-0-438"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;__&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span><span class="p">])</span>
4252
- <a id="__codelineno-0-439" name="__codelineno-0-439"></a>
4253
- <a id="__codelineno-0-440" name="__codelineno-0-440"></a> <span class="k">return</span> <span class="p">{</span><span class="n">name</span><span class="p">:</span> <span class="n">v</span><span class="p">}</span>
5371
+ <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-389" name="__codelineno-0-389"></a><span class="nd">@extend_schema_field</span><span class="p">(</span><span class="n">OpenApiTypes</span><span class="o">.</span><span class="n">STR</span><span class="p">)</span>
5372
+ <a id="__codelineno-0-390" name="__codelineno-0-390"></a><span class="k">class</span> <span class="nc">NaturalKeyOrPKMultipleChoiceFilter</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">ModelMultipleChoiceFilter</span><span class="p">):</span>
5373
+ <a id="__codelineno-0-391" name="__codelineno-0-391"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5374
+ <a id="__codelineno-0-392" name="__codelineno-0-392"></a><span class="sd"> Filter that supports filtering on values matching the `pk` field and another</span>
5375
+ <a id="__codelineno-0-393" name="__codelineno-0-393"></a><span class="sd"> field of a foreign-key related object. The desired field is set using the `to_field_name`</span>
5376
+ <a id="__codelineno-0-394" name="__codelineno-0-394"></a><span class="sd"> keyword argument on filter initialization (defaults to `slug`).</span>
5377
+ <a id="__codelineno-0-395" name="__codelineno-0-395"></a><span class="sd"> &quot;&quot;&quot;</span>
5378
+ <a id="__codelineno-0-396" name="__codelineno-0-396"></a>
5379
+ <a id="__codelineno-0-397" name="__codelineno-0-397"></a> <span class="n">field_class</span> <span class="o">=</span> <span class="n">forms</span><span class="o">.</span><span class="n">MultiMatchModelMultipleChoiceField</span>
5380
+ <a id="__codelineno-0-398" name="__codelineno-0-398"></a>
5381
+ <a id="__codelineno-0-399" name="__codelineno-0-399"></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>
5382
+ <a id="__codelineno-0-400" name="__codelineno-0-400"></a> <span class="bp">self</span><span class="o">.</span><span class="n">natural_key</span> <span class="o">=</span> <span class="n">kwargs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="s2">&quot;to_field_name&quot;</span><span class="p">,</span> <span class="s2">&quot;slug&quot;</span><span class="p">)</span>
5383
+ <a id="__codelineno-0-401" name="__codelineno-0-401"></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>
5384
+ <a id="__codelineno-0-402" name="__codelineno-0-402"></a>
5385
+ <a id="__codelineno-0-403" name="__codelineno-0-403"></a> <span class="k">def</span> <span class="nf">get_filter_predicate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
5386
+ <a id="__codelineno-0-404" name="__codelineno-0-404"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5387
+ <a id="__codelineno-0-405" name="__codelineno-0-405"></a><span class="sd"> Override base filter behavior to force the filter to use the `pk` field instead of</span>
5388
+ <a id="__codelineno-0-406" name="__codelineno-0-406"></a><span class="sd"> the natural key in the generated filter.</span>
5389
+ <a id="__codelineno-0-407" name="__codelineno-0-407"></a><span class="sd"> &quot;&quot;&quot;</span>
5390
+ <a id="__codelineno-0-408" name="__codelineno-0-408"></a>
5391
+ <a id="__codelineno-0-409" name="__codelineno-0-409"></a> <span class="c1"># Null value filtering</span>
5392
+ <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
5393
+ <a id="__codelineno-0-411" name="__codelineno-0-411"></a> <span class="k">return</span> <span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__isnull&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
5394
+ <a id="__codelineno-0-412" name="__codelineno-0-412"></a>
5395
+ <a id="__codelineno-0-413" name="__codelineno-0-413"></a> <span class="c1"># If value is a model instance, stringify it to a pk.</span>
5396
+ <a id="__codelineno-0-414" name="__codelineno-0-414"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
5397
+ <a id="__codelineno-0-415" name="__codelineno-0-415"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Model instance detected. Casting to a PK.&quot;</span><span class="p">)</span>
5398
+ <a id="__codelineno-0-416" name="__codelineno-0-416"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
5399
+ <a id="__codelineno-0-417" name="__codelineno-0-417"></a>
5400
+ <a id="__codelineno-0-418" name="__codelineno-0-418"></a> <span class="c1"># Try to cast the value to a UUID and set `is_pk` boolean.</span>
5401
+ <a id="__codelineno-0-419" name="__codelineno-0-419"></a> <span class="k">try</span><span class="p">:</span>
5402
+ <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="n">uuid</span><span class="o">.</span><span class="n">UUID</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
5403
+ <a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="k">except</span> <span class="p">(</span><span class="ne">AttributeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="ne">ValueError</span><span class="p">):</span>
5404
+ <a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Non-UUID value detected: Filtering using natural key&quot;</span><span class="p">)</span>
5405
+ <a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">False</span>
5406
+ <a id="__codelineno-0-424" name="__codelineno-0-424"></a> <span class="k">else</span><span class="p">:</span>
5407
+ <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="c1"># Cast possible UUID instance to a string</span>
5408
+ <a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">True</span>
5409
+ <a id="__codelineno-0-427" name="__codelineno-0-427"></a>
5410
+ <a id="__codelineno-0-428" name="__codelineno-0-428"></a> <span class="c1"># If it&#39;s not a pk, then it&#39;s a slug and the filter predicate needs to be nested (e.g.</span>
5411
+ <a id="__codelineno-0-429" name="__codelineno-0-429"></a> <span class="c1"># `{&quot;site__slug&quot;: &quot;ams01&quot;}`) so that it can be usable in `Q` objects.</span>
5412
+ <a id="__codelineno-0-430" name="__codelineno-0-430"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">is_pk</span><span class="p">:</span>
5413
+ <a id="__codelineno-0-431" name="__codelineno-0-431"></a> <span class="n">name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="si">}</span><span class="s2">&quot;</span>
5414
+ <a id="__codelineno-0-432" name="__codelineno-0-432"></a> <span class="k">else</span><span class="p">:</span>
5415
+ <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;UUID detected: Filtering using field name&quot;</span><span class="p">)</span>
5416
+ <a id="__codelineno-0-434" name="__codelineno-0-434"></a> <span class="n">name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">field_name</span>
5417
+ <a id="__codelineno-0-435" name="__codelineno-0-435"></a>
5418
+ <a id="__codelineno-0-436" name="__codelineno-0-436"></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span> <span class="o">!=</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_LOOKUP_EXPR</span><span class="p">:</span>
5419
+ <a id="__codelineno-0-437" name="__codelineno-0-437"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;__&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span><span class="p">])</span>
5420
+ <a id="__codelineno-0-438" name="__codelineno-0-438"></a>
5421
+ <a id="__codelineno-0-439" name="__codelineno-0-439"></a> <span class="k">return</span> <span class="p">{</span><span class="n">name</span><span class="p">:</span> <span class="n">v</span><span class="p">}</span>
4254
5422
  </code></pre></div></td></tr></table></div>
4255
5423
  </details>
4256
5424
 
@@ -4283,7 +5451,8 @@ the natural key in the generated filter.</p>
4283
5451
 
4284
5452
  <details class="quote">
4285
5453
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4286
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-404">404</a></span>
5454
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-403">403</a></span>
5455
+ <span class="normal"><a href="#__codelineno-0-404">404</a></span>
4287
5456
  <span class="normal"><a href="#__codelineno-0-405">405</a></span>
4288
5457
  <span class="normal"><a href="#__codelineno-0-406">406</a></span>
4289
5458
  <span class="normal"><a href="#__codelineno-0-407">407</a></span>
@@ -4318,44 +5487,43 @@ the natural key in the generated filter.</p>
4318
5487
  <span class="normal"><a href="#__codelineno-0-436">436</a></span>
4319
5488
  <span class="normal"><a href="#__codelineno-0-437">437</a></span>
4320
5489
  <span class="normal"><a href="#__codelineno-0-438">438</a></span>
4321
- <span class="normal"><a href="#__codelineno-0-439">439</a></span>
4322
- <span class="normal"><a href="#__codelineno-0-440">440</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-404" name="__codelineno-0-404"></a><span class="k">def</span> <span class="nf">get_filter_predicate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
4323
- <a id="__codelineno-0-405" name="__codelineno-0-405"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4324
- <a id="__codelineno-0-406" name="__codelineno-0-406"></a><span class="sd"> Override base filter behavior to force the filter to use the `pk` field instead of</span>
4325
- <a id="__codelineno-0-407" name="__codelineno-0-407"></a><span class="sd"> the natural key in the generated filter.</span>
4326
- <a id="__codelineno-0-408" name="__codelineno-0-408"></a><span class="sd"> &quot;&quot;&quot;</span>
4327
- <a id="__codelineno-0-409" name="__codelineno-0-409"></a>
4328
- <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="c1"># Null value filtering</span>
4329
- <a id="__codelineno-0-411" name="__codelineno-0-411"></a> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4330
- <a id="__codelineno-0-412" name="__codelineno-0-412"></a> <span class="k">return</span> <span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__isnull&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
4331
- <a id="__codelineno-0-413" name="__codelineno-0-413"></a>
4332
- <a id="__codelineno-0-414" name="__codelineno-0-414"></a> <span class="c1"># If value is a model instance, stringify it to a pk.</span>
4333
- <a id="__codelineno-0-415" name="__codelineno-0-415"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
4334
- <a id="__codelineno-0-416" name="__codelineno-0-416"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Model instance detected. Casting to a PK.&quot;</span><span class="p">)</span>
4335
- <a id="__codelineno-0-417" name="__codelineno-0-417"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
4336
- <a id="__codelineno-0-418" name="__codelineno-0-418"></a>
4337
- <a id="__codelineno-0-419" name="__codelineno-0-419"></a> <span class="c1"># Try to cast the value to a UUID and set `is_pk` boolean.</span>
4338
- <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="k">try</span><span class="p">:</span>
4339
- <a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="n">uuid</span><span class="o">.</span><span class="n">UUID</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
4340
- <a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="k">except</span> <span class="p">(</span><span class="ne">AttributeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="ne">ValueError</span><span class="p">):</span>
4341
- <a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Non-UUID value detected: Filtering using natural key&quot;</span><span class="p">)</span>
4342
- <a id="__codelineno-0-424" name="__codelineno-0-424"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">False</span>
4343
- <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="k">else</span><span class="p">:</span>
4344
- <a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="c1"># Cast possible UUID instance to a string</span>
4345
- <a id="__codelineno-0-427" name="__codelineno-0-427"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">True</span>
4346
- <a id="__codelineno-0-428" name="__codelineno-0-428"></a>
4347
- <a id="__codelineno-0-429" name="__codelineno-0-429"></a> <span class="c1"># If it&#39;s not a pk, then it&#39;s a slug and the filter predicate needs to be nested (e.g.</span>
4348
- <a id="__codelineno-0-430" name="__codelineno-0-430"></a> <span class="c1"># `{&quot;site__slug&quot;: &quot;ams01&quot;}`) so that it can be usable in `Q` objects.</span>
4349
- <a id="__codelineno-0-431" name="__codelineno-0-431"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">is_pk</span><span class="p">:</span>
4350
- <a id="__codelineno-0-432" name="__codelineno-0-432"></a> <span class="n">name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="si">}</span><span class="s2">&quot;</span>
4351
- <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="k">else</span><span class="p">:</span>
4352
- <a id="__codelineno-0-434" name="__codelineno-0-434"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;UUID detected: Filtering using field name&quot;</span><span class="p">)</span>
4353
- <a id="__codelineno-0-435" name="__codelineno-0-435"></a> <span class="n">name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">field_name</span>
4354
- <a id="__codelineno-0-436" name="__codelineno-0-436"></a>
4355
- <a id="__codelineno-0-437" name="__codelineno-0-437"></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span> <span class="o">!=</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_LOOKUP_EXPR</span><span class="p">:</span>
4356
- <a id="__codelineno-0-438" name="__codelineno-0-438"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;__&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span><span class="p">])</span>
4357
- <a id="__codelineno-0-439" name="__codelineno-0-439"></a>
4358
- <a id="__codelineno-0-440" name="__codelineno-0-440"></a> <span class="k">return</span> <span class="p">{</span><span class="n">name</span><span class="p">:</span> <span class="n">v</span><span class="p">}</span>
5490
+ <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-403" name="__codelineno-0-403"></a><span class="k">def</span> <span class="nf">get_filter_predicate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">v</span><span class="p">):</span>
5491
+ <a id="__codelineno-0-404" name="__codelineno-0-404"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5492
+ <a id="__codelineno-0-405" name="__codelineno-0-405"></a><span class="sd"> Override base filter behavior to force the filter to use the `pk` field instead of</span>
5493
+ <a id="__codelineno-0-406" name="__codelineno-0-406"></a><span class="sd"> the natural key in the generated filter.</span>
5494
+ <a id="__codelineno-0-407" name="__codelineno-0-407"></a><span class="sd"> &quot;&quot;&quot;</span>
5495
+ <a id="__codelineno-0-408" name="__codelineno-0-408"></a>
5496
+ <a id="__codelineno-0-409" name="__codelineno-0-409"></a> <span class="c1"># Null value filtering</span>
5497
+ <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="k">if</span> <span class="n">v</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
5498
+ <a id="__codelineno-0-411" name="__codelineno-0-411"></a> <span class="k">return</span> <span class="p">{</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__isnull&quot;</span><span class="p">:</span> <span class="kc">True</span><span class="p">}</span>
5499
+ <a id="__codelineno-0-412" name="__codelineno-0-412"></a>
5500
+ <a id="__codelineno-0-413" name="__codelineno-0-413"></a> <span class="c1"># If value is a model instance, stringify it to a pk.</span>
5501
+ <a id="__codelineno-0-414" name="__codelineno-0-414"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">v</span><span class="p">,</span> <span class="n">models</span><span class="o">.</span><span class="n">Model</span><span class="p">):</span>
5502
+ <a id="__codelineno-0-415" name="__codelineno-0-415"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Model instance detected. Casting to a PK.&quot;</span><span class="p">)</span>
5503
+ <a id="__codelineno-0-416" name="__codelineno-0-416"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="o">.</span><span class="n">pk</span><span class="p">)</span>
5504
+ <a id="__codelineno-0-417" name="__codelineno-0-417"></a>
5505
+ <a id="__codelineno-0-418" name="__codelineno-0-418"></a> <span class="c1"># Try to cast the value to a UUID and set `is_pk` boolean.</span>
5506
+ <a id="__codelineno-0-419" name="__codelineno-0-419"></a> <span class="k">try</span><span class="p">:</span>
5507
+ <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="n">uuid</span><span class="o">.</span><span class="n">UUID</span><span class="p">(</span><span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">))</span>
5508
+ <a id="__codelineno-0-421" name="__codelineno-0-421"></a> <span class="k">except</span> <span class="p">(</span><span class="ne">AttributeError</span><span class="p">,</span> <span class="ne">TypeError</span><span class="p">,</span> <span class="ne">ValueError</span><span class="p">):</span>
5509
+ <a id="__codelineno-0-422" name="__codelineno-0-422"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;Non-UUID value detected: Filtering using natural key&quot;</span><span class="p">)</span>
5510
+ <a id="__codelineno-0-423" name="__codelineno-0-423"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">False</span>
5511
+ <a id="__codelineno-0-424" name="__codelineno-0-424"></a> <span class="k">else</span><span class="p">:</span>
5512
+ <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="n">v</span> <span class="o">=</span> <span class="nb">str</span><span class="p">(</span><span class="n">v</span><span class="p">)</span> <span class="c1"># Cast possible UUID instance to a string</span>
5513
+ <a id="__codelineno-0-426" name="__codelineno-0-426"></a> <span class="n">is_pk</span> <span class="o">=</span> <span class="kc">True</span>
5514
+ <a id="__codelineno-0-427" name="__codelineno-0-427"></a>
5515
+ <a id="__codelineno-0-428" name="__codelineno-0-428"></a> <span class="c1"># If it&#39;s not a pk, then it&#39;s a slug and the filter predicate needs to be nested (e.g.</span>
5516
+ <a id="__codelineno-0-429" name="__codelineno-0-429"></a> <span class="c1"># `{&quot;site__slug&quot;: &quot;ams01&quot;}`) so that it can be usable in `Q` objects.</span>
5517
+ <a id="__codelineno-0-430" name="__codelineno-0-430"></a> <span class="k">if</span> <span class="ow">not</span> <span class="n">is_pk</span><span class="p">:</span>
5518
+ <a id="__codelineno-0-431" name="__codelineno-0-431"></a> <span class="n">name</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field_name</span><span class="si">}</span><span class="s2">__</span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="si">}</span><span class="s2">&quot;</span>
5519
+ <a id="__codelineno-0-432" name="__codelineno-0-432"></a> <span class="k">else</span><span class="p">:</span>
5520
+ <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="n">logger</span><span class="o">.</span><span class="n">debug</span><span class="p">(</span><span class="s2">&quot;UUID detected: Filtering using field name&quot;</span><span class="p">)</span>
5521
+ <a id="__codelineno-0-434" name="__codelineno-0-434"></a> <span class="n">name</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">field_name</span>
5522
+ <a id="__codelineno-0-435" name="__codelineno-0-435"></a>
5523
+ <a id="__codelineno-0-436" name="__codelineno-0-436"></a> <span class="k">if</span> <span class="n">name</span> <span class="ow">and</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span> <span class="o">!=</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">conf</span><span class="o">.</span><span class="n">settings</span><span class="o">.</span><span class="n">DEFAULT_LOOKUP_EXPR</span><span class="p">:</span>
5524
+ <a id="__codelineno-0-437" name="__codelineno-0-437"></a> <span class="n">name</span> <span class="o">=</span> <span class="s2">&quot;__&quot;</span><span class="o">.</span><span class="n">join</span><span class="p">([</span><span class="n">name</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">lookup_expr</span><span class="p">])</span>
5525
+ <a id="__codelineno-0-438" name="__codelineno-0-438"></a>
5526
+ <a id="__codelineno-0-439" name="__codelineno-0-439"></a> <span class="k">return</span> <span class="p">{</span><span class="n">name</span><span class="p">:</span> <span class="n">v</span><span class="p">}</span>
4359
5527
  </code></pre></div></td></tr></table></div>
4360
5528
  </details>
4361
5529
  </div>
@@ -4453,7 +5621,8 @@ argument to test for the existence of related objects.</p>
4453
5621
 
4454
5622
  <details class="quote">
4455
5623
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4456
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-125">125</a></span>
5624
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-124">124</a></span>
5625
+ <span class="normal"><a href="#__codelineno-0-125">125</a></span>
4457
5626
  <span class="normal"><a href="#__codelineno-0-126">126</a></span>
4458
5627
  <span class="normal"><a href="#__codelineno-0-127">127</a></span>
4459
5628
  <span class="normal"><a href="#__codelineno-0-128">128</a></span>
@@ -4484,40 +5653,39 @@ argument to test for the existence of related objects.</p>
4484
5653
  <span class="normal"><a href="#__codelineno-0-153">153</a></span>
4485
5654
  <span class="normal"><a href="#__codelineno-0-154">154</a></span>
4486
5655
  <span class="normal"><a href="#__codelineno-0-155">155</a></span>
4487
- <span class="normal"><a href="#__codelineno-0-156">156</a></span>
4488
- <span class="normal"><a href="#__codelineno-0-157">157</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-125" name="__codelineno-0-125"></a><span class="k">class</span> <span class="nc">RelatedMembershipBooleanFilter</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">BooleanFilter</span><span class="p">):</span>
4489
- <a id="__codelineno-0-126" name="__codelineno-0-126"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4490
- <a id="__codelineno-0-127" name="__codelineno-0-127"></a><span class="sd"> BooleanFilter for related objects that will explicitly perform `exclude=True` and `isnull`</span>
4491
- <a id="__codelineno-0-128" name="__codelineno-0-128"></a><span class="sd"> lookups. The `field_name` argument is required and must be set to the related field on the</span>
4492
- <a id="__codelineno-0-129" name="__codelineno-0-129"></a><span class="sd"> model.</span>
4493
- <a id="__codelineno-0-130" name="__codelineno-0-130"></a>
4494
- <a id="__codelineno-0-131" name="__codelineno-0-131"></a><span class="sd"> This should be used instead of a default `BooleanFilter` paired `method=`</span>
4495
- <a id="__codelineno-0-132" name="__codelineno-0-132"></a><span class="sd"> argument to test for the existence of related objects.</span>
4496
- <a id="__codelineno-0-133" name="__codelineno-0-133"></a>
4497
- <a id="__codelineno-0-134" name="__codelineno-0-134"></a><span class="sd"> Example:</span>
4498
- <a id="__codelineno-0-135" name="__codelineno-0-135"></a>
4499
- <a id="__codelineno-0-136" name="__codelineno-0-136"></a><span class="sd"> has_interfaces = RelatedMembershipBooleanFilter(</span>
4500
- <a id="__codelineno-0-137" name="__codelineno-0-137"></a><span class="sd"> field_name=&quot;interfaces&quot;,</span>
4501
- <a id="__codelineno-0-138" name="__codelineno-0-138"></a><span class="sd"> label=&quot;Has interfaces&quot;,</span>
4502
- <a id="__codelineno-0-139" name="__codelineno-0-139"></a><span class="sd"> )</span>
4503
- <a id="__codelineno-0-140" name="__codelineno-0-140"></a><span class="sd"> &quot;&quot;&quot;</span>
4504
- <a id="__codelineno-0-141" name="__codelineno-0-141"></a>
4505
- <a id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
4506
- <a id="__codelineno-0-143" name="__codelineno-0-143"></a> <span class="bp">self</span><span class="p">,</span> <span class="n">field_name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">lookup_expr</span><span class="o">=</span><span class="s2">&quot;isnull&quot;</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">distinct</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">exclude</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span>
4507
- <a id="__codelineno-0-144" name="__codelineno-0-144"></a> <span class="p">):</span>
4508
- <a id="__codelineno-0-145" name="__codelineno-0-145"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
4509
- <a id="__codelineno-0-146" name="__codelineno-0-146"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Field name is required for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
4510
- <a id="__codelineno-0-147" name="__codelineno-0-147"></a>
4511
- <a id="__codelineno-0-148" name="__codelineno-0-148"></a> <span class="nb">super</span><span class="p">()</span><span class="o">.</span><span class="fm">__init__</span><span class="p">(</span>
4512
- <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">field_name</span><span class="p">,</span>
4513
- <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="n">lookup_expr</span><span class="o">=</span><span class="n">lookup_expr</span><span class="p">,</span>
4514
- <a id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="n">label</span><span class="o">=</span><span class="n">label</span><span class="p">,</span>
4515
- <a id="__codelineno-0-152" name="__codelineno-0-152"></a> <span class="n">method</span><span class="o">=</span><span class="n">method</span><span class="p">,</span>
4516
- <a id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="n">distinct</span><span class="o">=</span><span class="n">distinct</span><span class="p">,</span>
4517
- <a id="__codelineno-0-154" name="__codelineno-0-154"></a> <span class="n">exclude</span><span class="o">=</span><span class="n">exclude</span><span class="p">,</span>
4518
- <a id="__codelineno-0-155" name="__codelineno-0-155"></a> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">StaticSelect2</span><span class="p">(</span><span class="n">choices</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">BOOLEAN_CHOICES</span><span class="p">),</span>
4519
- <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
4520
- <a id="__codelineno-0-157" name="__codelineno-0-157"></a> <span class="p">)</span>
5656
+ <span class="normal"><a href="#__codelineno-0-156">156</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-124" name="__codelineno-0-124"></a><span class="k">class</span> <span class="nc">RelatedMembershipBooleanFilter</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">BooleanFilter</span><span class="p">):</span>
5657
+ <a id="__codelineno-0-125" name="__codelineno-0-125"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5658
+ <a id="__codelineno-0-126" name="__codelineno-0-126"></a><span class="sd"> BooleanFilter for related objects that will explicitly perform `exclude=True` and `isnull`</span>
5659
+ <a id="__codelineno-0-127" name="__codelineno-0-127"></a><span class="sd"> lookups. The `field_name` argument is required and must be set to the related field on the</span>
5660
+ <a id="__codelineno-0-128" name="__codelineno-0-128"></a><span class="sd"> model.</span>
5661
+ <a id="__codelineno-0-129" name="__codelineno-0-129"></a>
5662
+ <a id="__codelineno-0-130" name="__codelineno-0-130"></a><span class="sd"> This should be used instead of a default `BooleanFilter` paired `method=`</span>
5663
+ <a id="__codelineno-0-131" name="__codelineno-0-131"></a><span class="sd"> argument to test for the existence of related objects.</span>
5664
+ <a id="__codelineno-0-132" name="__codelineno-0-132"></a>
5665
+ <a id="__codelineno-0-133" name="__codelineno-0-133"></a><span class="sd"> Example:</span>
5666
+ <a id="__codelineno-0-134" name="__codelineno-0-134"></a>
5667
+ <a id="__codelineno-0-135" name="__codelineno-0-135"></a><span class="sd"> has_interfaces = RelatedMembershipBooleanFilter(</span>
5668
+ <a id="__codelineno-0-136" name="__codelineno-0-136"></a><span class="sd"> field_name=&quot;interfaces&quot;,</span>
5669
+ <a id="__codelineno-0-137" name="__codelineno-0-137"></a><span class="sd"> label=&quot;Has interfaces&quot;,</span>
5670
+ <a id="__codelineno-0-138" name="__codelineno-0-138"></a><span class="sd"> )</span>
5671
+ <a id="__codelineno-0-139" name="__codelineno-0-139"></a><span class="sd"> &quot;&quot;&quot;</span>
5672
+ <a id="__codelineno-0-140" name="__codelineno-0-140"></a>
5673
+ <a id="__codelineno-0-141" name="__codelineno-0-141"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
5674
+ <a id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="bp">self</span><span class="p">,</span> <span class="n">field_name</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">lookup_expr</span><span class="o">=</span><span class="s2">&quot;isnull&quot;</span><span class="p">,</span> <span class="o">*</span><span class="p">,</span> <span class="n">label</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">method</span><span class="o">=</span><span class="kc">None</span><span class="p">,</span> <span class="n">distinct</span><span class="o">=</span><span class="kc">False</span><span class="p">,</span> <span class="n">exclude</span><span class="o">=</span><span class="kc">True</span><span class="p">,</span> <span class="o">**</span><span class="n">kwargs</span>
5675
+ <a id="__codelineno-0-143" name="__codelineno-0-143"></a> <span class="p">):</span>
5676
+ <a id="__codelineno-0-144" name="__codelineno-0-144"></a> <span class="k">if</span> <span class="n">field_name</span> <span class="ow">is</span> <span class="kc">None</span><span class="p">:</span>
5677
+ <a id="__codelineno-0-145" name="__codelineno-0-145"></a> <span class="k">raise</span> <span class="ne">ValueError</span><span class="p">(</span><span class="sa">f</span><span class="s2">&quot;Field name is required for </span><span class="si">{</span><span class="bp">self</span><span class="o">.</span><span class="vm">__class__</span><span class="o">.</span><span class="vm">__name__</span><span class="si">}</span><span class="s2">&quot;</span><span class="p">)</span>
5678
+ <a id="__codelineno-0-146" name="__codelineno-0-146"></a>
5679
+ <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>
5680
+ <a id="__codelineno-0-148" name="__codelineno-0-148"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">field_name</span><span class="p">,</span>
5681
+ <a id="__codelineno-0-149" name="__codelineno-0-149"></a> <span class="n">lookup_expr</span><span class="o">=</span><span class="n">lookup_expr</span><span class="p">,</span>
5682
+ <a id="__codelineno-0-150" name="__codelineno-0-150"></a> <span class="n">label</span><span class="o">=</span><span class="n">label</span><span class="p">,</span>
5683
+ <a id="__codelineno-0-151" name="__codelineno-0-151"></a> <span class="n">method</span><span class="o">=</span><span class="n">method</span><span class="p">,</span>
5684
+ <a id="__codelineno-0-152" name="__codelineno-0-152"></a> <span class="n">distinct</span><span class="o">=</span><span class="n">distinct</span><span class="p">,</span>
5685
+ <a id="__codelineno-0-153" name="__codelineno-0-153"></a> <span class="n">exclude</span><span class="o">=</span><span class="n">exclude</span><span class="p">,</span>
5686
+ <a id="__codelineno-0-154" name="__codelineno-0-154"></a> <span class="n">widget</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">StaticSelect2</span><span class="p">(</span><span class="n">choices</span><span class="o">=</span><span class="n">forms</span><span class="o">.</span><span class="n">BOOLEAN_CHOICES</span><span class="p">),</span>
5687
+ <a id="__codelineno-0-155" name="__codelineno-0-155"></a> <span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
5688
+ <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="p">)</span>
4521
5689
  </code></pre></div></td></tr></table></div>
4522
5690
  </details>
4523
5691
 
@@ -4662,10 +5830,10 @@ argument to test for the existence of related objects.</p>
4662
5830
  <a id="__codelineno-0-254" name="__codelineno-0-254"></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>
4663
5831
  <a id="__codelineno-0-255" name="__codelineno-0-255"></a>
4664
5832
  <a id="__codelineno-0-256" name="__codelineno-0-256"></a> <span class="c1"># If this model is on the &quot;source&quot; side of the relationship, then the field will be named</span>
4665
- <a id="__codelineno-0-257" name="__codelineno-0-257"></a> <span class="c1"># &quot;cr_&lt;relationship-slug&gt;__destination&quot; since it&#39;s used to pick the destination object(s).</span>
4666
- <a id="__codelineno-0-258" name="__codelineno-0-258"></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>
4667
- <a id="__codelineno-0-259" name="__codelineno-0-259"></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>
4668
- <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>
5833
+ <a id="__codelineno-0-257" name="__codelineno-0-257"></a> <span class="c1"># &quot;cr_&lt;relationship_key&gt;__destination&quot; since it&#39;s used to pick the destination object(s).</span>
5834
+ <a id="__codelineno-0-258" name="__codelineno-0-258"></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>
5835
+ <a id="__codelineno-0-259" name="__codelineno-0-259"></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>
5836
+ <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">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>
4669
5837
  <a id="__codelineno-0-261" name="__codelineno-0-261"></a>
4670
5838
  <a id="__codelineno-0-262" name="__codelineno-0-262"></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>
4671
5839
  <a id="__codelineno-0-263" name="__codelineno-0-263"></a> <span class="c1"># This is a symmetric relationship that we already processed from the opposing &quot;initial_side&quot;.</span>
@@ -4732,21 +5900,21 @@ argument to test for the existence of related objects.</p>
4732
5900
 
4733
5901
  <details class="quote">
4734
5902
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4735
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-443">443</a></span>
5903
+ <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>
5904
+ <span class="normal"><a href="#__codelineno-0-443">443</a></span>
4736
5905
  <span class="normal"><a href="#__codelineno-0-444">444</a></span>
4737
5906
  <span class="normal"><a href="#__codelineno-0-445">445</a></span>
4738
5907
  <span class="normal"><a href="#__codelineno-0-446">446</a></span>
4739
5908
  <span class="normal"><a href="#__codelineno-0-447">447</a></span>
4740
5909
  <span class="normal"><a href="#__codelineno-0-448">448</a></span>
4741
- <span class="normal"><a href="#__codelineno-0-449">449</a></span>
4742
- <span class="normal"><a href="#__codelineno-0-450">450</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-443" name="__codelineno-0-443"></a><span class="k">class</span> <span class="nc">SearchFilter</span><span class="p">(</span><span class="n">MappedPredicatesFilterMixin</span><span class="p">,</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">CharFilter</span><span class="p">):</span>
4743
- <a id="__codelineno-0-444" name="__codelineno-0-444"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4744
- <a id="__codelineno-0-445" name="__codelineno-0-445"></a><span class="sd"> Provide a search filter for use on filtersets as the `q=` parameter.</span>
4745
- <a id="__codelineno-0-446" name="__codelineno-0-446"></a>
4746
- <a id="__codelineno-0-447" name="__codelineno-0-447"></a><span class="sd"> See the docstring for `nautobot.core.filters.MappedPredicatesFilterMixin` for usage.</span>
4747
- <a id="__codelineno-0-448" name="__codelineno-0-448"></a><span class="sd"> &quot;&quot;&quot;</span>
4748
- <a id="__codelineno-0-449" name="__codelineno-0-449"></a>
4749
- <a id="__codelineno-0-450" name="__codelineno-0-450"></a> <span class="n">label</span> <span class="o">=</span> <span class="s2">&quot;Search&quot;</span>
5910
+ <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-442" name="__codelineno-0-442"></a><span class="k">class</span> <span class="nc">SearchFilter</span><span class="p">(</span><span class="n">MappedPredicatesFilterMixin</span><span class="p">,</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">CharFilter</span><span class="p">):</span>
5911
+ <a id="__codelineno-0-443" name="__codelineno-0-443"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5912
+ <a id="__codelineno-0-444" name="__codelineno-0-444"></a><span class="sd"> Provide a search filter for use on filtersets as the `q=` parameter.</span>
5913
+ <a id="__codelineno-0-445" name="__codelineno-0-445"></a>
5914
+ <a id="__codelineno-0-446" name="__codelineno-0-446"></a><span class="sd"> See the docstring for `nautobot.core.filters.MappedPredicatesFilterMixin` for usage.</span>
5915
+ <a id="__codelineno-0-447" name="__codelineno-0-447"></a><span class="sd"> &quot;&quot;&quot;</span>
5916
+ <a id="__codelineno-0-448" name="__codelineno-0-448"></a>
5917
+ <a id="__codelineno-0-449" name="__codelineno-0-449"></a> <span class="n">label</span> <span class="o">=</span> <span class="s2">&quot;Search&quot;</span>
4750
5918
  </code></pre></div></td></tr></table></div>
4751
5919
  </details>
4752
5920
 
@@ -4939,7 +6107,8 @@ would match both "Athens" and "Durham".</p>
4939
6107
 
4940
6108
  <details class="quote">
4941
6109
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4942
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-469">469</a></span>
6110
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-468">468</a></span>
6111
+ <span class="normal"><a href="#__codelineno-0-469">469</a></span>
4943
6112
  <span class="normal"><a href="#__codelineno-0-470">470</a></span>
4944
6113
  <span class="normal"><a href="#__codelineno-0-471">471</a></span>
4945
6114
  <span class="normal"><a href="#__codelineno-0-472">472</a></span>
@@ -4993,63 +6162,62 @@ would match both "Athens" and "Durham".</p>
4993
6162
  <span class="normal"><a href="#__codelineno-0-520">520</a></span>
4994
6163
  <span class="normal"><a href="#__codelineno-0-521">521</a></span>
4995
6164
  <span class="normal"><a href="#__codelineno-0-522">522</a></span>
4996
- <span class="normal"><a href="#__codelineno-0-523">523</a></span>
4997
- <span class="normal"><a href="#__codelineno-0-524">524</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-469" name="__codelineno-0-469"></a><span class="k">class</span> <span class="nc">TreeNodeMultipleChoiceFilter</span><span class="p">(</span><span class="n">NaturalKeyOrPKMultipleChoiceFilter</span><span class="p">):</span>
4998
- <a id="__codelineno-0-470" name="__codelineno-0-470"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4999
- <a id="__codelineno-0-471" name="__codelineno-0-471"></a><span class="sd"> Filter that matches on the given model(s) (identified by slug and/or pk) _as well as their tree descendants._</span>
5000
- <a id="__codelineno-0-472" name="__codelineno-0-472"></a>
5001
- <a id="__codelineno-0-473" name="__codelineno-0-473"></a><span class="sd"> For example, if we have:</span>
5002
- <a id="__codelineno-0-474" name="__codelineno-0-474"></a>
5003
- <a id="__codelineno-0-475" name="__codelineno-0-475"></a><span class="sd"> Region &quot;Earth&quot;</span>
5004
- <a id="__codelineno-0-476" name="__codelineno-0-476"></a><span class="sd"> Region &quot;USA&quot;</span>
5005
- <a id="__codelineno-0-477" name="__codelineno-0-477"></a><span class="sd"> Region &quot;GA&quot; &lt;- Site &quot;Athens&quot;</span>
5006
- <a id="__codelineno-0-478" name="__codelineno-0-478"></a><span class="sd"> Region &quot;NC&quot; &lt;- Site &quot;Durham&quot;</span>
5007
- <a id="__codelineno-0-479" name="__codelineno-0-479"></a>
5008
- <a id="__codelineno-0-480" name="__codelineno-0-480"></a><span class="sd"> a NaturalKeyOrPKMultipleChoiceFilter on Site for {&quot;region&quot;: &quot;USA&quot;} would have no matches,</span>
5009
- <a id="__codelineno-0-481" name="__codelineno-0-481"></a><span class="sd"> since there are no Sites whose immediate Region is &quot;USA&quot;,</span>
5010
- <a id="__codelineno-0-482" name="__codelineno-0-482"></a><span class="sd"> but a TreeNodeMultipleChoiceFilter on Site for {&quot;region&quot;: &quot;USA&quot;} or {&quot;region&quot;: &quot;Earth&quot;}</span>
5011
- <a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="sd"> would match both &quot;Athens&quot; and &quot;Durham&quot;.</span>
5012
- <a id="__codelineno-0-484" name="__codelineno-0-484"></a><span class="sd"> &quot;&quot;&quot;</span>
5013
- <a id="__codelineno-0-485" name="__codelineno-0-485"></a>
5014
- <a id="__codelineno-0-486" name="__codelineno-0-486"></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>
5015
- <a id="__codelineno-0-487" name="__codelineno-0-487"></a> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;lookup_expr&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> <span class="c1"># Disallow overloading of `lookup_expr`.</span>
5016
- <a id="__codelineno-0-488" name="__codelineno-0-488"></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>
5017
- <a id="__codelineno-0-489" name="__codelineno-0-489"></a>
5018
- <a id="__codelineno-0-490" name="__codelineno-0-490"></a> <span class="k">def</span> <span class="nf">generate_query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">qs</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>
5019
- <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5020
- <a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> Given a filter value, return a `Q` object that accounts for nested tree node descendants.</span>
5021
- <a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> &quot;&quot;&quot;</span>
5022
- <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
5023
- <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="c1"># django-tree-queries</span>
5024
- <a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="n">value</span> <span class="o">=</span> <span class="p">[</span><span class="n">node</span><span class="o">.</span><span class="n">descendants</span><span class="p">(</span><span class="n">include_self</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">value</span><span class="p">]</span>
5025
- <a id="__codelineno-0-497" name="__codelineno-0-497"></a>
5026
- <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="c1"># This new_value is going to be a list of querysets that needs to be flattened.</span>
5027
- <a id="__codelineno-0-499" name="__codelineno-0-499"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">data_utils</span><span class="o">.</span><span class="n">flatten_iterable</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
5028
- <a id="__codelineno-0-500" name="__codelineno-0-500"></a>
5029
- <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="c1"># Construct a list of filter predicates that will be used to generate the Q object.</span>
5030
- <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="n">predicates</span> <span class="o">=</span> <span class="p">[]</span>
5031
- <a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
5032
- <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="c1"># Try to get the `to_field_name` (e.g. `slug`) or just pass the object through.</span>
5033
- <a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
5034
- <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="k">if</span> <span class="n">val</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_value</span><span class="p">:</span>
5035
- <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="n">val</span> <span class="o">=</span> <span class="kc">None</span>
5036
- <a id="__codelineno-0-508" name="__codelineno-0-508"></a> <span class="n">predicates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_filter_predicate</span><span class="p">(</span><span class="n">val</span><span class="p">))</span>
5037
- <a id="__codelineno-0-509" name="__codelineno-0-509"></a>
5038
- <a id="__codelineno-0-510" name="__codelineno-0-510"></a> <span class="c1"># Construct a nested OR query from the list of filter predicates derived from the flattened</span>
5039
- <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="c1"># listed of descendant objects.</span>
5040
- <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="n">query</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">()</span>
5041
- <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="k">for</span> <span class="n">predicate</span> <span class="ow">in</span> <span class="n">predicates</span><span class="p">:</span>
5042
- <a id="__codelineno-0-514" name="__codelineno-0-514"></a> <span class="n">query</span> <span class="o">|=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">(</span><span class="o">**</span><span class="n">predicate</span><span class="p">)</span>
5043
- <a id="__codelineno-0-515" name="__codelineno-0-515"></a>
5044
- <a id="__codelineno-0-516" name="__codelineno-0-516"></a> <span class="k">return</span> <span class="n">query</span>
5045
- <a id="__codelineno-0-517" name="__codelineno-0-517"></a>
5046
- <a id="__codelineno-0-518" name="__codelineno-0-518"></a> <span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">qs</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
5047
- <a id="__codelineno-0-519" name="__codelineno-0-519"></a> <span class="k">if</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">EMPTY_VALUES</span><span class="p">:</span>
5048
- <a id="__codelineno-0-520" name="__codelineno-0-520"></a> <span class="k">return</span> <span class="n">qs</span>
5049
- <a id="__codelineno-0-521" name="__codelineno-0-521"></a>
5050
- <a id="__codelineno-0-522" name="__codelineno-0-522"></a> <span class="c1"># Fetch the generated Q object and filter the incoming qs with it before passing it along.</span>
5051
- <a id="__codelineno-0-523" name="__codelineno-0-523"></a> <span class="n">query</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">generate_query</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
5052
- <a id="__codelineno-0-524" name="__codelineno-0-524"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_method</span><span class="p">(</span><span class="n">qs</span><span class="p">)(</span><span class="n">query</span><span class="p">)</span>
6165
+ <span class="normal"><a href="#__codelineno-0-523">523</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-468" name="__codelineno-0-468"></a><span class="k">class</span> <span class="nc">TreeNodeMultipleChoiceFilter</span><span class="p">(</span><span class="n">NaturalKeyOrPKMultipleChoiceFilter</span><span class="p">):</span>
6166
+ <a id="__codelineno-0-469" name="__codelineno-0-469"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6167
+ <a id="__codelineno-0-470" name="__codelineno-0-470"></a><span class="sd"> Filter that matches on the given model(s) (identified by slug and/or pk) _as well as their tree descendants._</span>
6168
+ <a id="__codelineno-0-471" name="__codelineno-0-471"></a>
6169
+ <a id="__codelineno-0-472" name="__codelineno-0-472"></a><span class="sd"> For example, if we have:</span>
6170
+ <a id="__codelineno-0-473" name="__codelineno-0-473"></a>
6171
+ <a id="__codelineno-0-474" name="__codelineno-0-474"></a><span class="sd"> Region &quot;Earth&quot;</span>
6172
+ <a id="__codelineno-0-475" name="__codelineno-0-475"></a><span class="sd"> Region &quot;USA&quot;</span>
6173
+ <a id="__codelineno-0-476" name="__codelineno-0-476"></a><span class="sd"> Region &quot;GA&quot; &lt;- Site &quot;Athens&quot;</span>
6174
+ <a id="__codelineno-0-477" name="__codelineno-0-477"></a><span class="sd"> Region &quot;NC&quot; &lt;- Site &quot;Durham&quot;</span>
6175
+ <a id="__codelineno-0-478" name="__codelineno-0-478"></a>
6176
+ <a id="__codelineno-0-479" name="__codelineno-0-479"></a><span class="sd"> a NaturalKeyOrPKMultipleChoiceFilter on Site for {&quot;region&quot;: &quot;USA&quot;} would have no matches,</span>
6177
+ <a id="__codelineno-0-480" name="__codelineno-0-480"></a><span class="sd"> since there are no Sites whose immediate Region is &quot;USA&quot;,</span>
6178
+ <a id="__codelineno-0-481" name="__codelineno-0-481"></a><span class="sd"> but a TreeNodeMultipleChoiceFilter on Site for {&quot;region&quot;: &quot;USA&quot;} or {&quot;region&quot;: &quot;Earth&quot;}</span>
6179
+ <a id="__codelineno-0-482" name="__codelineno-0-482"></a><span class="sd"> would match both &quot;Athens&quot; and &quot;Durham&quot;.</span>
6180
+ <a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="sd"> &quot;&quot;&quot;</span>
6181
+ <a id="__codelineno-0-484" name="__codelineno-0-484"></a>
6182
+ <a id="__codelineno-0-485" name="__codelineno-0-485"></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>
6183
+ <a id="__codelineno-0-486" name="__codelineno-0-486"></a> <span class="n">kwargs</span><span class="o">.</span><span class="n">pop</span><span class="p">(</span><span class="s2">&quot;lookup_expr&quot;</span><span class="p">,</span> <span class="kc">None</span><span class="p">)</span> <span class="c1"># Disallow overloading of `lookup_expr`.</span>
6184
+ <a id="__codelineno-0-487" name="__codelineno-0-487"></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>
6185
+ <a id="__codelineno-0-488" name="__codelineno-0-488"></a>
6186
+ <a id="__codelineno-0-489" name="__codelineno-0-489"></a> <span class="k">def</span> <span class="nf">generate_query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">qs</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>
6187
+ <a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6188
+ <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="sd"> Given a filter value, return a `Q` object that accounts for nested tree node descendants.</span>
6189
+ <a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> &quot;&quot;&quot;</span>
6190
+ <a id="__codelineno-0-493" name="__codelineno-0-493"></a> <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
6191
+ <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="c1"># django-tree-queries</span>
6192
+ <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="n">value</span> <span class="o">=</span> <span class="p">[</span><span class="n">node</span><span class="o">.</span><span class="n">descendants</span><span class="p">(</span><span class="n">include_self</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">value</span><span class="p">]</span>
6193
+ <a id="__codelineno-0-496" name="__codelineno-0-496"></a>
6194
+ <a id="__codelineno-0-497" name="__codelineno-0-497"></a> <span class="c1"># This new_value is going to be a list of querysets that needs to be flattened.</span>
6195
+ <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">data_utils</span><span class="o">.</span><span class="n">flatten_iterable</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
6196
+ <a id="__codelineno-0-499" name="__codelineno-0-499"></a>
6197
+ <a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="c1"># Construct a list of filter predicates that will be used to generate the Q object.</span>
6198
+ <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="n">predicates</span> <span class="o">=</span> <span class="p">[]</span>
6199
+ <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
6200
+ <a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="c1"># Try to get the `to_field_name` (e.g. `slug`) or just pass the object through.</span>
6201
+ <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
6202
+ <a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="k">if</span> <span class="n">val</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_value</span><span class="p">:</span>
6203
+ <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="n">val</span> <span class="o">=</span> <span class="kc">None</span>
6204
+ <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="n">predicates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_filter_predicate</span><span class="p">(</span><span class="n">val</span><span class="p">))</span>
6205
+ <a id="__codelineno-0-508" name="__codelineno-0-508"></a>
6206
+ <a id="__codelineno-0-509" name="__codelineno-0-509"></a> <span class="c1"># Construct a nested OR query from the list of filter predicates derived from the flattened</span>
6207
+ <a id="__codelineno-0-510" name="__codelineno-0-510"></a> <span class="c1"># listed of descendant objects.</span>
6208
+ <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="n">query</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">()</span>
6209
+ <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="k">for</span> <span class="n">predicate</span> <span class="ow">in</span> <span class="n">predicates</span><span class="p">:</span>
6210
+ <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="n">query</span> <span class="o">|=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">(</span><span class="o">**</span><span class="n">predicate</span><span class="p">)</span>
6211
+ <a id="__codelineno-0-514" name="__codelineno-0-514"></a>
6212
+ <a id="__codelineno-0-515" name="__codelineno-0-515"></a> <span class="k">return</span> <span class="n">query</span>
6213
+ <a id="__codelineno-0-516" name="__codelineno-0-516"></a>
6214
+ <a id="__codelineno-0-517" name="__codelineno-0-517"></a> <span class="k">def</span> <span class="nf">filter</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">qs</span><span class="p">,</span> <span class="n">value</span><span class="p">):</span>
6215
+ <a id="__codelineno-0-518" name="__codelineno-0-518"></a> <span class="k">if</span> <span class="n">value</span> <span class="ow">in</span> <span class="n">EMPTY_VALUES</span><span class="p">:</span>
6216
+ <a id="__codelineno-0-519" name="__codelineno-0-519"></a> <span class="k">return</span> <span class="n">qs</span>
6217
+ <a id="__codelineno-0-520" name="__codelineno-0-520"></a>
6218
+ <a id="__codelineno-0-521" name="__codelineno-0-521"></a> <span class="c1"># Fetch the generated Q object and filter the incoming qs with it before passing it along.</span>
6219
+ <a id="__codelineno-0-522" name="__codelineno-0-522"></a> <span class="n">query</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">generate_query</span><span class="p">(</span><span class="n">value</span><span class="p">)</span>
6220
+ <a id="__codelineno-0-523" name="__codelineno-0-523"></a> <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">get_method</span><span class="p">(</span><span class="n">qs</span><span class="p">)(</span><span class="n">query</span><span class="p">)</span>
5053
6221
  </code></pre></div></td></tr></table></div>
5054
6222
  </details>
5055
6223
 
@@ -5081,7 +6249,8 @@ would match both "Athens" and "Durham".</p>
5081
6249
 
5082
6250
  <details class="quote">
5083
6251
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
5084
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-490">490</a></span>
6252
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-489">489</a></span>
6253
+ <span class="normal"><a href="#__codelineno-0-490">490</a></span>
5085
6254
  <span class="normal"><a href="#__codelineno-0-491">491</a></span>
5086
6255
  <span class="normal"><a href="#__codelineno-0-492">492</a></span>
5087
6256
  <span class="normal"><a href="#__codelineno-0-493">493</a></span>
@@ -5106,34 +6275,33 @@ would match both "Athens" and "Durham".</p>
5106
6275
  <span class="normal"><a href="#__codelineno-0-512">512</a></span>
5107
6276
  <span class="normal"><a href="#__codelineno-0-513">513</a></span>
5108
6277
  <span class="normal"><a href="#__codelineno-0-514">514</a></span>
5109
- <span class="normal"><a href="#__codelineno-0-515">515</a></span>
5110
- <span class="normal"><a href="#__codelineno-0-516">516</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="k">def</span> <span class="nf">generate_query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">qs</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>
5111
- <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5112
- <a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> Given a filter value, return a `Q` object that accounts for nested tree node descendants.</span>
5113
- <a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> &quot;&quot;&quot;</span>
5114
- <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
5115
- <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="c1"># django-tree-queries</span>
5116
- <a id="__codelineno-0-496" name="__codelineno-0-496"></a> <span class="n">value</span> <span class="o">=</span> <span class="p">[</span><span class="n">node</span><span class="o">.</span><span class="n">descendants</span><span class="p">(</span><span class="n">include_self</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">value</span><span class="p">]</span>
5117
- <a id="__codelineno-0-497" name="__codelineno-0-497"></a>
5118
- <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="c1"># This new_value is going to be a list of querysets that needs to be flattened.</span>
5119
- <a id="__codelineno-0-499" name="__codelineno-0-499"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">data_utils</span><span class="o">.</span><span class="n">flatten_iterable</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
5120
- <a id="__codelineno-0-500" name="__codelineno-0-500"></a>
5121
- <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="c1"># Construct a list of filter predicates that will be used to generate the Q object.</span>
5122
- <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="n">predicates</span> <span class="o">=</span> <span class="p">[]</span>
5123
- <a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
5124
- <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="c1"># Try to get the `to_field_name` (e.g. `slug`) or just pass the object through.</span>
5125
- <a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
5126
- <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="k">if</span> <span class="n">val</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_value</span><span class="p">:</span>
5127
- <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="n">val</span> <span class="o">=</span> <span class="kc">None</span>
5128
- <a id="__codelineno-0-508" name="__codelineno-0-508"></a> <span class="n">predicates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_filter_predicate</span><span class="p">(</span><span class="n">val</span><span class="p">))</span>
5129
- <a id="__codelineno-0-509" name="__codelineno-0-509"></a>
5130
- <a id="__codelineno-0-510" name="__codelineno-0-510"></a> <span class="c1"># Construct a nested OR query from the list of filter predicates derived from the flattened</span>
5131
- <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="c1"># listed of descendant objects.</span>
5132
- <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="n">query</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">()</span>
5133
- <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="k">for</span> <span class="n">predicate</span> <span class="ow">in</span> <span class="n">predicates</span><span class="p">:</span>
5134
- <a id="__codelineno-0-514" name="__codelineno-0-514"></a> <span class="n">query</span> <span class="o">|=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">(</span><span class="o">**</span><span class="n">predicate</span><span class="p">)</span>
5135
- <a id="__codelineno-0-515" name="__codelineno-0-515"></a>
5136
- <a id="__codelineno-0-516" name="__codelineno-0-516"></a> <span class="k">return</span> <span class="n">query</span>
6278
+ <span class="normal"><a href="#__codelineno-0-515">515</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-489" name="__codelineno-0-489"></a><span class="k">def</span> <span class="nf">generate_query</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">value</span><span class="p">,</span> <span class="n">qs</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>
6279
+ <a id="__codelineno-0-490" name="__codelineno-0-490"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
6280
+ <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="sd"> Given a filter value, return a `Q` object that accounts for nested tree node descendants.</span>
6281
+ <a id="__codelineno-0-492" name="__codelineno-0-492"></a><span class="sd"> &quot;&quot;&quot;</span>
6282
+ <a id="__codelineno-0-493" name="__codelineno-0-493"></a> <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
6283
+ <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="c1"># django-tree-queries</span>
6284
+ <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="n">value</span> <span class="o">=</span> <span class="p">[</span><span class="n">node</span><span class="o">.</span><span class="n">descendants</span><span class="p">(</span><span class="n">include_self</span><span class="o">=</span><span class="kc">True</span><span class="p">)</span> <span class="k">if</span> <span class="ow">not</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">node</span><span class="p">,</span> <span class="nb">str</span><span class="p">)</span> <span class="k">else</span> <span class="n">node</span> <span class="k">for</span> <span class="n">node</span> <span class="ow">in</span> <span class="n">value</span><span class="p">]</span>
6285
+ <a id="__codelineno-0-496" name="__codelineno-0-496"></a>
6286
+ <a id="__codelineno-0-497" name="__codelineno-0-497"></a> <span class="c1"># This new_value is going to be a list of querysets that needs to be flattened.</span>
6287
+ <a id="__codelineno-0-498" name="__codelineno-0-498"></a> <span class="n">value</span> <span class="o">=</span> <span class="nb">list</span><span class="p">(</span><span class="n">data_utils</span><span class="o">.</span><span class="n">flatten_iterable</span><span class="p">(</span><span class="n">value</span><span class="p">))</span>
6288
+ <a id="__codelineno-0-499" name="__codelineno-0-499"></a>
6289
+ <a id="__codelineno-0-500" name="__codelineno-0-500"></a> <span class="c1"># Construct a list of filter predicates that will be used to generate the Q object.</span>
6290
+ <a id="__codelineno-0-501" name="__codelineno-0-501"></a> <span class="n">predicates</span> <span class="o">=</span> <span class="p">[]</span>
6291
+ <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="k">for</span> <span class="n">obj</span> <span class="ow">in</span> <span class="n">value</span><span class="p">:</span>
6292
+ <a id="__codelineno-0-503" name="__codelineno-0-503"></a> <span class="c1"># Try to get the `to_field_name` (e.g. `slug`) or just pass the object through.</span>
6293
+ <a id="__codelineno-0-504" name="__codelineno-0-504"></a> <span class="n">val</span> <span class="o">=</span> <span class="nb">getattr</span><span class="p">(</span><span class="n">obj</span><span class="p">,</span> <span class="bp">self</span><span class="o">.</span><span class="n">field</span><span class="o">.</span><span class="n">to_field_name</span><span class="p">,</span> <span class="n">obj</span><span class="p">)</span>
6294
+ <a id="__codelineno-0-505" name="__codelineno-0-505"></a> <span class="k">if</span> <span class="n">val</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">null_value</span><span class="p">:</span>
6295
+ <a id="__codelineno-0-506" name="__codelineno-0-506"></a> <span class="n">val</span> <span class="o">=</span> <span class="kc">None</span>
6296
+ <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="n">predicates</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">get_filter_predicate</span><span class="p">(</span><span class="n">val</span><span class="p">))</span>
6297
+ <a id="__codelineno-0-508" name="__codelineno-0-508"></a>
6298
+ <a id="__codelineno-0-509" name="__codelineno-0-509"></a> <span class="c1"># Construct a nested OR query from the list of filter predicates derived from the flattened</span>
6299
+ <a id="__codelineno-0-510" name="__codelineno-0-510"></a> <span class="c1"># listed of descendant objects.</span>
6300
+ <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="n">query</span> <span class="o">=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">()</span>
6301
+ <a id="__codelineno-0-512" name="__codelineno-0-512"></a> <span class="k">for</span> <span class="n">predicate</span> <span class="ow">in</span> <span class="n">predicates</span><span class="p">:</span>
6302
+ <a id="__codelineno-0-513" name="__codelineno-0-513"></a> <span class="n">query</span> <span class="o">|=</span> <span class="n">models</span><span class="o">.</span><span class="n">Q</span><span class="p">(</span><span class="o">**</span><span class="n">predicate</span><span class="p">)</span>
6303
+ <a id="__codelineno-0-514" name="__codelineno-0-514"></a>
6304
+ <a id="__codelineno-0-515" name="__codelineno-0-515"></a> <span class="k">return</span> <span class="n">query</span>
5137
6305
  </code></pre></div></td></tr></table></div>
5138
6306
  </details>
5139
6307
  </div>