nautobot 2.0.0a2__py3-none-any.whl → 2.0.0b1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (1029) hide show
  1. nautobot/__init__.py +1 -5
  2. nautobot/apps/api.py +6 -8
  3. nautobot/apps/forms.py +0 -2
  4. nautobot/apps/ui.py +0 -8
  5. nautobot/circuits/api/serializers.py +9 -119
  6. nautobot/circuits/api/urls.py +1 -1
  7. nautobot/circuits/api/views.py +0 -1
  8. nautobot/circuits/choices.py +0 -2
  9. nautobot/circuits/filters.py +7 -6
  10. nautobot/circuits/forms.py +3 -73
  11. nautobot/circuits/migrations/0001_initial_part_1.py +0 -1
  12. nautobot/circuits/migrations/0002_initial_part_2.py +0 -1
  13. nautobot/circuits/migrations/0003_auto_slug.py +0 -1
  14. nautobot/circuits/migrations/0004_increase_provider_account_length.py +0 -1
  15. nautobot/circuits/migrations/0005_providernetwork.py +0 -1
  16. nautobot/circuits/migrations/0006_cache_circuit_terminations.py +0 -1
  17. nautobot/circuits/migrations/0007_circuitterminations_primary_model.py +0 -1
  18. nautobot/circuits/migrations/0008_add_natural_indexing.py +0 -1
  19. nautobot/circuits/migrations/0009_circuittermination_location.py +0 -1
  20. nautobot/circuits/migrations/0010_rename_foreign_keys_and_related_names.py +0 -1
  21. nautobot/circuits/migrations/0011_remove_site_foreign_key_from_circuit_termination_class.py +0 -1
  22. nautobot/circuits/migrations/0012_created_datetime.py +0 -1
  23. nautobot/circuits/migrations/0013_alter_circuittermination__path.py +0 -1
  24. nautobot/circuits/migrations/0014_related_name_changes.py +1 -2
  25. nautobot/circuits/migrations/0015_remove_circuittype_provider_slug.py +20 -0
  26. nautobot/circuits/migrations/0016_tagsfield.py +34 -0
  27. nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
  28. nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
  29. nautobot/circuits/models.py +3 -93
  30. nautobot/circuits/navigation.py +14 -69
  31. nautobot/circuits/signals.py +0 -2
  32. nautobot/circuits/tables.py +42 -5
  33. nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -1
  34. nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -1
  35. nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -1
  36. nautobot/circuits/templates/circuits/provider_create.html +0 -1
  37. nautobot/circuits/templates/circuits/provider_retrieve.html +1 -1
  38. nautobot/circuits/tests/integration/test_relationships.py +13 -16
  39. nautobot/circuits/tests/test_api.py +13 -43
  40. nautobot/circuits/tests/test_filters.py +20 -15
  41. nautobot/circuits/tests/test_models.py +7 -3
  42. nautobot/circuits/tests/test_views.py +57 -67
  43. nautobot/circuits/views.py +18 -9
  44. nautobot/core/api/__init__.py +8 -2
  45. nautobot/core/api/authentication.py +0 -3
  46. nautobot/core/api/fields.py +15 -6
  47. nautobot/core/api/filter_backends.py +3 -2
  48. nautobot/core/api/metadata.py +237 -30
  49. nautobot/core/api/mixins.py +94 -0
  50. nautobot/core/api/pagination.py +3 -3
  51. nautobot/core/api/parsers.py +154 -0
  52. nautobot/core/api/renderers.py +153 -2
  53. nautobot/core/api/schema.py +47 -3
  54. nautobot/core/api/serializers.py +377 -37
  55. nautobot/core/api/urls.py +11 -3
  56. nautobot/core/api/utils.py +174 -2
  57. nautobot/core/api/versioning.py +32 -10
  58. nautobot/core/api/views.py +266 -75
  59. nautobot/core/apps/__init__.py +138 -221
  60. nautobot/core/celery/__init__.py +112 -41
  61. nautobot/core/celery/backends.py +19 -13
  62. nautobot/core/celery/control.py +46 -0
  63. nautobot/core/celery/encoders.py +53 -0
  64. nautobot/core/celery/log.py +38 -0
  65. nautobot/core/celery/schedulers.py +23 -4
  66. nautobot/core/celery/task.py +1 -16
  67. nautobot/core/checks.py +0 -27
  68. nautobot/core/choices.py +21 -113
  69. nautobot/core/{cli.py → cli/__init__.py} +1 -2
  70. nautobot/core/cli/__main__.py +3 -0
  71. nautobot/core/constants.py +25 -43
  72. nautobot/core/context_processors.py +12 -0
  73. nautobot/core/filters.py +2 -2
  74. nautobot/core/forms/__init__.py +0 -4
  75. nautobot/core/forms/fields.py +39 -68
  76. nautobot/core/forms/forms.py +27 -27
  77. nautobot/core/forms/utils.py +7 -59
  78. nautobot/core/forms/widgets.py +0 -1
  79. nautobot/core/graphql/__init__.py +2 -2
  80. nautobot/core/graphql/schema.py +4 -27
  81. nautobot/core/jobs/__init__.py +75 -0
  82. nautobot/core/management/commands/build_ui.py +255 -0
  83. nautobot/core/management/commands/celery.py +0 -1
  84. nautobot/core/management/commands/generate_test_data.py +18 -13
  85. nautobot/core/management/commands/post_upgrade.py +24 -24
  86. nautobot/core/management/commands/validate_models.py +0 -1
  87. nautobot/core/middleware.py +0 -1
  88. nautobot/core/models/__init__.py +26 -1
  89. nautobot/core/models/fields.py +24 -5
  90. nautobot/core/models/generics.py +2 -46
  91. nautobot/core/models/managers.py +5 -0
  92. nautobot/core/models/name_color_content_types.py +1 -19
  93. nautobot/core/models/tree_queries.py +14 -4
  94. nautobot/core/models/utils.py +9 -10
  95. nautobot/core/models/validators.py +17 -8
  96. nautobot/core/releases.py +8 -10
  97. nautobot/core/settings.py +81 -53
  98. nautobot/core/tables.py +5 -5
  99. nautobot/core/tasks.py +4 -7
  100. nautobot/core/templates/base.html +1 -49
  101. nautobot/core/templates/base_django.html +49 -0
  102. nautobot/core/templates/base_react.html +55 -0
  103. nautobot/core/templates/buttons/export.html +6 -4
  104. nautobot/core/templates/generic/object_bulk_create.html +10 -21
  105. nautobot/core/templates/generic/object_list.html +4 -1
  106. nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
  107. nautobot/core/templates/inc/footer.html +1 -0
  108. nautobot/core/templates/inc/javascript.html +0 -14
  109. nautobot/core/templates/inc/nav_menu.html +28 -33
  110. nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
  111. nautobot/core/templates/inc/relationships_table_rows.html +2 -2
  112. nautobot/core/templates/nautobot_config.py.j2 +8 -25
  113. nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
  114. nautobot/core/templates/rest_framework/api.html +8 -0
  115. nautobot/core/templatetags/buttons.py +32 -29
  116. nautobot/core/templatetags/helpers.py +1 -1
  117. nautobot/core/testing/__init__.py +47 -44
  118. nautobot/core/testing/api.py +365 -47
  119. nautobot/core/testing/filters.py +12 -7
  120. nautobot/core/testing/integration.py +1 -1
  121. nautobot/core/testing/migrations.py +2 -0
  122. nautobot/core/testing/mixins.py +22 -12
  123. nautobot/core/testing/schema.py +2 -1
  124. nautobot/core/testing/views.py +28 -51
  125. nautobot/core/tests/integration/test_filters.py +17 -8
  126. nautobot/core/tests/integration/test_navbar.py +11 -34
  127. nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
  128. nautobot/core/tests/nautobot_config.py +2 -3
  129. nautobot/core/tests/runner.py +0 -1
  130. nautobot/core/tests/test_api.py +290 -24
  131. nautobot/core/tests/test_authentication.py +57 -14
  132. nautobot/core/tests/test_checks.py +0 -7
  133. nautobot/core/tests/test_choices.py +0 -1
  134. nautobot/core/tests/test_filters.py +117 -110
  135. nautobot/core/tests/test_forms.py +47 -110
  136. nautobot/core/tests/test_graphql.py +158 -135
  137. nautobot/core/tests/test_logging.py +4 -1
  138. nautobot/core/tests/test_managers.py +3 -5
  139. nautobot/core/tests/test_models.py +2 -0
  140. nautobot/core/tests/test_ordering.py +0 -2
  141. nautobot/core/tests/test_paginator.py +3 -1
  142. nautobot/core/tests/test_releases.py +12 -12
  143. nautobot/core/tests/test_templatetags_helpers.py +7 -4
  144. nautobot/core/tests/test_utils.py +112 -78
  145. nautobot/core/tests/test_views.py +12 -17
  146. nautobot/core/tests/test_views_utils.py +6 -9
  147. nautobot/core/utils/data.py +17 -0
  148. nautobot/core/utils/deprecation.py +13 -20
  149. nautobot/core/utils/filtering.py +53 -9
  150. nautobot/core/utils/git.py +12 -4
  151. nautobot/core/utils/lookup.py +3 -1
  152. nautobot/core/utils/requests.py +23 -116
  153. nautobot/core/views/__init__.py +1 -2
  154. nautobot/core/views/generic.py +131 -119
  155. nautobot/core/views/mixins.py +53 -62
  156. nautobot/core/views/paginator.py +0 -1
  157. nautobot/core/views/renderers.py +14 -12
  158. nautobot/core/views/utils.py +87 -4
  159. nautobot/dcim/api/serializers.py +160 -672
  160. nautobot/dcim/api/urls.py +1 -1
  161. nautobot/dcim/api/views.py +7 -46
  162. nautobot/dcim/choices.py +2 -25
  163. nautobot/dcim/elevations.py +0 -1
  164. nautobot/dcim/factory.py +15 -4
  165. nautobot/dcim/filters/__init__.py +42 -13
  166. nautobot/dcim/form_mixins.py +1 -27
  167. nautobot/dcim/forms.py +58 -797
  168. nautobot/dcim/management/commands/trace_paths.py +0 -1
  169. nautobot/dcim/migrations/0001_initial_part_1.py +0 -1
  170. nautobot/dcim/migrations/0002_initial_part_2.py +0 -1
  171. nautobot/dcim/migrations/0003_initial_part_3.py +0 -1
  172. nautobot/dcim/migrations/0004_initial_part_4.py +0 -1
  173. nautobot/dcim/migrations/0005_device_local_context_schema.py +0 -1
  174. nautobot/dcim/migrations/0006_auto_slug.py +0 -1
  175. nautobot/dcim/migrations/0007_device_secrets_group.py +0 -1
  176. nautobot/dcim/migrations/0008_increase_all_serial_lengths.py +0 -1
  177. nautobot/dcim/migrations/0009_add_natural_indexing.py +0 -1
  178. nautobot/dcim/migrations/0010_interface_status.py +0 -1
  179. nautobot/dcim/migrations/0011_interface_status_data_migration.py +0 -1
  180. nautobot/dcim/migrations/0012_interface_parent_bridge.py +0 -1
  181. nautobot/dcim/migrations/0013_location_location_type.py +0 -1
  182. nautobot/dcim/migrations/0014_location_status_data_migration.py +0 -1
  183. nautobot/dcim/migrations/0015_device_components__changeloggedmodel.py +0 -1
  184. nautobot/dcim/migrations/0016_device_components__timestamp_data_migration.py +0 -1
  185. nautobot/dcim/migrations/0017_locationtype_nestable.py +0 -1
  186. nautobot/dcim/migrations/0018_device_redundancy_group.py +0 -1
  187. nautobot/dcim/migrations/0019_device_redundancy_group_data_migration.py +0 -1
  188. nautobot/dcim/migrations/0020_move_site_fields_to_location_model.py +0 -1
  189. nautobot/dcim/migrations/0021_mptt_to_tree_queries.py +0 -1
  190. nautobot/dcim/migrations/0022_interface_mac_address_data_migration.py +0 -1
  191. nautobot/dcim/migrations/0023_alter_interface_mac_address.py +0 -1
  192. nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -2
  193. nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -14
  194. nautobot/dcim/migrations/0026_rename_device_and_rack_role.py +0 -1
  195. nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -2
  196. nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -2
  197. nautobot/dcim/migrations/0029_add_tree_managers_and_foreign_keys_pre_data_migration.py +0 -1
  198. nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
  199. nautobot/dcim/migrations/0031_rename_path_end_point_related_name.py +0 -1
  200. nautobot/dcim/migrations/0032_remove_site_foreign_key_from_dcim_models.py +0 -1
  201. nautobot/dcim/migrations/0033_created_datetime.py +0 -1
  202. nautobot/dcim/migrations/0034_fixup_fks_and_related_names.py +0 -1
  203. nautobot/dcim/migrations/0035_related_name_changes.py +1 -2
  204. nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -2
  205. nautobot/dcim/migrations/0037_interface_ip_addresses_m2m.py +0 -1
  206. nautobot/dcim/migrations/0038_alter_location_managers.py +0 -1
  207. nautobot/dcim/migrations/0039_remove_slug.py +24 -0
  208. nautobot/dcim/migrations/0040_tagsfield.py +109 -0
  209. nautobot/dcim/migrations/0041_ipam__namespaces.py +25 -0
  210. nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
  211. nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
  212. nautobot/dcim/models/cables.py +4 -35
  213. nautobot/dcim/models/device_component_templates.py +7 -2
  214. nautobot/dcim/models/device_components.py +26 -203
  215. nautobot/dcim/models/devices.py +30 -152
  216. nautobot/dcim/models/locations.py +3 -64
  217. nautobot/dcim/models/power.py +3 -51
  218. nautobot/dcim/models/racks.py +7 -86
  219. nautobot/dcim/navigation.py +141 -467
  220. nautobot/dcim/signals.py +0 -2
  221. nautobot/dcim/tables/devices.py +8 -5
  222. nautobot/dcim/tables/devicetypes.py +1 -1
  223. nautobot/dcim/tables/locations.py +2 -2
  224. nautobot/dcim/tables/power.py +2 -2
  225. nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
  226. nautobot/dcim/templates/dcim/device.html +15 -4
  227. nautobot/dcim/templates/dcim/device_edit.html +6 -0
  228. nautobot/dcim/templates/dcim/deviceredundancygroup_create.html +0 -1
  229. nautobot/dcim/templates/dcim/devicetype.html +2 -2
  230. nautobot/dcim/templates/dcim/interface.html +4 -0
  231. nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
  232. nautobot/dcim/templates/dcim/interface_edit.html +1 -0
  233. nautobot/dcim/templates/dcim/location.html +16 -1
  234. nautobot/dcim/templates/dcim/locationtype.html +15 -0
  235. nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
  236. nautobot/dcim/templates/dcim/rackgroup.html +0 -12
  237. nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
  238. nautobot/dcim/tests/test_api.py +202 -130
  239. nautobot/dcim/tests/test_cablepaths.py +47 -42
  240. nautobot/dcim/tests/test_filters.py +156 -134
  241. nautobot/dcim/tests/test_forms.py +12 -213
  242. nautobot/dcim/tests/test_graphql.py +8 -3
  243. nautobot/dcim/tests/test_migrations.py +6 -11
  244. nautobot/dcim/tests/test_models.py +208 -158
  245. nautobot/dcim/tests/test_natural_ordering.py +12 -14
  246. nautobot/dcim/tests/test_signals.py +7 -4
  247. nautobot/dcim/tests/test_views.py +270 -264
  248. nautobot/dcim/urls.py +21 -26
  249. nautobot/dcim/views.py +14 -156
  250. nautobot/docs/additional-features/caching.md +6 -87
  251. nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
  252. nautobot/docs/additional-features/jobs.md +179 -197
  253. nautobot/docs/administration/nautobot-server.md +9 -24
  254. nautobot/docs/administration/nautobot-shell.md +6 -6
  255. nautobot/docs/administration/replicating-nautobot.md +0 -10
  256. nautobot/docs/configuration/index.md +9 -9
  257. nautobot/docs/configuration/optional-settings.md +32 -61
  258. nautobot/docs/configuration/required-settings.md +11 -52
  259. nautobot/docs/development/application-registry.md +2 -13
  260. nautobot/docs/development/best-practices.md +2 -1
  261. nautobot/docs/development/docker-compose-advanced-use-cases.md +1 -1
  262. nautobot/docs/development/extending-models.md +15 -17
  263. nautobot/docs/development/generic-views.md +0 -2
  264. nautobot/docs/development/getting-started.md +56 -6
  265. nautobot/docs/development/navigation-menu.md +22 -93
  266. nautobot/docs/development/react-ui.md +105 -0
  267. nautobot/docs/development/release-checklist.md +3 -3
  268. nautobot/docs/development/role-internals.md +1 -3
  269. nautobot/docs/development/style-guide.md +6 -4
  270. nautobot/docs/development/templates.md +2 -1
  271. nautobot/docs/docker/index.md +16 -14
  272. nautobot/docs/index.md +7 -3
  273. nautobot/docs/installation/index.md +4 -1
  274. nautobot/docs/installation/migrating-from-netbox.md +12 -43
  275. nautobot/docs/installation/migrating-from-postgresql.md +1 -1
  276. nautobot/docs/installation/nautobot.md +1 -1
  277. nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  278. nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  279. nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  280. nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  281. nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
  282. nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  283. nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  284. nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  285. nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  286. nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  287. nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  288. nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  289. nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  290. nautobot/docs/installation/upgrading-from-nautobot-v1.md +190 -636
  291. nautobot/docs/installation/upgrading.md +5 -2
  292. nautobot/docs/models/dcim/device.md +3 -0
  293. nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
  294. nautobot/docs/models/extras/computedfield.md +4 -4
  295. nautobot/docs/models/extras/dynamicgroup.md +9 -9
  296. nautobot/docs/models/extras/gitrepository.md +3 -0
  297. nautobot/docs/models/extras/job.md +1 -0
  298. nautobot/docs/models/extras/jobbutton.md +18 -13
  299. nautobot/docs/models/extras/jobhook.md +7 -4
  300. nautobot/docs/models/extras/jobresult.md +6 -2
  301. nautobot/docs/models/extras/relationship.md +2 -2
  302. nautobot/docs/models/extras/status.md +6 -19
  303. nautobot/docs/models/ipam/ipaddress.md +3 -0
  304. nautobot/docs/models/ipam/vrf.md +0 -3
  305. nautobot/docs/models/virtualization/virtualmachine.md +3 -0
  306. nautobot/docs/plugins/development.md +92 -24
  307. nautobot/docs/release-notes/version-1.5.md +96 -0
  308. nautobot/docs/release-notes/version-2.0.md +216 -0
  309. nautobot/docs/requirements.txt +5 -4
  310. nautobot/docs/rest-api/overview.md +384 -215
  311. nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
  312. nautobot/extras/admin.py +3 -5
  313. nautobot/extras/api/customfields.py +15 -39
  314. nautobot/extras/api/fields.py +0 -11
  315. nautobot/extras/api/mixins.py +45 -0
  316. nautobot/extras/api/relationships.py +63 -159
  317. nautobot/extras/api/serializers.py +165 -706
  318. nautobot/extras/api/urls.py +1 -1
  319. nautobot/extras/api/views.py +295 -282
  320. nautobot/extras/apps.py +4 -7
  321. nautobot/extras/choices.py +11 -22
  322. nautobot/extras/constants.py +9 -3
  323. nautobot/extras/datasources/__init__.py +2 -0
  324. nautobot/extras/datasources/git.py +135 -186
  325. nautobot/extras/datasources/registry.py +25 -35
  326. nautobot/extras/factory.py +1 -3
  327. nautobot/extras/filters/__init__.py +49 -47
  328. nautobot/extras/filters/mixins.py +10 -8
  329. nautobot/extras/forms/forms.py +72 -148
  330. nautobot/extras/forms/mixins.py +34 -57
  331. nautobot/extras/health_checks.py +0 -33
  332. nautobot/extras/jobs.py +387 -566
  333. nautobot/extras/management/__init__.py +55 -48
  334. nautobot/extras/management/commands/renaturalize.py +0 -1
  335. nautobot/extras/management/commands/runjob.py +24 -62
  336. nautobot/extras/management/commands/webhook_receiver.py +0 -1
  337. nautobot/extras/managers.py +30 -7
  338. nautobot/extras/migrations/0001_initial_part_1.py +0 -1
  339. nautobot/extras/migrations/0002_initial_part_2.py +0 -1
  340. nautobot/extras/migrations/0003_initial_part_3.py +0 -1
  341. nautobot/extras/migrations/0004_populate_default_status_records.py +0 -1
  342. nautobot/extras/migrations/0005_configcontext_device_types.py +0 -1
  343. nautobot/extras/migrations/0006_graphqlquery.py +0 -1
  344. nautobot/extras/migrations/0007_configcontextschema.py +0 -1
  345. nautobot/extras/migrations/0008_jobresult__custom_field_data.py +0 -1
  346. nautobot/extras/migrations/0009_computedfield.py +0 -1
  347. nautobot/extras/migrations/0010_change_cf_validation_max_min_field_to_bigint.py +0 -1
  348. nautobot/extras/migrations/0011_fileattachment_fileproxy.py +0 -1
  349. nautobot/extras/migrations/0012_healthchecktestmodel.py +0 -1
  350. nautobot/extras/migrations/0013_default_fallback_value_computedfield.py +0 -1
  351. nautobot/extras/migrations/0014_auto_slug.py +0 -1
  352. nautobot/extras/migrations/0015_scheduled_job.py +0 -1
  353. nautobot/extras/migrations/0016_secret.py +0 -1
  354. nautobot/extras/migrations/0017_joblogentry.py +0 -1
  355. nautobot/extras/migrations/0018_joblog_data_migration.py +0 -2
  356. nautobot/extras/migrations/0019_joblogentry__meta_options__related_name.py +0 -1
  357. nautobot/extras/migrations/0020_customfield_changelog.py +0 -1
  358. nautobot/extras/migrations/0021_customfield_changelog_data.py +0 -1
  359. nautobot/extras/migrations/0022_objectchange_object_datav2.py +0 -1
  360. nautobot/extras/migrations/0023_job_model.py +0 -1
  361. nautobot/extras/migrations/0024_job_data_migration.py +0 -1
  362. nautobot/extras/migrations/0025_add_advanced_ui_boolean_to_customfield_conputedfield_and_relationship.py +0 -1
  363. nautobot/extras/migrations/0026_job_add_gitrepository_fk.py +0 -1
  364. nautobot/extras/migrations/0027_job_gitrepository_data_migration.py +0 -1
  365. nautobot/extras/migrations/0028_job_reduce_source.py +0 -1
  366. nautobot/extras/migrations/0029_dynamicgroup.py +0 -1
  367. nautobot/extras/migrations/0030_webhook_alter_unique_together.py +0 -1
  368. nautobot/extras/migrations/0031_tag_content_types.py +0 -1
  369. nautobot/extras/migrations/0032_tag_content_types_data_migration.py +0 -1
  370. nautobot/extras/migrations/0033_add__optimized_indexing.py +0 -1
  371. nautobot/extras/migrations/0034_alter_fileattachment_mimetype.py +0 -1
  372. nautobot/extras/migrations/0035_scheduledjob_crontab.py +0 -1
  373. nautobot/extras/migrations/0036_job_add_has_sensitive_variables.py +0 -1
  374. nautobot/extras/migrations/0037_configcontextschema__remove_name_unique__create_constraint_unique_name_owner.py +0 -1
  375. nautobot/extras/migrations/0038_configcontext_locations.py +0 -1
  376. nautobot/extras/migrations/0039_objectchange__add_change_context.py +0 -1
  377. nautobot/extras/migrations/0040_dynamicgroup__dynamicgroupmembership.py +0 -1
  378. nautobot/extras/migrations/0041_jobresult_job_kwargs.py +0 -1
  379. nautobot/extras/migrations/0042_job__add_is_job_hook_receiver.py +0 -1
  380. nautobot/extras/migrations/0043_note.py +0 -1
  381. nautobot/extras/migrations/0044_add_job_hook.py +0 -1
  382. nautobot/extras/migrations/0045_add_custom_field_slug.py +0 -1
  383. nautobot/extras/migrations/0046_populate_custom_field_slug_label.py +0 -1
  384. nautobot/extras/migrations/0047_enforce_custom_field_slug.py +0 -1
  385. nautobot/extras/migrations/0048_alter_objectchange_change_context_detail.py +0 -1
  386. nautobot/extras/migrations/0049_alter_tag_slug.py +0 -1
  387. nautobot/extras/migrations/0050_customfield_grouping.py +0 -1
  388. nautobot/extras/migrations/0051_add_job_task_queues.py +0 -1
  389. nautobot/extras/migrations/0052_configcontext_device_redundancy_groups.py +0 -1
  390. nautobot/extras/migrations/0053_relationship_required_on.py +0 -1
  391. nautobot/extras/migrations/0054_scheduledjob_kwargs_request_user_change.py +0 -1
  392. nautobot/extras/migrations/0055_configcontext_dynamic_groups.py +0 -1
  393. nautobot/extras/migrations/0056_objectchange_add_reverse_time_idx.py +0 -1
  394. nautobot/extras/migrations/0057_jobbutton.py +0 -1
  395. nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
  396. nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -2
  397. nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -2
  398. nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -8
  399. nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -33
  400. nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -2
  401. nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -2
  402. nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
  403. nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -2
  404. nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -3
  405. nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -2
  406. nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -2
  407. nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
  408. nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -2
  409. nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
  410. nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -10
  411. nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -2
  412. nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
  413. nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
  414. nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
  415. nautobot/extras/migrations/0078_remove_slug.py +45 -0
  416. nautobot/extras/migrations/0079_tagsfield.py +28 -0
  417. nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
  418. nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
  419. nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
  420. nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
  421. nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
  422. nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
  423. nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
  424. nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
  425. nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
  426. nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
  427. nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
  428. nautobot/extras/models/__init__.py +2 -3
  429. nautobot/extras/models/change_logging.py +0 -36
  430. nautobot/extras/models/customfields.py +39 -33
  431. nautobot/extras/models/datasources.py +48 -50
  432. nautobot/extras/models/groups.py +5 -12
  433. nautobot/extras/models/jobs.py +190 -323
  434. nautobot/extras/models/mixins.py +0 -71
  435. nautobot/extras/models/models.py +1 -22
  436. nautobot/extras/models/relationships.py +20 -21
  437. nautobot/extras/models/roles.py +0 -23
  438. nautobot/extras/models/secrets.py +2 -31
  439. nautobot/extras/models/statuses.py +6 -5
  440. nautobot/extras/models/tags.py +2 -17
  441. nautobot/extras/navigation.py +89 -307
  442. nautobot/extras/plugins/__init__.py +3 -121
  443. nautobot/extras/plugins/utils.py +0 -3
  444. nautobot/extras/plugins/validators.py +5 -4
  445. nautobot/extras/plugins/views.py +16 -4
  446. nautobot/extras/querysets.py +1 -7
  447. nautobot/extras/registry.py +3 -0
  448. nautobot/extras/signals.py +26 -60
  449. nautobot/extras/tables.py +42 -49
  450. nautobot/extras/tasks.py +0 -12
  451. nautobot/extras/templates/extras/configcontext.html +1 -1
  452. nautobot/extras/templates/extras/configcontextschema.html +16 -1
  453. nautobot/extras/templates/extras/customfield.html +0 -13
  454. nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -1
  455. nautobot/extras/templates/extras/gitrepository.html +3 -3
  456. nautobot/extras/templates/extras/inc/jobresult.html +10 -0
  457. nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
  458. nautobot/extras/templates/extras/job.html +35 -25
  459. nautobot/extras/templates/extras/job_approval_request.html +15 -30
  460. nautobot/extras/templates/extras/job_detail.html +13 -31
  461. nautobot/extras/templates/extras/job_edit.html +14 -17
  462. nautobot/extras/templates/extras/jobresult.html +24 -6
  463. nautobot/extras/templates/extras/objectchange_list.html +1 -1
  464. nautobot/extras/templates/extras/scheduledjob.html +2 -2
  465. nautobot/extras/templates/extras/secret.html +28 -0
  466. nautobot/extras/templates/extras/secret_edit.html +0 -1
  467. nautobot/extras/templates/extras/secretsgroup_edit.html +0 -1
  468. nautobot/extras/templatetags/custom_links.py +0 -2
  469. nautobot/extras/templatetags/job_buttons.py +1 -0
  470. nautobot/extras/templatetags/plugins.py +0 -1
  471. nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
  472. nautobot/extras/test_jobs/atomic_transaction.py +53 -0
  473. nautobot/extras/test_jobs/dry_run.py +29 -0
  474. nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
  475. nautobot/extras/test_jobs/duplicate_name2.py +9 -0
  476. nautobot/extras/test_jobs/fail.py +23 -0
  477. nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
  478. nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
  479. nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
  480. nautobot/extras/test_jobs/file_upload_pass.py +25 -0
  481. nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
  482. nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
  483. nautobot/extras/test_jobs/job_button_receiver.py +28 -0
  484. nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
  485. nautobot/extras/test_jobs/job_variables.py +88 -0
  486. nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
  487. nautobot/extras/test_jobs/log_redaction.py +20 -0
  488. nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
  489. nautobot/extras/test_jobs/modify_db.py +25 -0
  490. nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
  491. nautobot/extras/test_jobs/object_var_optional.py +21 -0
  492. nautobot/extras/test_jobs/object_var_required.py +21 -0
  493. nautobot/extras/test_jobs/object_vars.py +26 -0
  494. nautobot/extras/test_jobs/pass.py +25 -0
  495. nautobot/extras/test_jobs/profiling.py +32 -0
  496. nautobot/extras/test_jobs/read_only_job.py +15 -0
  497. nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
  498. nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
  499. nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
  500. nautobot/extras/tests/integration/__init__.py +3 -3
  501. nautobot/extras/tests/integration/test_computedfields.py +1 -1
  502. nautobot/extras/tests/integration/test_configcontextschema.py +7 -5
  503. nautobot/extras/tests/integration/test_customfields.py +4 -2
  504. nautobot/extras/tests/integration/test_dynamicgroups.py +2 -2
  505. nautobot/extras/tests/integration/test_jobs.py +25 -27
  506. nautobot/extras/tests/integration/test_notes.py +8 -4
  507. nautobot/extras/tests/integration/test_plugins.py +4 -4
  508. nautobot/extras/tests/integration/test_relationships.py +2 -2
  509. nautobot/extras/tests/test_api.py +371 -381
  510. nautobot/extras/tests/test_changelog.py +17 -16
  511. nautobot/extras/tests/test_context_managers.py +5 -6
  512. nautobot/extras/tests/test_customfields.py +112 -73
  513. nautobot/extras/tests/test_datasources.py +191 -117
  514. nautobot/extras/tests/test_dynamicgroups.py +45 -68
  515. nautobot/extras/tests/test_filters.py +170 -130
  516. nautobot/extras/tests/test_forms.py +107 -109
  517. nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
  518. nautobot/extras/tests/test_jobs.py +271 -273
  519. nautobot/extras/tests/test_management.py +3 -6
  520. nautobot/extras/tests/test_migrations.py +5 -3
  521. nautobot/extras/tests/test_models.py +121 -173
  522. nautobot/extras/tests/test_notes.py +0 -1
  523. nautobot/extras/tests/test_plugins.py +55 -89
  524. nautobot/extras/tests/test_relationships.py +174 -130
  525. nautobot/extras/tests/test_tags.py +6 -12
  526. nautobot/extras/tests/test_utils.py +31 -1
  527. nautobot/extras/tests/test_views.py +223 -184
  528. nautobot/extras/tests/test_webhooks.py +16 -15
  529. nautobot/extras/urls.py +69 -69
  530. nautobot/extras/utils.py +137 -163
  531. nautobot/extras/views.py +81 -153
  532. nautobot/ipam/api/fields.py +17 -0
  533. nautobot/ipam/api/serializers.py +77 -164
  534. nautobot/ipam/api/urls.py +4 -1
  535. nautobot/ipam/api/views.py +28 -19
  536. nautobot/ipam/apps.py +1 -0
  537. nautobot/ipam/choices.py +5 -12
  538. nautobot/ipam/constants.py +1 -0
  539. nautobot/ipam/factory.py +41 -30
  540. nautobot/ipam/filters.py +58 -25
  541. nautobot/ipam/forms.py +82 -211
  542. nautobot/ipam/graphql/types.py +0 -9
  543. nautobot/ipam/lookups.py +13 -8
  544. nautobot/ipam/management/commands/__init__.py +0 -0
  545. nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
  546. nautobot/ipam/migrations/0001_initial_part_1.py +0 -1
  547. nautobot/ipam/migrations/0002_initial_part_2.py +0 -1
  548. nautobot/ipam/migrations/0003_remove_max_length.py +0 -1
  549. nautobot/ipam/migrations/0004_fixup_p2p_broadcast.py +0 -1
  550. nautobot/ipam/migrations/0005_auto_slug.py +0 -1
  551. nautobot/ipam/migrations/0006_ipaddress_nat_outside_list.py +0 -1
  552. nautobot/ipam/migrations/0007_add_natural_indexing.py +0 -1
  553. nautobot/ipam/migrations/0008_prefix_vlan_vlangroup_location.py +0 -1
  554. nautobot/ipam/migrations/0009_alter_vlan_name.py +0 -1
  555. nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -2
  556. nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -39
  557. nautobot/ipam/migrations/0012_rename_ipam_roles.py +0 -1
  558. nautobot/ipam/migrations/0013_delete_role.py +0 -1
  559. nautobot/ipam/migrations/0014_rename_foreign_keys_and_related_names.py +0 -1
  560. nautobot/ipam/migrations/0015_prefix_add_type.py +0 -1
  561. nautobot/ipam/migrations/0016_prefix_type_data_migration.py +0 -3
  562. nautobot/ipam/migrations/0017_prefix_remove_is_pool.py +0 -1
  563. nautobot/ipam/migrations/0018_remove_site_foreign_key_from_ipam_models.py +0 -1
  564. nautobot/ipam/migrations/0019_created_datetime.py +0 -1
  565. nautobot/ipam/migrations/0020_related_name_changes.py +1 -2
  566. nautobot/ipam/migrations/0021_prefix_add_rir_and_date_allocated.py +0 -1
  567. nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +3 -5
  568. nautobot/ipam/migrations/0023_delete_aggregate.py +0 -1
  569. nautobot/ipam/migrations/0024_interface_to_ipaddress_m2m.py +0 -1
  570. nautobot/ipam/migrations/0025_interface_ipaddress_m2m_data_migration.py +0 -1
  571. nautobot/ipam/migrations/0026_ipaddress_remove_assigned_object.py +0 -1
  572. nautobot/ipam/migrations/0027_remove_rir_slug.py +16 -0
  573. nautobot/ipam/migrations/0028_tagsfield.py +44 -0
  574. nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
  575. nautobot/ipam/migrations/0030_ipam__namespaces.py +231 -0
  576. nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
  577. nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
  578. nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
  579. nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
  580. nautobot/ipam/models.py +579 -368
  581. nautobot/ipam/navigation.py +36 -159
  582. nautobot/ipam/querysets.py +117 -90
  583. nautobot/ipam/signals.py +89 -0
  584. nautobot/ipam/tables.py +86 -28
  585. nautobot/ipam/templates/ipam/ipaddress.html +14 -30
  586. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -0
  587. nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
  588. nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
  589. nautobot/ipam/templates/ipam/namespace_retrieve.html +42 -0
  590. nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
  591. nautobot/ipam/templates/ipam/prefix.html +27 -33
  592. nautobot/ipam/templates/ipam/prefix_edit.html +7 -1
  593. nautobot/ipam/templates/ipam/vlangroup.html +0 -13
  594. nautobot/ipam/templates/ipam/vrf.html +6 -4
  595. nautobot/ipam/templates/ipam/vrf_edit.html +20 -2
  596. nautobot/ipam/tests/integration/test_prefixes.py +4 -27
  597. nautobot/ipam/tests/test_api.py +60 -61
  598. nautobot/ipam/tests/test_filters.py +187 -126
  599. nautobot/ipam/tests/test_forms.py +12 -6
  600. nautobot/ipam/tests/test_graphql.py +8 -6
  601. nautobot/ipam/tests/test_migrations.py +8 -13
  602. nautobot/ipam/tests/test_models.py +426 -274
  603. nautobot/ipam/tests/test_ordering.py +6 -3
  604. nautobot/ipam/tests/test_querysets.py +340 -96
  605. nautobot/ipam/tests/test_views.py +100 -55
  606. nautobot/ipam/urls.py +28 -5
  607. nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
  608. nautobot/ipam/utils/migrations.py +713 -0
  609. nautobot/ipam/views.py +237 -122
  610. nautobot/project-static/docs/404.html +1399 -166
  611. nautobot/project-static/docs/additional-features/caching.html +1416 -320
  612. nautobot/project-static/docs/additional-features/change-logging.html +1389 -190
  613. nautobot/project-static/docs/additional-features/config-contexts.html +1389 -190
  614. nautobot/project-static/docs/additional-features/graphql.html +1389 -190
  615. nautobot/project-static/docs/additional-features/healthcheck.html +1389 -190
  616. nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1393 -190
  617. nautobot/project-static/docs/additional-features/jobs.html +1677 -460
  618. nautobot/project-static/docs/additional-features/napalm.html +1389 -190
  619. nautobot/project-static/docs/additional-features/prometheus-metrics.html +1389 -190
  620. nautobot/project-static/docs/additional-features/template-filters.html +1389 -190
  621. nautobot/project-static/docs/administration/celery-queues.html +1389 -190
  622. nautobot/project-static/docs/administration/nautobot-server.html +1553 -375
  623. nautobot/project-static/docs/administration/nautobot-shell.html +1395 -196
  624. nautobot/project-static/docs/administration/permissions.html +1389 -190
  625. nautobot/project-static/docs/administration/replicating-nautobot.html +1387 -207
  626. nautobot/project-static/docs/apps/index.html +1389 -190
  627. nautobot/project-static/docs/apps/nautobot-apps.html +1387 -175
  628. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js +29 -0
  629. nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js.map +8 -0
  630. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js → search.208ed371.min.js} +9 -15
  631. nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js.map → search.208ed371.min.js.map} +4 -4
  632. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css +1 -0
  633. nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css.map +1 -0
  634. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css +1 -0
  635. nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css.map +1 -0
  636. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1775 -590
  637. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1389 -190
  638. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3588 -1922
  639. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1461 -262
  640. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1401 -170
  641. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1396 -191
  642. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +2095 -894
  643. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2357 -1194
  644. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2258 -940
  645. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1389 -190
  646. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1400 -201
  647. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11068 -7861
  648. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2867 -2224
  649. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1389 -190
  650. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2641 -1573
  651. nautobot/project-static/docs/configuration/authentication/ldap.html +1389 -190
  652. nautobot/project-static/docs/configuration/authentication/remote.html +1389 -190
  653. nautobot/project-static/docs/configuration/authentication/sso.html +1389 -190
  654. nautobot/project-static/docs/configuration/index.html +1398 -199
  655. nautobot/project-static/docs/configuration/optional-settings.html +1418 -274
  656. nautobot/project-static/docs/configuration/required-settings.html +1419 -287
  657. nautobot/project-static/docs/core-functionality/circuits.html +1446 -247
  658. nautobot/project-static/docs/core-functionality/device-types.html +1448 -249
  659. nautobot/project-static/docs/core-functionality/devices.html +1452 -249
  660. nautobot/project-static/docs/core-functionality/ipam.html +1452 -253
  661. nautobot/project-static/docs/core-functionality/power.html +1448 -249
  662. nautobot/project-static/docs/core-functionality/secrets.html +1448 -249
  663. nautobot/project-static/docs/core-functionality/services.html +1448 -249
  664. nautobot/project-static/docs/core-functionality/sites-and-racks.html +1448 -249
  665. nautobot/project-static/docs/core-functionality/tenancy.html +1448 -249
  666. nautobot/project-static/docs/core-functionality/virtualization.html +1452 -249
  667. nautobot/project-static/docs/core-functionality/vlans.html +1448 -249
  668. nautobot/project-static/docs/development/application-registry.html +1393 -214
  669. nautobot/project-static/docs/development/best-practices.html +1392 -192
  670. nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1390 -191
  671. nautobot/project-static/docs/development/extending-models.html +1443 -257
  672. nautobot/project-static/docs/development/generic-views.html +1403 -174
  673. nautobot/project-static/docs/development/getting-started.html +1568 -262
  674. nautobot/project-static/docs/development/homepage.html +1389 -190
  675. nautobot/project-static/docs/development/index.html +1389 -190
  676. nautobot/project-static/docs/development/model-features.html +1389 -190
  677. nautobot/project-static/docs/development/natural-keys.html +1389 -190
  678. nautobot/project-static/docs/development/navigation-menu.html +1451 -330
  679. nautobot/project-static/docs/development/react-ui.html +4199 -0
  680. nautobot/project-static/docs/development/release-checklist.html +1392 -193
  681. nautobot/project-static/docs/development/role-internals.html +1402 -172
  682. nautobot/project-static/docs/development/style-guide.html +1399 -199
  683. nautobot/project-static/docs/development/templates.html +1391 -191
  684. nautobot/project-static/docs/development/testing.html +1389 -190
  685. nautobot/project-static/docs/development/user-preferences.html +1389 -190
  686. nautobot/project-static/docs/docker/index.html +1408 -206
  687. nautobot/project-static/docs/index.html +1397 -180
  688. nautobot/project-static/docs/installation/centos.html +1401 -170
  689. nautobot/project-static/docs/installation/external-authentication.html +1389 -190
  690. nautobot/project-static/docs/installation/http-server.html +1389 -190
  691. nautobot/project-static/docs/installation/index.html +1394 -191
  692. nautobot/project-static/docs/installation/migrating-from-netbox.html +1452 -305
  693. nautobot/project-static/docs/installation/migrating-from-postgresql.html +1390 -191
  694. nautobot/project-static/docs/installation/nautobot.html +1390 -191
  695. nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1389 -190
  696. nautobot/project-static/docs/installation/selinux-troubleshooting.html +1401 -170
  697. nautobot/project-static/docs/installation/services.html +1389 -190
  698. nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
  699. nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
  700. nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
  701. nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
  702. nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
  703. nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
  704. nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
  705. nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
  706. nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
  707. nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
  708. nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
  709. nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
  710. nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
  711. nautobot/project-static/docs/installation/ubuntu.html +1401 -170
  712. nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +4254 -1923
  713. nautobot/project-static/docs/installation/upgrading.html +1395 -192
  714. nautobot/project-static/docs/models/circuits/circuit.html +1427 -174
  715. nautobot/project-static/docs/models/circuits/circuittermination.html +1427 -174
  716. nautobot/project-static/docs/models/circuits/circuittype.html +1427 -174
  717. nautobot/project-static/docs/models/circuits/provider.html +1427 -174
  718. nautobot/project-static/docs/models/circuits/providernetwork.html +1427 -174
  719. nautobot/project-static/docs/models/dcim/cable.html +1458 -174
  720. nautobot/project-static/docs/models/dcim/consoleport.html +1427 -174
  721. nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1427 -174
  722. nautobot/project-static/docs/models/dcim/consoleserverport.html +1427 -174
  723. nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1427 -174
  724. nautobot/project-static/docs/models/dcim/device.html +1431 -174
  725. nautobot/project-static/docs/models/dcim/devicebay.html +1427 -174
  726. nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1427 -174
  727. nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1522 -177
  728. nautobot/project-static/docs/models/dcim/devicetype.html +1427 -174
  729. nautobot/project-static/docs/models/dcim/frontport.html +1427 -174
  730. nautobot/project-static/docs/models/dcim/frontporttemplate.html +1427 -174
  731. nautobot/project-static/docs/models/dcim/interface.html +1427 -174
  732. nautobot/project-static/docs/models/dcim/interfacetemplate.html +1427 -174
  733. nautobot/project-static/docs/models/dcim/inventoryitem.html +1427 -174
  734. nautobot/project-static/docs/models/dcim/location.html +1427 -174
  735. nautobot/project-static/docs/models/dcim/locationtype.html +1427 -174
  736. nautobot/project-static/docs/models/dcim/manufacturer.html +1427 -174
  737. nautobot/project-static/docs/models/dcim/platform.html +1427 -174
  738. nautobot/project-static/docs/models/dcim/powerfeed.html +1425 -172
  739. nautobot/project-static/docs/models/dcim/poweroutlet.html +1427 -174
  740. nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1427 -174
  741. nautobot/project-static/docs/models/dcim/powerpanel.html +1425 -172
  742. nautobot/project-static/docs/models/dcim/powerport.html +1427 -174
  743. nautobot/project-static/docs/models/dcim/powerporttemplate.html +1427 -174
  744. nautobot/project-static/docs/models/dcim/rack.html +1427 -174
  745. nautobot/project-static/docs/models/dcim/rackgroup.html +1427 -174
  746. nautobot/project-static/docs/models/dcim/rackreservation.html +1427 -174
  747. nautobot/project-static/docs/models/dcim/rearport.html +1427 -174
  748. nautobot/project-static/docs/models/dcim/rearporttemplate.html +1427 -174
  749. nautobot/project-static/docs/models/dcim/region.html +1401 -170
  750. nautobot/project-static/docs/models/dcim/site.html +1401 -170
  751. nautobot/project-static/docs/models/dcim/virtualchassis.html +1425 -172
  752. nautobot/project-static/docs/models/extras/computedfield.html +1393 -194
  753. nautobot/project-static/docs/models/extras/configcontext.html +1465 -174
  754. nautobot/project-static/docs/models/extras/configcontextschema.html +1421 -168
  755. nautobot/project-static/docs/models/extras/customfield.html +1389 -190
  756. nautobot/project-static/docs/models/extras/customlink.html +1389 -190
  757. nautobot/project-static/docs/models/extras/dynamicgroup.html +1398 -199
  758. nautobot/project-static/docs/models/extras/exporttemplate.html +1389 -190
  759. nautobot/project-static/docs/models/extras/gitrepository.html +1393 -190
  760. nautobot/project-static/docs/models/extras/graphqlquery.html +1469 -171
  761. nautobot/project-static/docs/models/extras/imageattachment.html +1434 -181
  762. nautobot/project-static/docs/models/extras/job.html +1411 -157
  763. nautobot/project-static/docs/models/extras/jobbutton.html +1410 -207
  764. nautobot/project-static/docs/models/extras/jobhook.html +1397 -194
  765. nautobot/project-static/docs/models/extras/joblogentry.html +1408 -155
  766. nautobot/project-static/docs/models/extras/jobresult.html +1417 -159
  767. nautobot/project-static/docs/models/extras/note.html +1389 -190
  768. nautobot/project-static/docs/models/extras/relationship.html +1391 -192
  769. nautobot/project-static/docs/models/extras/role.html +1495 -198
  770. nautobot/project-static/docs/models/extras/secret.html +1492 -201
  771. nautobot/project-static/docs/models/extras/secretsgroup.html +1410 -157
  772. nautobot/project-static/docs/models/extras/status.html +1381 -221
  773. nautobot/project-static/docs/models/extras/tag.html +1389 -190
  774. nautobot/project-static/docs/models/extras/webhook.html +1389 -190
  775. nautobot/project-static/docs/models/ipam/ipaddress.html +1488 -200
  776. nautobot/project-static/docs/models/ipam/prefix.html +1410 -157
  777. nautobot/project-static/docs/models/ipam/rir.html +1410 -157
  778. nautobot/project-static/docs/models/ipam/routetarget.html +1410 -157
  779. nautobot/project-static/docs/models/ipam/service.html +1410 -157
  780. nautobot/project-static/docs/models/ipam/vlan.html +1410 -157
  781. nautobot/project-static/docs/models/ipam/vlangroup.html +1410 -157
  782. nautobot/project-static/docs/models/ipam/vrf.html +1410 -161
  783. nautobot/project-static/docs/models/tenancy/tenant.html +1412 -159
  784. nautobot/project-static/docs/models/tenancy/tenantgroup.html +1412 -159
  785. nautobot/project-static/docs/models/users/objectpermission.html +1462 -171
  786. nautobot/project-static/docs/models/users/token.html +1410 -157
  787. nautobot/project-static/docs/models/virtualization/cluster.html +1410 -157
  788. nautobot/project-static/docs/models/virtualization/clustergroup.html +1410 -157
  789. nautobot/project-static/docs/models/virtualization/clustertype.html +1410 -157
  790. nautobot/project-static/docs/models/virtualization/virtualmachine.html +1414 -157
  791. nautobot/project-static/docs/models/virtualization/vminterface.html +1410 -157
  792. nautobot/project-static/docs/objects.inv +0 -0
  793. nautobot/project-static/docs/plugins/development.html +1916 -646
  794. nautobot/project-static/docs/plugins/index.html +1389 -190
  795. nautobot/project-static/docs/plugins/porting-from-netbox.html +1389 -190
  796. nautobot/project-static/docs/release-notes/index.html +1389 -190
  797. nautobot/project-static/docs/release-notes/version-1.0.html +1389 -190
  798. nautobot/project-static/docs/release-notes/version-1.1.html +1389 -190
  799. nautobot/project-static/docs/release-notes/version-1.2.html +1389 -190
  800. nautobot/project-static/docs/release-notes/version-1.3.html +1389 -190
  801. nautobot/project-static/docs/release-notes/version-1.4.html +1389 -190
  802. nautobot/project-static/docs/release-notes/version-1.5.html +2016 -397
  803. nautobot/project-static/docs/release-notes/version-2.0.html +1935 -287
  804. nautobot/project-static/docs/requirements.txt +5 -4
  805. nautobot/project-static/docs/rest-api/authentication.html +1389 -190
  806. nautobot/project-static/docs/rest-api/filtering.html +1389 -190
  807. nautobot/project-static/docs/rest-api/overview.html +2002 -576
  808. nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
  809. nautobot/project-static/docs/search/search_index.json +1 -1
  810. nautobot/project-static/docs/sitemap.xml +197 -187
  811. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  812. nautobot/project-static/docs/user-guides/custom-fields.html +1390 -191
  813. nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1392 -193
  814. nautobot/project-static/docs/user-guides/getting-started/index.html +1388 -189
  815. nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1388 -189
  816. nautobot/project-static/docs/user-guides/getting-started/ipam.html +1386 -187
  817. nautobot/project-static/docs/user-guides/getting-started/platforms.html +1448 -249
  818. nautobot/project-static/docs/user-guides/getting-started/regions.html +1411 -212
  819. nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1395 -196
  820. nautobot/project-static/docs/user-guides/getting-started/tenants.html +1448 -249
  821. nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1448 -249
  822. nautobot/project-static/docs/user-guides/git-data-source.html +1405 -206
  823. nautobot/project-static/docs/user-guides/graphql.html +1402 -203
  824. nautobot/project-static/docs/user-guides/relationships.html +1448 -249
  825. nautobot/project-static/docs/user-guides/s3-django-storage.html +1448 -249
  826. nautobot/project-static/js/forms.js +16 -9
  827. nautobot/project-static/js/theme.js +5 -0
  828. nautobot/tenancy/api/serializers.py +4 -34
  829. nautobot/tenancy/api/urls.py +1 -1
  830. nautobot/tenancy/filters/__init__.py +9 -7
  831. nautobot/tenancy/filters/mixins.py +3 -2
  832. nautobot/tenancy/forms.py +3 -36
  833. nautobot/tenancy/migrations/0001_initial.py +0 -1
  834. nautobot/tenancy/migrations/0002_auto_slug.py +0 -1
  835. nautobot/tenancy/migrations/0003_mptt_to_tree_queries.py +0 -1
  836. nautobot/tenancy/migrations/0004_change_tree_manager_on_tree_models.py +0 -1
  837. nautobot/tenancy/migrations/0005_rename_foreign_keys_and_related_names.py +0 -1
  838. nautobot/tenancy/migrations/0006_created_datetime.py +0 -1
  839. nautobot/tenancy/migrations/0007_remove_tenant_tenantgroup_slug.py +20 -0
  840. nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
  841. nautobot/tenancy/models.py +0 -30
  842. nautobot/tenancy/navigation.py +6 -39
  843. nautobot/tenancy/tables.py +4 -4
  844. nautobot/tenancy/templates/tenancy/tenant.html +12 -12
  845. nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -1
  846. nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
  847. nautobot/tenancy/tests/test_api.py +1 -12
  848. nautobot/tenancy/tests/test_filters.py +20 -12
  849. nautobot/tenancy/tests/test_views.py +11 -29
  850. nautobot/tenancy/urls.py +10 -10
  851. nautobot/tenancy/views.py +0 -3
  852. nautobot/ui/.eslintignore +6 -0
  853. nautobot/ui/.gitignore +10 -0
  854. nautobot/ui/.prettierignore +9 -0
  855. nautobot/ui/.prettierrc +4 -0
  856. nautobot/ui/README.md +33 -0
  857. nautobot/ui/app_imports.js.j2 +7 -0
  858. nautobot/ui/craco.config.js +46 -0
  859. nautobot/ui/jsconfig-base.json +11 -0
  860. nautobot/ui/jsconfig.json +5 -0
  861. nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
  862. nautobot/ui/package-lock.json +21451 -0
  863. nautobot/ui/package.json +70 -0
  864. nautobot/ui/public/index.html +47 -0
  865. nautobot/ui/public/logo192.png +0 -0
  866. nautobot/ui/public/logo512.png +0 -0
  867. nautobot/ui/public/manifest.json +25 -0
  868. nautobot/ui/public/nautobot_logo.svg +131 -0
  869. nautobot/ui/public/robots.txt +3 -0
  870. nautobot/ui/src/App.js +71 -0
  871. nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
  872. nautobot/ui/src/components/AppTab.js +40 -0
  873. nautobot/ui/src/components/Apps.js +60 -0
  874. nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
  875. nautobot/ui/src/components/HomePanel.js +58 -0
  876. nautobot/ui/src/components/JobHistoryTable.js +78 -0
  877. nautobot/ui/src/components/Layout.js +53 -0
  878. nautobot/ui/src/components/LoadingWidget.js +25 -0
  879. nautobot/ui/src/components/Navbar.js +116 -0
  880. nautobot/ui/src/components/NotificationPopover.js +27 -0
  881. nautobot/ui/src/components/ObjectListTable.js +209 -0
  882. nautobot/ui/src/components/ReferenceDataTag.js +35 -0
  883. nautobot/ui/src/components/RouterButton.js +10 -0
  884. nautobot/ui/src/components/RouterLink.js +10 -0
  885. nautobot/ui/src/components/SidebarNav.js +147 -0
  886. nautobot/ui/src/components/Table.js +48 -0
  887. nautobot/ui/src/components/TableItem.js +71 -0
  888. nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
  889. nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
  890. nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
  891. nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
  892. nautobot/ui/src/components/__tests__/Table.test.js +36 -0
  893. nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
  894. nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
  895. nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
  896. nautobot/ui/src/components/pagination.js +93 -0
  897. nautobot/ui/src/components/paginator.js +79 -0
  898. nautobot/ui/src/components/paginator_form.js +43 -0
  899. nautobot/ui/src/components/usePagination.js +57 -0
  900. nautobot/ui/src/constants/apiPath.js +10 -0
  901. nautobot/ui/src/constants/icons.js +15 -0
  902. nautobot/ui/src/constants/size.js +15 -0
  903. nautobot/ui/src/index.js +65 -0
  904. nautobot/ui/src/reportWebVitals.js +15 -0
  905. nautobot/ui/src/router.js +77 -0
  906. nautobot/ui/src/utils/api.js +131 -0
  907. nautobot/ui/src/utils/app-import.js +15 -0
  908. nautobot/ui/src/utils/color.js +15 -0
  909. nautobot/ui/src/utils/date.js +14 -0
  910. nautobot/ui/src/utils/index.js +15 -0
  911. nautobot/ui/src/utils/navigation.js +32 -0
  912. nautobot/ui/src/utils/session.js +64 -0
  913. nautobot/ui/src/utils/store.js +242 -0
  914. nautobot/ui/src/utils/string.js +6 -0
  915. nautobot/ui/src/utils/url.js +4 -0
  916. nautobot/ui/src/views/Home.js +138 -0
  917. nautobot/ui/src/views/InstalledApps.js +80 -0
  918. nautobot/ui/src/views/Login.js +48 -0
  919. nautobot/ui/src/views/Logout.js +20 -0
  920. nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
  921. nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
  922. nautobot/ui/src/views/__tests__/Login.test.js +15 -0
  923. nautobot/ui/src/views/generic/GenericView.js +142 -0
  924. nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
  925. nautobot/ui/src/views/generic/ObjectList.js +127 -0
  926. nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
  927. nautobot/users/admin.py +1 -1
  928. nautobot/users/api/serializers.py +51 -61
  929. nautobot/users/api/urls.py +1 -1
  930. nautobot/users/api/views.py +53 -2
  931. nautobot/users/migrations/0001_initial.py +0 -1
  932. nautobot/users/migrations/0002_token_ordering_by_created.py +0 -1
  933. nautobot/users/migrations/0003_alter_user_options.py +0 -1
  934. nautobot/users/migrations/0004_alter_user_managers.py +0 -1
  935. nautobot/users/tests/test_api.py +109 -28
  936. nautobot/users/tests/test_filters.py +0 -4
  937. nautobot/users/tests/test_models.py +0 -1
  938. nautobot/users/views.py +0 -7
  939. nautobot/virtualization/api/serializers.py +18 -132
  940. nautobot/virtualization/api/urls.py +1 -1
  941. nautobot/virtualization/api/views.py +1 -22
  942. nautobot/virtualization/choices.py +0 -2
  943. nautobot/virtualization/filters.py +12 -7
  944. nautobot/virtualization/forms.py +21 -117
  945. nautobot/virtualization/migrations/0001_initial.py +0 -1
  946. nautobot/virtualization/migrations/0002_virtualmachine_local_context_schema.py +0 -1
  947. nautobot/virtualization/migrations/0003_vminterface_verbose_name.py +0 -1
  948. nautobot/virtualization/migrations/0004_auto_slug.py +0 -1
  949. nautobot/virtualization/migrations/0005_add_natural_indexing.py +0 -1
  950. nautobot/virtualization/migrations/0006_vminterface_status.py +0 -1
  951. nautobot/virtualization/migrations/0007_vminterface_status_data_migration.py +0 -1
  952. nautobot/virtualization/migrations/0008_vminterface_parent.py +0 -1
  953. nautobot/virtualization/migrations/0009_cluster_location.py +0 -1
  954. nautobot/virtualization/migrations/0010_vminterface_mac_address_data_migration.py +0 -1
  955. nautobot/virtualization/migrations/0011_alter_vminterface_mac_address.py +0 -1
  956. nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -2
  957. nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -12
  958. nautobot/virtualization/migrations/0014_rename_virtualmachine_roles.py +0 -1
  959. nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -2
  960. nautobot/virtualization/migrations/0016_remove_site_foreign_key_from_cluster_class.py +0 -1
  961. nautobot/virtualization/migrations/0017_created_datetime.py +0 -1
  962. nautobot/virtualization/migrations/0018_related_name_changes.py +1 -2
  963. nautobot/virtualization/migrations/0019_vminterface_ip_addresses_m2m.py +0 -1
  964. nautobot/virtualization/migrations/0020_remove_clustergroup_clustertype_slug.py +20 -0
  965. nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
  966. nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
  967. nautobot/virtualization/migrations/0023_ipam__namespaces.py +25 -0
  968. nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
  969. nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
  970. nautobot/virtualization/models.py +39 -131
  971. nautobot/virtualization/navigation.py +18 -99
  972. nautobot/virtualization/tables.py +4 -4
  973. nautobot/virtualization/templates/virtualization/virtualmachine.html +13 -2
  974. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
  975. nautobot/virtualization/tests/test_api.py +42 -52
  976. nautobot/virtualization/tests/test_filters.py +98 -75
  977. nautobot/virtualization/tests/test_models.py +36 -13
  978. nautobot/virtualization/tests/test_views.py +68 -73
  979. nautobot/virtualization/urls.py +10 -10
  980. nautobot/virtualization/views.py +8 -14
  981. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +15 -22
  982. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +987 -834
  983. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
  984. nautobot/circuits/api/nested_serializers.py +0 -69
  985. nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
  986. nautobot/dcim/api/nested_serializers.py +0 -356
  987. nautobot/dcim/templates/dcim/device_import.html +0 -5
  988. nautobot/dcim/templates/dcim/device_import_child.html +0 -5
  989. nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
  990. nautobot/extras/api/nested_serializers.py +0 -353
  991. nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -42
  992. nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -47
  993. nautobot/extras/reports.py +0 -60
  994. nautobot/extras/scripts.py +0 -72
  995. nautobot/extras/tests/example_jobs/script_variables.py +0 -67
  996. nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
  997. nautobot/extras/tests/example_jobs/test_fail.py +0 -16
  998. nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
  999. nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
  1000. nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
  1001. nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
  1002. nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
  1003. nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
  1004. nautobot/extras/tests/example_jobs/test_modify_db.py +0 -19
  1005. nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
  1006. nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
  1007. nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
  1008. nautobot/extras/tests/example_jobs/test_pass.py +0 -19
  1009. nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
  1010. nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
  1011. nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
  1012. nautobot/ipam/api/nested_serializers.py +0 -143
  1013. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js +0 -29
  1014. nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js.map +0 -8
  1015. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js +0 -18
  1016. nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js.map +0 -8
  1017. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css +0 -1
  1018. nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css.map +0 -1
  1019. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css +0 -1
  1020. nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css.map +0 -1
  1021. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css +0 -1
  1022. nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css.map +0 -1
  1023. nautobot/tenancy/api/nested_serializers.py +0 -31
  1024. nautobot/users/api/nested_serializers.py +0 -67
  1025. nautobot/virtualization/api/nested_serializers.py +0 -65
  1026. /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
  1027. /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
  1028. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
  1029. {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
@@ -10,8 +10,14 @@
10
10
 
11
11
  <link rel="canonical" href="https://docs.nautobot.com/projects/core/en/stable/code-reference/nautobot/apps/filters.html">
12
12
 
13
+
14
+ <link rel="prev" href="datasources.html">
15
+
16
+
17
+ <link rel="next" href="forms.html">
18
+
13
19
  <link rel="icon" href="../../../assets/favicon.ico">
14
- <meta name="generator" content="mkdocs-1.4.2, mkdocs-material-8.5.10">
20
+ <meta name="generator" content="mkdocs-1.4.2, mkdocs-material-9.1.6">
15
21
 
16
22
 
17
23
 
@@ -19,11 +25,10 @@
19
25
 
20
26
 
21
27
 
22
- <link rel="stylesheet" href="../../../assets/stylesheets/main.975780f9.min.css">
28
+ <link rel="stylesheet" href="../../../assets/stylesheets/main.ded33207.min.css">
23
29
 
24
30
 
25
- <link rel="stylesheet" href="../../../assets/stylesheets/palette.2505c338.min.css">
26
-
31
+ <link rel="stylesheet" href="../../../assets/stylesheets/palette.a0c5b2b5.min.css">
27
32
 
28
33
 
29
34
 
@@ -86,7 +91,7 @@
86
91
 
87
92
 
88
93
 
89
- <header class="md-header md-header--lifted" data-md-component="header">
94
+ <header class="md-header md-header--shadow md-header--lifted" data-md-component="header">
90
95
  <nav class="md-header__inner md-grid" aria-label="Header">
91
96
  <a href="../../../index.html" title="Nautobot Documentation" class="md-header__button md-logo" aria-label="Nautobot Documentation" data-md-component="logo">
92
97
 
@@ -116,8 +121,6 @@
116
121
  <form class="md-header__option" data-md-component="palette">
117
122
 
118
123
 
119
-
120
-
121
124
  <input class="md-option" data-md-color-media="(prefers-color-scheme: light)" data-md-color-scheme="default" data-md-color-primary="black" data-md-color-accent="" aria-label="Switch to dark mode" type="radio" name="__palette" id="__palette_1">
122
125
 
123
126
  <label class="md-header__button md-icon" title="Switch to dark mode" for="__palette_2" hidden>
@@ -126,8 +129,6 @@
126
129
 
127
130
 
128
131
 
129
-
130
-
131
132
  <input class="md-option" data-md-color-media="(prefers-color-scheme: dark)" data-md-color-scheme="slate" data-md-color-primary="black" data-md-color-accent="" aria-label="Switch to light mode" type="radio" name="__palette" id="__palette_2">
132
133
 
133
134
  <label class="md-header__button md-icon" title="Switch to light mode" for="__palette_1" hidden>
@@ -171,7 +172,7 @@
171
172
  <div class="md-search-result__meta">
172
173
  Initializing search
173
174
  </div>
174
- <ol class="md-search-result__list"></ol>
175
+ <ol class="md-search-result__list" role="presentation"></ol>
175
176
  </div>
176
177
  </div>
177
178
  </div>
@@ -183,7 +184,7 @@
183
184
  <a href="https://github.com/nautobot/nautobot" title="Go to repository" class="md-source" data-md-component="source">
184
185
  <div class="md-source__icon md-icon">
185
186
 
186
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
187
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
187
188
  </div>
188
189
  <div class="md-source__repository">
189
190
  GitHub
@@ -196,7 +197,7 @@
196
197
 
197
198
 
198
199
  <nav class="md-tabs" aria-label="Tabs" data-md-component="tabs">
199
- <div class="md-tabs__inner md-grid">
200
+ <div class="md-grid">
200
201
  <ul class="md-tabs__list">
201
202
 
202
203
 
@@ -351,7 +352,7 @@
351
352
  <a href="https://github.com/nautobot/nautobot" title="Go to repository" class="md-source" data-md-component="source">
352
353
  <div class="md-source__icon md-icon">
353
354
 
354
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
355
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M439.55 236.05 244 40.45a28.87 28.87 0 0 0-40.81 0l-40.66 40.63 51.52 51.52c27.06-9.14 52.68 16.77 43.39 43.68l49.66 49.66c34.23-11.8 61.18 31 35.47 56.69-26.49 26.49-70.21-2.87-56-37.34L240.22 199v121.85c25.3 12.54 22.26 41.85 9.08 55a34.34 34.34 0 0 1-48.55 0c-17.57-17.6-11.07-46.91 11.25-56v-123c-20.8-8.51-24.6-30.74-18.64-45L142.57 101 8.45 235.14a28.86 28.86 0 0 0 0 40.81l195.61 195.6a28.86 28.86 0 0 0 40.8 0l194.69-194.69a28.86 28.86 0 0 0 0-40.81z"/></svg>
355
356
  </div>
356
357
  <div class="md-source__repository">
357
358
  GitHub
@@ -387,17 +388,18 @@
387
388
  <li class="md-nav__item md-nav__item--nested">
388
389
 
389
390
 
390
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2" type="checkbox" id="__nav_2" >
391
391
 
392
392
 
393
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2" >
394
+
393
395
 
394
396
 
395
- <label class="md-nav__link" for="__nav_2">
397
+ <label class="md-nav__link" for="__nav_2" id="__nav_2_label" tabindex="0">
396
398
  Documentation
397
399
  <span class="md-nav__icon md-icon"></span>
398
400
  </label>
399
401
 
400
- <nav class="md-nav" aria-label="Documentation" data-md-level="1">
402
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_2_label" aria-expanded="false">
401
403
  <label class="md-nav__title" for="__nav_2">
402
404
  <span class="md-nav__icon md-icon"></span>
403
405
  Documentation
@@ -413,17 +415,18 @@
413
415
  <li class="md-nav__item md-nav__item--nested">
414
416
 
415
417
 
416
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_1" type="checkbox" id="__nav_2_1" >
417
418
 
418
419
 
420
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_1" >
419
421
 
420
422
 
421
- <label class="md-nav__link" for="__nav_2_1">
423
+
424
+ <label class="md-nav__link" for="__nav_2_1" id="__nav_2_1_label" tabindex="0">
422
425
  Installation
423
426
  <span class="md-nav__icon md-icon"></span>
424
427
  </label>
425
428
 
426
- <nav class="md-nav" aria-label="Installation" data-md-level="2">
429
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_1_label" aria-expanded="false">
427
430
  <label class="md-nav__title" for="__nav_2_1">
428
431
  <span class="md-nav__icon md-icon"></span>
429
432
  Installation
@@ -530,17 +533,18 @@
530
533
  <li class="md-nav__item md-nav__item--nested">
531
534
 
532
535
 
533
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_2" type="checkbox" id="__nav_2_2" >
534
536
 
535
537
 
538
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_2" >
539
+
536
540
 
537
541
 
538
- <label class="md-nav__link" for="__nav_2_2">
542
+ <label class="md-nav__link" for="__nav_2_2" id="__nav_2_2_label" tabindex="0">
539
543
  Migration
540
544
  <span class="md-nav__icon md-icon"></span>
541
545
  </label>
542
546
 
543
- <nav class="md-nav" aria-label="Migration" data-md-level="2">
547
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_2_label" aria-expanded="false">
544
548
  <label class="md-nav__title" for="__nav_2_2">
545
549
  <span class="md-nav__icon md-icon"></span>
546
550
  Migration
@@ -633,17 +637,18 @@
633
637
  <li class="md-nav__item md-nav__item--nested">
634
638
 
635
639
 
636
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_3" type="checkbox" id="__nav_2_3" >
637
640
 
638
641
 
642
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_3" >
639
643
 
640
644
 
641
- <label class="md-nav__link" for="__nav_2_3">
645
+
646
+ <label class="md-nav__link" for="__nav_2_3" id="__nav_2_3_label" tabindex="0">
642
647
  Configuration
643
648
  <span class="md-nav__icon md-icon"></span>
644
649
  </label>
645
650
 
646
- <nav class="md-nav" aria-label="Configuration" data-md-level="2">
651
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_3_label" aria-expanded="false">
647
652
  <label class="md-nav__title" for="__nav_2_3">
648
653
  <span class="md-nav__icon md-icon"></span>
649
654
  Configuration
@@ -708,17 +713,18 @@
708
713
  <li class="md-nav__item md-nav__item--nested">
709
714
 
710
715
 
711
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_4" type="checkbox" id="__nav_2_4" >
712
716
 
713
717
 
718
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_4" >
719
+
714
720
 
715
721
 
716
- <label class="md-nav__link" for="__nav_2_4">
722
+ <label class="md-nav__link" for="__nav_2_4" id="__nav_2_4_label" tabindex="0">
717
723
  External Authentication
718
724
  <span class="md-nav__icon md-icon"></span>
719
725
  </label>
720
726
 
721
- <nav class="md-nav" aria-label="External Authentication" data-md-level="2">
727
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_4_label" aria-expanded="false">
722
728
  <label class="md-nav__title" for="__nav_2_4">
723
729
  <span class="md-nav__icon md-icon"></span>
724
730
  External Authentication
@@ -783,17 +789,18 @@
783
789
  <li class="md-nav__item md-nav__item--nested">
784
790
 
785
791
 
786
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_5" type="checkbox" id="__nav_2_5" >
787
792
 
788
793
 
794
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_5" >
789
795
 
790
796
 
791
- <label class="md-nav__link" for="__nav_2_5">
797
+
798
+ <label class="md-nav__link" for="__nav_2_5" id="__nav_2_5_label" tabindex="0">
792
799
  Administration
793
800
  <span class="md-nav__icon md-icon"></span>
794
801
  </label>
795
802
 
796
- <nav class="md-nav" aria-label="Administration" data-md-level="2">
803
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_5_label" aria-expanded="false">
797
804
  <label class="md-nav__title" for="__nav_2_5">
798
805
  <span class="md-nav__icon md-icon"></span>
799
806
  Administration
@@ -886,17 +893,18 @@
886
893
  <li class="md-nav__item md-nav__item--nested">
887
894
 
888
895
 
889
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_6" type="checkbox" id="__nav_2_6" >
890
896
 
891
897
 
898
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_6" >
899
+
892
900
 
893
901
 
894
- <label class="md-nav__link" for="__nav_2_6">
902
+ <label class="md-nav__link" for="__nav_2_6" id="__nav_2_6_label" tabindex="0">
895
903
  User Guides
896
904
  <span class="md-nav__icon md-icon"></span>
897
905
  </label>
898
906
 
899
- <nav class="md-nav" aria-label="User Guides" data-md-level="2">
907
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_6_label" aria-expanded="false">
900
908
  <label class="md-nav__title" for="__nav_2_6">
901
909
  <span class="md-nav__icon md-icon"></span>
902
910
  User Guides
@@ -1007,22 +1015,1129 @@
1007
1015
 
1008
1016
 
1009
1017
  <li class="md-nav__item">
1010
- <a href="../../../user-guides/getting-started/platforms.html" class="md-nav__link">
1011
- Platforms
1018
+ <a href="../../../user-guides/getting-started/platforms.html" class="md-nav__link">
1019
+ Platforms
1020
+ </a>
1021
+ </li>
1022
+
1023
+
1024
+
1025
+
1026
+
1027
+
1028
+
1029
+
1030
+
1031
+ <li class="md-nav__item">
1032
+ <a href="../../../user-guides/getting-started/regions.html" class="md-nav__link">
1033
+ Regions
1034
+ </a>
1035
+ </li>
1036
+
1037
+
1038
+
1039
+
1040
+
1041
+
1042
+
1043
+
1044
+
1045
+ <li class="md-nav__item">
1046
+ <a href="../../../user-guides/getting-started/tenants.html" class="md-nav__link">
1047
+ Tenants
1048
+ </a>
1049
+ </li>
1050
+
1051
+
1052
+
1053
+
1054
+
1055
+
1056
+
1057
+
1058
+
1059
+ <li class="md-nav__item">
1060
+ <a href="../../../user-guides/getting-started/search-bar.html" class="md-nav__link">
1061
+ The Search Bar
1062
+ </a>
1063
+ </li>
1064
+
1065
+
1066
+
1067
+
1068
+
1069
+
1070
+
1071
+
1072
+
1073
+ <li class="md-nav__item">
1074
+ <a href="../../../user-guides/git-data-source.html" class="md-nav__link">
1075
+ Git as a Data Source
1076
+ </a>
1077
+ </li>
1078
+
1079
+
1080
+
1081
+
1082
+
1083
+
1084
+
1085
+
1086
+
1087
+ <li class="md-nav__item">
1088
+ <a href="../../../user-guides/graphql.html" class="md-nav__link">
1089
+ GraphQL
1090
+ </a>
1091
+ </li>
1092
+
1093
+
1094
+
1095
+
1096
+
1097
+
1098
+
1099
+
1100
+
1101
+ <li class="md-nav__item">
1102
+ <a href="../../../user-guides/relationships.html" class="md-nav__link">
1103
+ Relationships
1104
+ </a>
1105
+ </li>
1106
+
1107
+
1108
+
1109
+
1110
+
1111
+
1112
+
1113
+
1114
+
1115
+ <li class="md-nav__item">
1116
+ <a href="../../../user-guides/s3-django-storage.html" class="md-nav__link">
1117
+ Django Storages with S3
1118
+ </a>
1119
+ </li>
1120
+
1121
+
1122
+
1123
+
1124
+
1125
+
1126
+
1127
+
1128
+
1129
+ <li class="md-nav__item">
1130
+ <a href="../../../user-guides/getting-started/vlans-and-vlan-groups.html" class="md-nav__link">
1131
+ VLANS and VLAN Groups
1132
+ </a>
1133
+ </li>
1134
+
1135
+
1136
+
1137
+
1138
+ </ul>
1139
+ </nav>
1140
+ </li>
1141
+
1142
+
1143
+
1144
+
1145
+
1146
+
1147
+
1148
+
1149
+
1150
+
1151
+ <li class="md-nav__item md-nav__item--nested">
1152
+
1153
+
1154
+
1155
+
1156
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_7" >
1157
+
1158
+
1159
+
1160
+ <label class="md-nav__link" for="__nav_2_7" id="__nav_2_7_label" tabindex="0">
1161
+ Core Functionality
1162
+ <span class="md-nav__icon md-icon"></span>
1163
+ </label>
1164
+
1165
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_7_label" aria-expanded="false">
1166
+ <label class="md-nav__title" for="__nav_2_7">
1167
+ <span class="md-nav__icon md-icon"></span>
1168
+ Core Functionality
1169
+ </label>
1170
+ <ul class="md-nav__list" data-md-scrollfix>
1171
+
1172
+
1173
+
1174
+
1175
+
1176
+
1177
+ <li class="md-nav__item">
1178
+ <a href="../../../core-functionality/circuits.html" class="md-nav__link">
1179
+ Circuits
1180
+ </a>
1181
+ </li>
1182
+
1183
+
1184
+
1185
+
1186
+
1187
+
1188
+
1189
+
1190
+
1191
+ <li class="md-nav__item">
1192
+ <a href="../../../core-functionality/devices.html" class="md-nav__link">
1193
+ Devices and Cabling
1194
+ </a>
1195
+ </li>
1196
+
1197
+
1198
+
1199
+
1200
+
1201
+
1202
+
1203
+
1204
+
1205
+ <li class="md-nav__item">
1206
+ <a href="../../../core-functionality/device-types.html" class="md-nav__link">
1207
+ Device Types
1208
+ </a>
1209
+ </li>
1210
+
1211
+
1212
+
1213
+
1214
+
1215
+
1216
+
1217
+
1218
+
1219
+ <li class="md-nav__item">
1220
+ <a href="../../../core-functionality/ipam.html" class="md-nav__link">
1221
+ IP Address Management
1222
+ </a>
1223
+ </li>
1224
+
1225
+
1226
+
1227
+
1228
+
1229
+
1230
+
1231
+
1232
+
1233
+ <li class="md-nav__item">
1234
+ <a href="../../../core-functionality/power.html" class="md-nav__link">
1235
+ Power Tracking
1236
+ </a>
1237
+ </li>
1238
+
1239
+
1240
+
1241
+
1242
+
1243
+
1244
+
1245
+
1246
+
1247
+ <li class="md-nav__item">
1248
+ <a href="../../../core-functionality/secrets.html" class="md-nav__link">
1249
+ Secrets
1250
+ </a>
1251
+ </li>
1252
+
1253
+
1254
+
1255
+
1256
+
1257
+
1258
+
1259
+
1260
+
1261
+ <li class="md-nav__item">
1262
+ <a href="../../../core-functionality/services.html" class="md-nav__link">
1263
+ Service Mapping
1264
+ </a>
1265
+ </li>
1266
+
1267
+
1268
+
1269
+
1270
+
1271
+
1272
+
1273
+
1274
+
1275
+ <li class="md-nav__item">
1276
+ <a href="../../../core-functionality/sites-and-racks.html" class="md-nav__link">
1277
+ Sites, Locations, and Racks
1278
+ </a>
1279
+ </li>
1280
+
1281
+
1282
+
1283
+
1284
+
1285
+
1286
+
1287
+
1288
+
1289
+ <li class="md-nav__item">
1290
+ <a href="../../../core-functionality/tenancy.html" class="md-nav__link">
1291
+ Tenancy
1292
+ </a>
1293
+ </li>
1294
+
1295
+
1296
+
1297
+
1298
+
1299
+
1300
+
1301
+
1302
+
1303
+ <li class="md-nav__item">
1304
+ <a href="../../../core-functionality/virtualization.html" class="md-nav__link">
1305
+ Virtualization
1306
+ </a>
1307
+ </li>
1308
+
1309
+
1310
+
1311
+
1312
+
1313
+
1314
+
1315
+
1316
+
1317
+ <li class="md-nav__item">
1318
+ <a href="../../../core-functionality/vlans.html" class="md-nav__link">
1319
+ VLAN Management
1320
+ </a>
1321
+ </li>
1322
+
1323
+
1324
+
1325
+
1326
+ </ul>
1327
+ </nav>
1328
+ </li>
1329
+
1330
+
1331
+
1332
+
1333
+
1334
+
1335
+
1336
+
1337
+
1338
+
1339
+ <li class="md-nav__item md-nav__item--nested">
1340
+
1341
+
1342
+
1343
+
1344
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8" >
1345
+
1346
+
1347
+
1348
+ <label class="md-nav__link" for="__nav_2_8" id="__nav_2_8_label" tabindex="0">
1349
+ Model Details
1350
+ <span class="md-nav__icon md-icon"></span>
1351
+ </label>
1352
+
1353
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_8_label" aria-expanded="false">
1354
+ <label class="md-nav__title" for="__nav_2_8">
1355
+ <span class="md-nav__icon md-icon"></span>
1356
+ Model Details
1357
+ </label>
1358
+ <ul class="md-nav__list" data-md-scrollfix>
1359
+
1360
+
1361
+
1362
+
1363
+
1364
+
1365
+
1366
+ <li class="md-nav__item md-nav__item--nested">
1367
+
1368
+
1369
+
1370
+
1371
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_1" >
1372
+
1373
+
1374
+
1375
+ <label class="md-nav__link" for="__nav_2_8_1" id="__nav_2_8_1_label" tabindex="0">
1376
+ Circuits
1377
+ <span class="md-nav__icon md-icon"></span>
1378
+ </label>
1379
+
1380
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_1_label" aria-expanded="false">
1381
+ <label class="md-nav__title" for="__nav_2_8_1">
1382
+ <span class="md-nav__icon md-icon"></span>
1383
+ Circuits
1384
+ </label>
1385
+ <ul class="md-nav__list" data-md-scrollfix>
1386
+
1387
+
1388
+
1389
+
1390
+
1391
+
1392
+ <li class="md-nav__item">
1393
+ <a href="../../../models/circuits/circuit.html" class="md-nav__link">
1394
+ Circuit
1395
+ </a>
1396
+ </li>
1397
+
1398
+
1399
+
1400
+
1401
+
1402
+
1403
+
1404
+
1405
+
1406
+ <li class="md-nav__item">
1407
+ <a href="../../../models/circuits/circuittermination.html" class="md-nav__link">
1408
+ Circuit Termination
1409
+ </a>
1410
+ </li>
1411
+
1412
+
1413
+
1414
+
1415
+
1416
+
1417
+
1418
+
1419
+
1420
+ <li class="md-nav__item">
1421
+ <a href="../../../models/circuits/circuittype.html" class="md-nav__link">
1422
+ Circuit Type
1423
+ </a>
1424
+ </li>
1425
+
1426
+
1427
+
1428
+
1429
+
1430
+
1431
+
1432
+
1433
+
1434
+ <li class="md-nav__item">
1435
+ <a href="../../../models/circuits/provider.html" class="md-nav__link">
1436
+ Circuit Provider
1437
+ </a>
1438
+ </li>
1439
+
1440
+
1441
+
1442
+
1443
+
1444
+
1445
+
1446
+
1447
+
1448
+ <li class="md-nav__item">
1449
+ <a href="../../../models/circuits/providernetwork.html" class="md-nav__link">
1450
+ Circuit Provider Network
1451
+ </a>
1452
+ </li>
1453
+
1454
+
1455
+
1456
+
1457
+ </ul>
1458
+ </nav>
1459
+ </li>
1460
+
1461
+
1462
+
1463
+
1464
+
1465
+
1466
+
1467
+
1468
+
1469
+
1470
+ <li class="md-nav__item md-nav__item--nested">
1471
+
1472
+
1473
+
1474
+
1475
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_2" >
1476
+
1477
+
1478
+
1479
+ <label class="md-nav__link" for="__nav_2_8_2" id="__nav_2_8_2_label" tabindex="0">
1480
+ DCIM
1481
+ <span class="md-nav__icon md-icon"></span>
1482
+ </label>
1483
+
1484
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_2_label" aria-expanded="false">
1485
+ <label class="md-nav__title" for="__nav_2_8_2">
1486
+ <span class="md-nav__icon md-icon"></span>
1487
+ DCIM
1488
+ </label>
1489
+ <ul class="md-nav__list" data-md-scrollfix>
1490
+
1491
+
1492
+
1493
+
1494
+
1495
+
1496
+ <li class="md-nav__item">
1497
+ <a href="../../../models/dcim/cable.html" class="md-nav__link">
1498
+ Cable
1499
+ </a>
1500
+ </li>
1501
+
1502
+
1503
+
1504
+
1505
+
1506
+
1507
+
1508
+
1509
+
1510
+ <li class="md-nav__item">
1511
+ <a href="../../../models/dcim/consoleport.html" class="md-nav__link">
1512
+ Console Port
1513
+ </a>
1514
+ </li>
1515
+
1516
+
1517
+
1518
+
1519
+
1520
+
1521
+
1522
+
1523
+
1524
+ <li class="md-nav__item">
1525
+ <a href="../../../models/dcim/consoleporttemplate.html" class="md-nav__link">
1526
+ Console Port Template
1527
+ </a>
1528
+ </li>
1529
+
1530
+
1531
+
1532
+
1533
+
1534
+
1535
+
1536
+
1537
+
1538
+ <li class="md-nav__item">
1539
+ <a href="../../../models/dcim/consoleserverport.html" class="md-nav__link">
1540
+ Console Server Port
1541
+ </a>
1542
+ </li>
1543
+
1544
+
1545
+
1546
+
1547
+
1548
+
1549
+
1550
+
1551
+
1552
+ <li class="md-nav__item">
1553
+ <a href="../../../models/dcim/consoleserverporttemplate.html" class="md-nav__link">
1554
+ Console Server Port Template
1555
+ </a>
1556
+ </li>
1557
+
1558
+
1559
+
1560
+
1561
+
1562
+
1563
+
1564
+
1565
+
1566
+ <li class="md-nav__item">
1567
+ <a href="../../../models/dcim/device.html" class="md-nav__link">
1568
+ Device
1569
+ </a>
1570
+ </li>
1571
+
1572
+
1573
+
1574
+
1575
+
1576
+
1577
+
1578
+
1579
+
1580
+ <li class="md-nav__item">
1581
+ <a href="../../../models/dcim/devicebay.html" class="md-nav__link">
1582
+ Device Bay
1583
+ </a>
1584
+ </li>
1585
+
1586
+
1587
+
1588
+
1589
+
1590
+
1591
+
1592
+
1593
+
1594
+ <li class="md-nav__item">
1595
+ <a href="../../../models/dcim/devicebaytemplate.html" class="md-nav__link">
1596
+ Device Bay Template
1597
+ </a>
1598
+ </li>
1599
+
1600
+
1601
+
1602
+
1603
+
1604
+
1605
+
1606
+
1607
+
1608
+ <li class="md-nav__item">
1609
+ <a href="../../../models/dcim/deviceredundancygroup.html" class="md-nav__link">
1610
+ Device Redundancy Group
1611
+ </a>
1612
+ </li>
1613
+
1614
+
1615
+
1616
+
1617
+
1618
+
1619
+
1620
+
1621
+
1622
+ <li class="md-nav__item">
1623
+ <a href="../../../models/dcim/devicetype.html" class="md-nav__link">
1624
+ Device Type
1625
+ </a>
1626
+ </li>
1627
+
1628
+
1629
+
1630
+
1631
+
1632
+
1633
+
1634
+
1635
+
1636
+ <li class="md-nav__item">
1637
+ <a href="../../../models/dcim/frontport.html" class="md-nav__link">
1638
+ Front Port
1639
+ </a>
1640
+ </li>
1641
+
1642
+
1643
+
1644
+
1645
+
1646
+
1647
+
1648
+
1649
+
1650
+ <li class="md-nav__item">
1651
+ <a href="../../../models/dcim/frontporttemplate.html" class="md-nav__link">
1652
+ Front Port Template
1653
+ </a>
1654
+ </li>
1655
+
1656
+
1657
+
1658
+
1659
+
1660
+
1661
+
1662
+
1663
+
1664
+ <li class="md-nav__item">
1665
+ <a href="../../../models/dcim/interface.html" class="md-nav__link">
1666
+ Interface
1667
+ </a>
1668
+ </li>
1669
+
1670
+
1671
+
1672
+
1673
+
1674
+
1675
+
1676
+
1677
+
1678
+ <li class="md-nav__item">
1679
+ <a href="../../../models/dcim/interfacetemplate.html" class="md-nav__link">
1680
+ Interface Template
1681
+ </a>
1682
+ </li>
1683
+
1684
+
1685
+
1686
+
1687
+
1688
+
1689
+
1690
+
1691
+
1692
+ <li class="md-nav__item">
1693
+ <a href="../../../models/dcim/inventoryitem.html" class="md-nav__link">
1694
+ Inventory Item
1695
+ </a>
1696
+ </li>
1697
+
1698
+
1699
+
1700
+
1701
+
1702
+
1703
+
1704
+
1705
+
1706
+ <li class="md-nav__item">
1707
+ <a href="../../../models/dcim/location.html" class="md-nav__link">
1708
+ Location
1709
+ </a>
1710
+ </li>
1711
+
1712
+
1713
+
1714
+
1715
+
1716
+
1717
+
1718
+
1719
+
1720
+ <li class="md-nav__item">
1721
+ <a href="../../../models/dcim/locationtype.html" class="md-nav__link">
1722
+ Location Type
1723
+ </a>
1724
+ </li>
1725
+
1726
+
1727
+
1728
+
1729
+
1730
+
1731
+
1732
+
1733
+
1734
+ <li class="md-nav__item">
1735
+ <a href="../../../models/dcim/manufacturer.html" class="md-nav__link">
1736
+ Manufacturer
1737
+ </a>
1738
+ </li>
1739
+
1740
+
1741
+
1742
+
1743
+
1744
+
1745
+
1746
+
1747
+
1748
+ <li class="md-nav__item">
1749
+ <a href="../../../models/dcim/platform.html" class="md-nav__link">
1750
+ Platform
1751
+ </a>
1752
+ </li>
1753
+
1754
+
1755
+
1756
+
1757
+
1758
+
1759
+
1760
+
1761
+
1762
+ <li class="md-nav__item">
1763
+ <a href="../../../models/dcim/powerfeed.html" class="md-nav__link">
1764
+ Power Feed
1765
+ </a>
1766
+ </li>
1767
+
1768
+
1769
+
1770
+
1771
+
1772
+
1773
+
1774
+
1775
+
1776
+ <li class="md-nav__item">
1777
+ <a href="../../../models/dcim/poweroutlet.html" class="md-nav__link">
1778
+ Power Outlet
1779
+ </a>
1780
+ </li>
1781
+
1782
+
1783
+
1784
+
1785
+
1786
+
1787
+
1788
+
1789
+
1790
+ <li class="md-nav__item">
1791
+ <a href="../../../models/dcim/poweroutlettemplate.html" class="md-nav__link">
1792
+ Power Outlet Template
1793
+ </a>
1794
+ </li>
1795
+
1796
+
1797
+
1798
+
1799
+
1800
+
1801
+
1802
+
1803
+
1804
+ <li class="md-nav__item">
1805
+ <a href="../../../models/dcim/powerpanel.html" class="md-nav__link">
1806
+ Power Panel
1807
+ </a>
1808
+ </li>
1809
+
1810
+
1811
+
1812
+
1813
+
1814
+
1815
+
1816
+
1817
+
1818
+ <li class="md-nav__item">
1819
+ <a href="../../../models/dcim/powerport.html" class="md-nav__link">
1820
+ Power Port
1821
+ </a>
1822
+ </li>
1823
+
1824
+
1825
+
1826
+
1827
+
1828
+
1829
+
1830
+
1831
+
1832
+ <li class="md-nav__item">
1833
+ <a href="../../../models/dcim/powerporttemplate.html" class="md-nav__link">
1834
+ Power Port Template
1835
+ </a>
1836
+ </li>
1837
+
1838
+
1839
+
1840
+
1841
+
1842
+
1843
+
1844
+
1845
+
1846
+ <li class="md-nav__item">
1847
+ <a href="../../../models/dcim/rack.html" class="md-nav__link">
1848
+ Rack
1849
+ </a>
1850
+ </li>
1851
+
1852
+
1853
+
1854
+
1855
+
1856
+
1857
+
1858
+
1859
+
1860
+ <li class="md-nav__item">
1861
+ <a href="../../../models/dcim/rackgroup.html" class="md-nav__link">
1862
+ Rack Group
1863
+ </a>
1864
+ </li>
1865
+
1866
+
1867
+
1868
+
1869
+
1870
+
1871
+
1872
+
1873
+
1874
+ <li class="md-nav__item">
1875
+ <a href="../../../models/dcim/rackreservation.html" class="md-nav__link">
1876
+ Rack Reservation
1877
+ </a>
1878
+ </li>
1879
+
1880
+
1881
+
1882
+
1883
+
1884
+
1885
+
1886
+
1887
+
1888
+ <li class="md-nav__item">
1889
+ <a href="../../../models/dcim/rearport.html" class="md-nav__link">
1890
+ Rear Port
1891
+ </a>
1892
+ </li>
1893
+
1894
+
1895
+
1896
+
1897
+
1898
+
1899
+
1900
+
1901
+
1902
+ <li class="md-nav__item">
1903
+ <a href="../../../models/dcim/rearporttemplate.html" class="md-nav__link">
1904
+ Rear Port Template
1905
+ </a>
1906
+ </li>
1907
+
1908
+
1909
+
1910
+
1911
+
1912
+
1913
+
1914
+
1915
+
1916
+ <li class="md-nav__item">
1917
+ <a href="../../../models/dcim/virtualchassis.html" class="md-nav__link">
1918
+ Virtual Chassis
1919
+ </a>
1920
+ </li>
1921
+
1922
+
1923
+
1924
+
1925
+ </ul>
1926
+ </nav>
1927
+ </li>
1928
+
1929
+
1930
+
1931
+
1932
+
1933
+
1934
+
1935
+
1936
+
1937
+
1938
+ <li class="md-nav__item md-nav__item--nested">
1939
+
1940
+
1941
+
1942
+
1943
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_3" >
1944
+
1945
+
1946
+
1947
+ <label class="md-nav__link" for="__nav_2_8_3" id="__nav_2_8_3_label" tabindex="0">
1948
+ Extras
1949
+ <span class="md-nav__icon md-icon"></span>
1950
+ </label>
1951
+
1952
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_3_label" aria-expanded="false">
1953
+ <label class="md-nav__title" for="__nav_2_8_3">
1954
+ <span class="md-nav__icon md-icon"></span>
1955
+ Extras
1956
+ </label>
1957
+ <ul class="md-nav__list" data-md-scrollfix>
1958
+
1959
+
1960
+
1961
+
1962
+
1963
+
1964
+ <li class="md-nav__item">
1965
+ <a href="../../../models/extras/configcontext.html" class="md-nav__link">
1966
+ Config Context
1967
+ </a>
1968
+ </li>
1969
+
1970
+
1971
+
1972
+
1973
+
1974
+
1975
+
1976
+
1977
+
1978
+ <li class="md-nav__item">
1979
+ <a href="../../../models/extras/configcontextschema.html" class="md-nav__link">
1980
+ Config Context Schema
1981
+ </a>
1982
+ </li>
1983
+
1984
+
1985
+
1986
+
1987
+
1988
+
1989
+
1990
+
1991
+
1992
+ <li class="md-nav__item">
1993
+ <a href="../../../models/extras/graphqlquery.html" class="md-nav__link">
1994
+ GraphQL Query
1995
+ </a>
1996
+ </li>
1997
+
1998
+
1999
+
2000
+
2001
+
2002
+
2003
+
2004
+
2005
+
2006
+ <li class="md-nav__item">
2007
+ <a href="../../../models/extras/imageattachment.html" class="md-nav__link">
2008
+ Image Attachment
2009
+ </a>
2010
+ </li>
2011
+
2012
+
2013
+
2014
+
2015
+
2016
+
2017
+
2018
+
2019
+
2020
+ <li class="md-nav__item">
2021
+ <a href="../../../models/extras/job.html" class="md-nav__link">
2022
+ Job
2023
+ </a>
2024
+ </li>
2025
+
2026
+
2027
+
2028
+
2029
+
2030
+
2031
+
2032
+
2033
+
2034
+ <li class="md-nav__item">
2035
+ <a href="../../../models/extras/joblogentry.html" class="md-nav__link">
2036
+ Job Log Entry
2037
+ </a>
2038
+ </li>
2039
+
2040
+
2041
+
2042
+
2043
+
2044
+
2045
+
2046
+
2047
+
2048
+ <li class="md-nav__item">
2049
+ <a href="../../../models/extras/jobresult.html" class="md-nav__link">
2050
+ Job Result
2051
+ </a>
2052
+ </li>
2053
+
2054
+
2055
+
2056
+
2057
+
2058
+
2059
+
2060
+
2061
+
2062
+ <li class="md-nav__item">
2063
+ <a href="../../../models/extras/role.html" class="md-nav__link">
2064
+ Role
2065
+ </a>
2066
+ </li>
2067
+
2068
+
2069
+
2070
+
2071
+
2072
+
2073
+
2074
+
2075
+
2076
+ <li class="md-nav__item">
2077
+ <a href="../../../models/extras/secret.html" class="md-nav__link">
2078
+ Secret
2079
+ </a>
2080
+ </li>
2081
+
2082
+
2083
+
2084
+
2085
+
2086
+
2087
+
2088
+
2089
+
2090
+ <li class="md-nav__item">
2091
+ <a href="../../../models/extras/secretsgroup.html" class="md-nav__link">
2092
+ Secrets group
1012
2093
  </a>
1013
2094
  </li>
1014
2095
 
1015
2096
 
1016
2097
 
1017
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
+
1018
2133
 
1019
2134
 
1020
2135
 
1021
2136
 
1022
2137
 
1023
2138
  <li class="md-nav__item">
1024
- <a href="../../../user-guides/getting-started/regions.html" class="md-nav__link">
1025
- Regions
2139
+ <a href="../../../models/ipam/ipaddress.html" class="md-nav__link">
2140
+ IP Address
1026
2141
  </a>
1027
2142
  </li>
1028
2143
 
@@ -1035,8 +2150,8 @@
1035
2150
 
1036
2151
 
1037
2152
  <li class="md-nav__item">
1038
- <a href="../../../user-guides/getting-started/tenants.html" class="md-nav__link">
1039
- Tenants
2153
+ <a href="../../../models/ipam/prefix.html" class="md-nav__link">
2154
+ Prefix
1040
2155
  </a>
1041
2156
  </li>
1042
2157
 
@@ -1049,8 +2164,8 @@
1049
2164
 
1050
2165
 
1051
2166
  <li class="md-nav__item">
1052
- <a href="../../../user-guides/getting-started/search-bar.html" class="md-nav__link">
1053
- The Search Bar
2167
+ <a href="../../../models/ipam/rir.html" class="md-nav__link">
2168
+ Rir
1054
2169
  </a>
1055
2170
  </li>
1056
2171
 
@@ -1063,8 +2178,8 @@
1063
2178
 
1064
2179
 
1065
2180
  <li class="md-nav__item">
1066
- <a href="../../../user-guides/git-data-source.html" class="md-nav__link">
1067
- Git as a Data Source
2181
+ <a href="../../../models/ipam/routetarget.html" class="md-nav__link">
2182
+ Route Target
1068
2183
  </a>
1069
2184
  </li>
1070
2185
 
@@ -1077,8 +2192,8 @@
1077
2192
 
1078
2193
 
1079
2194
  <li class="md-nav__item">
1080
- <a href="../../../user-guides/graphql.html" class="md-nav__link">
1081
- GraphQL
2195
+ <a href="../../../models/ipam/service.html" class="md-nav__link">
2196
+ Service
1082
2197
  </a>
1083
2198
  </li>
1084
2199
 
@@ -1091,8 +2206,8 @@
1091
2206
 
1092
2207
 
1093
2208
  <li class="md-nav__item">
1094
- <a href="../../../user-guides/relationships.html" class="md-nav__link">
1095
- Relationships
2209
+ <a href="../../../models/ipam/vlan.html" class="md-nav__link">
2210
+ VLAN
1096
2211
  </a>
1097
2212
  </li>
1098
2213
 
@@ -1105,8 +2220,8 @@
1105
2220
 
1106
2221
 
1107
2222
  <li class="md-nav__item">
1108
- <a href="../../../user-guides/s3-django-storage.html" class="md-nav__link">
1109
- Django Storages with S3
2223
+ <a href="../../../models/ipam/vlangroup.html" class="md-nav__link">
2224
+ VLAN Group
1110
2225
  </a>
1111
2226
  </li>
1112
2227
 
@@ -1119,8 +2234,8 @@
1119
2234
 
1120
2235
 
1121
2236
  <li class="md-nav__item">
1122
- <a href="../../../user-guides/getting-started/vlans-and-vlan-groups.html" class="md-nav__link">
1123
- VLANS and VLAN Groups
2237
+ <a href="../../../models/ipam/vrf.html" class="md-nav__link">
2238
+ VRF
1124
2239
  </a>
1125
2240
  </li>
1126
2241
 
@@ -1143,20 +2258,21 @@
1143
2258
  <li class="md-nav__item md-nav__item--nested">
1144
2259
 
1145
2260
 
1146
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_7" type="checkbox" id="__nav_2_7" >
1147
2261
 
1148
2262
 
2263
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_5" >
1149
2264
 
1150
2265
 
1151
- <label class="md-nav__link" for="__nav_2_7">
1152
- Core Functionality
2266
+
2267
+ <label class="md-nav__link" for="__nav_2_8_5" id="__nav_2_8_5_label" tabindex="0">
2268
+ Tenancy
1153
2269
  <span class="md-nav__icon md-icon"></span>
1154
2270
  </label>
1155
2271
 
1156
- <nav class="md-nav" aria-label="Core Functionality" data-md-level="2">
1157
- <label class="md-nav__title" for="__nav_2_7">
2272
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_5_label" aria-expanded="false">
2273
+ <label class="md-nav__title" for="__nav_2_8_5">
1158
2274
  <span class="md-nav__icon md-icon"></span>
1159
- Core Functionality
2275
+ Tenancy
1160
2276
  </label>
1161
2277
  <ul class="md-nav__list" data-md-scrollfix>
1162
2278
 
@@ -1166,8 +2282,8 @@
1166
2282
 
1167
2283
 
1168
2284
  <li class="md-nav__item">
1169
- <a href="../../../core-functionality/circuits.html" class="md-nav__link">
1170
- Circuits
2285
+ <a href="../../../models/tenancy/tenant.html" class="md-nav__link">
2286
+ Tenant
1171
2287
  </a>
1172
2288
  </li>
1173
2289
 
@@ -1180,27 +2296,47 @@
1180
2296
 
1181
2297
 
1182
2298
  <li class="md-nav__item">
1183
- <a href="../../../core-functionality/devices.html" class="md-nav__link">
1184
- Devices and Cabling
2299
+ <a href="../../../models/tenancy/tenantgroup.html" class="md-nav__link">
2300
+ Tenant Group
1185
2301
  </a>
1186
2302
  </li>
1187
2303
 
1188
2304
 
1189
2305
 
1190
2306
 
2307
+ </ul>
2308
+ </nav>
2309
+ </li>
2310
+
2311
+
2312
+
2313
+
1191
2314
 
1192
2315
 
1193
2316
 
1194
2317
 
1195
2318
 
1196
- <li class="md-nav__item">
1197
- <a href="../../../core-functionality/device-types.html" class="md-nav__link">
1198
- Device Types
1199
- </a>
1200
- </li>
1201
-
1202
-
1203
-
2319
+
2320
+ <li class="md-nav__item md-nav__item--nested">
2321
+
2322
+
2323
+
2324
+
2325
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_6" >
2326
+
2327
+
2328
+
2329
+ <label class="md-nav__link" for="__nav_2_8_6" id="__nav_2_8_6_label" tabindex="0">
2330
+ Users
2331
+ <span class="md-nav__icon md-icon"></span>
2332
+ </label>
2333
+
2334
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_6_label" aria-expanded="false">
2335
+ <label class="md-nav__title" for="__nav_2_8_6">
2336
+ <span class="md-nav__icon md-icon"></span>
2337
+ Users
2338
+ </label>
2339
+ <ul class="md-nav__list" data-md-scrollfix>
1204
2340
 
1205
2341
 
1206
2342
 
@@ -1208,8 +2344,8 @@
1208
2344
 
1209
2345
 
1210
2346
  <li class="md-nav__item">
1211
- <a href="../../../core-functionality/ipam.html" class="md-nav__link">
1212
- IP Address Management
2347
+ <a href="../../../models/users/objectpermission.html" class="md-nav__link">
2348
+ Object Permission
1213
2349
  </a>
1214
2350
  </li>
1215
2351
 
@@ -1222,27 +2358,47 @@
1222
2358
 
1223
2359
 
1224
2360
  <li class="md-nav__item">
1225
- <a href="../../../core-functionality/power.html" class="md-nav__link">
1226
- Power Tracking
2361
+ <a href="../../../models/users/token.html" class="md-nav__link">
2362
+ Token
1227
2363
  </a>
1228
2364
  </li>
1229
2365
 
1230
2366
 
1231
2367
 
1232
2368
 
2369
+ </ul>
2370
+ </nav>
2371
+ </li>
2372
+
2373
+
2374
+
2375
+
1233
2376
 
1234
2377
 
1235
2378
 
1236
2379
 
1237
2380
 
1238
- <li class="md-nav__item">
1239
- <a href="../../../core-functionality/secrets.html" class="md-nav__link">
1240
- Secrets
1241
- </a>
1242
- </li>
1243
-
1244
-
1245
-
2381
+
2382
+ <li class="md-nav__item md-nav__item--nested">
2383
+
2384
+
2385
+
2386
+
2387
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_8_7" >
2388
+
2389
+
2390
+
2391
+ <label class="md-nav__link" for="__nav_2_8_7" id="__nav_2_8_7_label" tabindex="0">
2392
+ Virtualization
2393
+ <span class="md-nav__icon md-icon"></span>
2394
+ </label>
2395
+
2396
+ <nav class="md-nav" data-md-level="3" aria-labelledby="__nav_2_8_7_label" aria-expanded="false">
2397
+ <label class="md-nav__title" for="__nav_2_8_7">
2398
+ <span class="md-nav__icon md-icon"></span>
2399
+ Virtualization
2400
+ </label>
2401
+ <ul class="md-nav__list" data-md-scrollfix>
1246
2402
 
1247
2403
 
1248
2404
 
@@ -1250,8 +2406,8 @@
1250
2406
 
1251
2407
 
1252
2408
  <li class="md-nav__item">
1253
- <a href="../../../core-functionality/services.html" class="md-nav__link">
1254
- Service Mapping
2409
+ <a href="../../../models/virtualization/cluster.html" class="md-nav__link">
2410
+ Cluster
1255
2411
  </a>
1256
2412
  </li>
1257
2413
 
@@ -1264,8 +2420,8 @@
1264
2420
 
1265
2421
 
1266
2422
  <li class="md-nav__item">
1267
- <a href="../../../core-functionality/sites-and-racks.html" class="md-nav__link">
1268
- Sites, Locations, and Racks
2423
+ <a href="../../../models/virtualization/clustergroup.html" class="md-nav__link">
2424
+ Cluster Group
1269
2425
  </a>
1270
2426
  </li>
1271
2427
 
@@ -1278,8 +2434,8 @@
1278
2434
 
1279
2435
 
1280
2436
  <li class="md-nav__item">
1281
- <a href="../../../core-functionality/tenancy.html" class="md-nav__link">
1282
- Tenancy
2437
+ <a href="../../../models/virtualization/clustertype.html" class="md-nav__link">
2438
+ Cluster Type
1283
2439
  </a>
1284
2440
  </li>
1285
2441
 
@@ -1292,8 +2448,8 @@
1292
2448
 
1293
2449
 
1294
2450
  <li class="md-nav__item">
1295
- <a href="../../../core-functionality/virtualization.html" class="md-nav__link">
1296
- Virtualization
2451
+ <a href="../../../models/virtualization/virtualmachine.html" class="md-nav__link">
2452
+ Virtual Machine
1297
2453
  </a>
1298
2454
  </li>
1299
2455
 
@@ -1306,8 +2462,8 @@
1306
2462
 
1307
2463
 
1308
2464
  <li class="md-nav__item">
1309
- <a href="../../../core-functionality/vlans.html" class="md-nav__link">
1310
- VLAN Management
2465
+ <a href="../../../models/virtualization/vminterface.html" class="md-nav__link">
2466
+ VM Interface
1311
2467
  </a>
1312
2468
  </li>
1313
2469
 
@@ -1321,6 +2477,13 @@
1321
2477
 
1322
2478
 
1323
2479
 
2480
+ </ul>
2481
+ </nav>
2482
+ </li>
2483
+
2484
+
2485
+
2486
+
1324
2487
 
1325
2488
 
1326
2489
 
@@ -1330,18 +2493,19 @@
1330
2493
  <li class="md-nav__item md-nav__item--nested">
1331
2494
 
1332
2495
 
1333
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_8" type="checkbox" id="__nav_2_8" >
1334
2496
 
1335
2497
 
2498
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_9" >
2499
+
1336
2500
 
1337
2501
 
1338
- <label class="md-nav__link" for="__nav_2_8">
2502
+ <label class="md-nav__link" for="__nav_2_9" id="__nav_2_9_label" tabindex="0">
1339
2503
  Additional Features
1340
2504
  <span class="md-nav__icon md-icon"></span>
1341
2505
  </label>
1342
2506
 
1343
- <nav class="md-nav" aria-label="Additional Features" data-md-level="2">
1344
- <label class="md-nav__title" for="__nav_2_8">
2507
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_9_label" aria-expanded="false">
2508
+ <label class="md-nav__title" for="__nav_2_9">
1345
2509
  <span class="md-nav__icon md-icon"></span>
1346
2510
  Additional Features
1347
2511
  </label>
@@ -1671,18 +2835,19 @@
1671
2835
  <li class="md-nav__item md-nav__item--nested">
1672
2836
 
1673
2837
 
1674
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_9" type="checkbox" id="__nav_2_9" >
1675
2838
 
1676
2839
 
2840
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_10" >
1677
2841
 
1678
2842
 
1679
- <label class="md-nav__link" for="__nav_2_9">
2843
+
2844
+ <label class="md-nav__link" for="__nav_2_10" id="__nav_2_10_label" tabindex="0">
1680
2845
  REST API
1681
2846
  <span class="md-nav__icon md-icon"></span>
1682
2847
  </label>
1683
2848
 
1684
- <nav class="md-nav" aria-label="REST API" data-md-level="2">
1685
- <label class="md-nav__title" for="__nav_2_9">
2849
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_10_label" aria-expanded="false">
2850
+ <label class="md-nav__title" for="__nav_2_10">
1686
2851
  <span class="md-nav__icon md-icon"></span>
1687
2852
  REST API
1688
2853
  </label>
@@ -1730,6 +2895,20 @@
1730
2895
 
1731
2896
 
1732
2897
 
2898
+
2899
+
2900
+
2901
+
2902
+
2903
+ <li class="md-nav__item">
2904
+ <a href="../../../rest-api/ui-related-endpoints.html" class="md-nav__link">
2905
+ UI Endpoints
2906
+ </a>
2907
+ </li>
2908
+
2909
+
2910
+
2911
+
1733
2912
  </ul>
1734
2913
  </nav>
1735
2914
  </li>
@@ -1746,18 +2925,19 @@
1746
2925
  <li class="md-nav__item md-nav__item--nested">
1747
2926
 
1748
2927
 
1749
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_2_10" type="checkbox" id="__nav_2_10" >
1750
2928
 
1751
2929
 
2930
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_2_11" >
2931
+
1752
2932
 
1753
2933
 
1754
- <label class="md-nav__link" for="__nav_2_10">
2934
+ <label class="md-nav__link" for="__nav_2_11" id="__nav_2_11_label" tabindex="0">
1755
2935
  GraphQL API
1756
2936
  <span class="md-nav__icon md-icon"></span>
1757
2937
  </label>
1758
2938
 
1759
- <nav class="md-nav" aria-label="GraphQL API" data-md-level="2">
1760
- <label class="md-nav__title" for="__nav_2_10">
2939
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_2_11_label" aria-expanded="false">
2940
+ <label class="md-nav__title" for="__nav_2_11">
1761
2941
  <span class="md-nav__icon md-icon"></span>
1762
2942
  GraphQL API
1763
2943
  </label>
@@ -1817,17 +2997,18 @@
1817
2997
  <li class="md-nav__item md-nav__item--active md-nav__item--nested">
1818
2998
 
1819
2999
 
1820
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3" type="checkbox" id="__nav_3" checked>
1821
3000
 
1822
3001
 
3002
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3" checked>
3003
+
1823
3004
 
1824
3005
 
1825
- <label class="md-nav__link" for="__nav_3">
3006
+ <label class="md-nav__link" for="__nav_3" id="__nav_3_label" tabindex="0">
1826
3007
  App Developer Guide
1827
3008
  <span class="md-nav__icon md-icon"></span>
1828
3009
  </label>
1829
3010
 
1830
- <nav class="md-nav" aria-label="App Developer Guide" data-md-level="1">
3011
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_3_label" aria-expanded="true">
1831
3012
  <label class="md-nav__title" for="__nav_3">
1832
3013
  <span class="md-nav__icon md-icon"></span>
1833
3014
  App Developer Guide
@@ -1873,17 +3054,18 @@
1873
3054
  <li class="md-nav__item md-nav__item--active md-nav__item--nested">
1874
3055
 
1875
3056
 
1876
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_3_3" type="checkbox" id="__nav_3_3" checked>
1877
3057
 
1878
3058
 
3059
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_3_3" checked>
1879
3060
 
1880
3061
 
1881
- <label class="md-nav__link" for="__nav_3_3">
3062
+
3063
+ <label class="md-nav__link" for="__nav_3_3" id="__nav_3_3_label" tabindex="0">
1882
3064
  Code Reference
1883
3065
  <span class="md-nav__icon md-icon"></span>
1884
3066
  </label>
1885
3067
 
1886
- <nav class="md-nav" aria-label="Code Reference" data-md-level="2">
3068
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_3_3_label" aria-expanded="true">
1887
3069
  <label class="md-nav__title" for="__nav_3_3">
1888
3070
  <span class="md-nav__icon md-icon"></span>
1889
3071
  Code Reference
@@ -1969,7 +3151,7 @@
1969
3151
 
1970
3152
  <li class="md-nav__item md-nav__item--active">
1971
3153
 
1972
- <input class="md-nav__toggle md-toggle" data-md-toggle="toc" type="checkbox" id="__toc">
3154
+ <input class="md-nav__toggle md-toggle" type="checkbox" id="__toc">
1973
3155
 
1974
3156
 
1975
3157
 
@@ -2288,17 +3470,18 @@
2288
3470
  <li class="md-nav__item md-nav__item--nested">
2289
3471
 
2290
3472
 
2291
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_4" type="checkbox" id="__nav_4" >
2292
3473
 
2293
3474
 
3475
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_4" >
3476
+
2294
3477
 
2295
3478
 
2296
- <label class="md-nav__link" for="__nav_4">
3479
+ <label class="md-nav__link" for="__nav_4" id="__nav_4_label" tabindex="0">
2297
3480
  Core Developer Guide
2298
3481
  <span class="md-nav__icon md-icon"></span>
2299
3482
  </label>
2300
3483
 
2301
- <nav class="md-nav" aria-label="Core Developer Guide" data-md-level="1">
3484
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_4_label" aria-expanded="false">
2302
3485
  <label class="md-nav__title" for="__nav_4">
2303
3486
  <span class="md-nav__icon md-icon"></span>
2304
3487
  Core Developer Guide
@@ -2532,17 +3715,18 @@
2532
3715
  <li class="md-nav__item md-nav__item--nested">
2533
3716
 
2534
3717
 
2535
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_5" type="checkbox" id="__nav_5" >
2536
3718
 
2537
3719
 
3720
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_5" >
2538
3721
 
2539
3722
 
2540
- <label class="md-nav__link" for="__nav_5">
3723
+
3724
+ <label class="md-nav__link" for="__nav_5" id="__nav_5_label" tabindex="0">
2541
3725
  Release Notes
2542
3726
  <span class="md-nav__icon md-icon"></span>
2543
3727
  </label>
2544
3728
 
2545
- <nav class="md-nav" aria-label="Release Notes" data-md-level="1">
3729
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_5_label" aria-expanded="false">
2546
3730
  <label class="md-nav__title" for="__nav_5">
2547
3731
  <span class="md-nav__icon md-icon"></span>
2548
3732
  Release Notes
@@ -2678,17 +3862,18 @@
2678
3862
  <li class="md-nav__item md-nav__item--nested">
2679
3863
 
2680
3864
 
2681
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6" type="checkbox" id="__nav_6" >
2682
3865
 
2683
3866
 
3867
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6" >
3868
+
2684
3869
 
2685
3870
 
2686
- <label class="md-nav__link" for="__nav_6">
3871
+ <label class="md-nav__link" for="__nav_6" id="__nav_6_label" tabindex="0">
2687
3872
  Nautobot Apps
2688
3873
  <span class="md-nav__icon md-icon"></span>
2689
3874
  </label>
2690
3875
 
2691
- <nav class="md-nav" aria-label="Nautobot Apps" data-md-level="1">
3876
+ <nav class="md-nav" data-md-level="1" aria-labelledby="__nav_6_label" aria-expanded="false">
2692
3877
  <label class="md-nav__title" for="__nav_6">
2693
3878
  <span class="md-nav__icon md-icon"></span>
2694
3879
  Nautobot Apps
@@ -2718,17 +3903,18 @@
2718
3903
  <li class="md-nav__item md-nav__item--nested">
2719
3904
 
2720
3905
 
2721
- <input class="md-nav__toggle md-toggle" data-md-toggle="__nav_6_2" type="checkbox" id="__nav_6_2" >
2722
3906
 
2723
3907
 
3908
+ <input class="md-nav__toggle md-toggle " type="checkbox" id="__nav_6_2" >
2724
3909
 
2725
3910
 
2726
- <label class="md-nav__link" for="__nav_6_2">
3911
+
3912
+ <label class="md-nav__link" for="__nav_6_2" id="__nav_6_2_label" tabindex="0">
2727
3913
  Network to Code App Docs
2728
3914
  <span class="md-nav__icon md-icon"></span>
2729
3915
  </label>
2730
3916
 
2731
- <nav class="md-nav" aria-label="Network to Code App Docs" data-md-level="2">
3917
+ <nav class="md-nav" data-md-level="2" aria-labelledby="__nav_6_2_label" aria-expanded="false">
2732
3918
  <label class="md-nav__title" for="__nav_6_2">
2733
3919
  <span class="md-nav__icon md-icon"></span>
2734
3920
  Network to Code App Docs
@@ -2755,8 +3941,8 @@
2755
3941
 
2756
3942
 
2757
3943
  <li class="md-nav__item">
2758
- <a href="https://nautobot-plugin-firewall-models.readthedocs.io/en/latest/" class="md-nav__link">
2759
- Nautobot Firewall Models
3944
+ <a href="https://docs.nautobot.com/projects/circuit-maintenance/en/latest/" class="md-nav__link">
3945
+ Nautobot Circuit Maintenance
2760
3946
  </a>
2761
3947
  </li>
2762
3948
 
@@ -2769,8 +3955,36 @@
2769
3955
 
2770
3956
 
2771
3957
  <li class="md-nav__item">
2772
- <a href="https://docs.nautobot.com/projects/plugin-nornir/en/latest/" class="md-nav__link">
2773
- Nautobot Plugin Nornir
3958
+ <a href="https://docs.nautobot.com/projects/device-lifecycle/en/latest/" class="md-nav__link">
3959
+ Nautobot Device LifeCycle Management
3960
+ </a>
3961
+ </li>
3962
+
3963
+
3964
+
3965
+
3966
+
3967
+
3968
+
3969
+
3970
+
3971
+ <li class="md-nav__item">
3972
+ <a href="https://docs.nautobot.com/projects/device-onboarding/en/latest/" class="md-nav__link">
3973
+ Nautobot Device Onboarding
3974
+ </a>
3975
+ </li>
3976
+
3977
+
3978
+
3979
+
3980
+
3981
+
3982
+
3983
+
3984
+
3985
+ <li class="md-nav__item">
3986
+ <a href="https://nautobot-plugin-firewall-models.readthedocs.io/en/latest/" class="md-nav__link">
3987
+ Nautobot Firewall Models
2774
3988
  </a>
2775
3989
  </li>
2776
3990
 
@@ -2797,7 +4011,21 @@
2797
4011
 
2798
4012
 
2799
4013
  <li class="md-nav__item">
2800
- <a href="https://nautobot-plugin-ssot.readthedocs.io/en/latest/" class="md-nav__link">
4014
+ <a href="https://docs.nautobot.com/projects/plugin-nornir/en/latest/" class="md-nav__link">
4015
+ Nautobot Plugin Nornir
4016
+ </a>
4017
+ </li>
4018
+
4019
+
4020
+
4021
+
4022
+
4023
+
4024
+
4025
+
4026
+
4027
+ <li class="md-nav__item">
4028
+ <a href="https://docs.nautobot.com/projects/ssot/en/latest/" class="md-nav__link">
2801
4029
  Nautobot Single Source of Truth
2802
4030
  </a>
2803
4031
  </li>
@@ -3031,10 +4259,8 @@
3031
4259
 
3032
4260
 
3033
4261
 
3034
- <a href="https://github.com/nautobot/nautobot/edit/main/nautobot/docs/nautobot/apps/filters.py" title="Edit this page" class="md-content__button md-icon">
3035
-
3036
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20.71 7.04c.39-.39.39-1.04 0-1.41l-2.34-2.34c-.37-.39-1.02-.39-1.41 0l-1.84 1.83 3.75 3.75M3 17.25V21h3.75L17.81 9.93l-3.75-3.75L3 17.25Z"/></svg>
3037
- </a>
4262
+
4263
+
3038
4264
 
3039
4265
 
3040
4266
  <div class="doc doc-object doc-module">
@@ -3083,7 +4309,8 @@
3083
4309
 
3084
4310
  <details class="quote">
3085
4311
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3086
- <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>
3087
4314
  <span class="normal"><a href="#__codelineno-0-533">533</a></span>
3088
4315
  <span class="normal"><a href="#__codelineno-0-534">534</a></span>
3089
4316
  <span class="normal"><a href="#__codelineno-0-535">535</a></span>
@@ -3308,234 +4535,233 @@
3308
4535
  <span class="normal"><a href="#__codelineno-0-754">754</a></span>
3309
4536
  <span class="normal"><a href="#__codelineno-0-755">755</a></span>
3310
4537
  <span class="normal"><a href="#__codelineno-0-756">756</a></span>
3311
- <span class="normal"><a href="#__codelineno-0-757">757</a></span>
3312
- <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>
3313
- <a id="__codelineno-0-533" name="__codelineno-0-533"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3314
- <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>
3315
- <a id="__codelineno-0-535" name="__codelineno-0-535"></a><span class="sd"> &quot;&quot;&quot;</span>
3316
- <a id="__codelineno-0-536" name="__codelineno-0-536"></a>
3317
- <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>
3318
- <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>
3319
- <a id="__codelineno-0-539" name="__codelineno-0-539"></a> <span class="p">{</span>
3320
- <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>
3321
- <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>
3322
- <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>
3323
- <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>
3324
- <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>
3325
- <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>
3326
- <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>
3327
- <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>
3328
- <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>
3329
- <a id="__codelineno-0-549" name="__codelineno-0-549"></a> <span class="c1"># Ref: https://github.com/carltongibson/django-filter/issues/1107</span>
3330
- <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>
3331
- <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>
3332
- <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>
3333
- <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>
3334
- <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>
3335
- <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>
3336
- <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>
3337
- <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>
3338
- <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>
3339
- <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>
3340
- <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>
3341
- <a id="__codelineno-0-561" name="__codelineno-0-561"></a> <span class="p">}</span>
3342
- <a id="__codelineno-0-562" name="__codelineno-0-562"></a> <span class="p">)</span>
3343
- <a id="__codelineno-0-563" name="__codelineno-0-563"></a>
3344
- <a id="__codelineno-0-564" name="__codelineno-0-564"></a> <span class="nd">@staticmethod</span>
3345
- <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>
3346
- <a id="__codelineno-0-566" name="__codelineno-0-566"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
3347
- <a id="__codelineno-0-567" name="__codelineno-0-567"></a> <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span>
3348
- <a id="__codelineno-0-568" name="__codelineno-0-568"></a> <span class="n">existing_filter</span><span class="p">,</span>
3349
- <a id="__codelineno-0-569" name="__codelineno-0-569"></a> <span class="p">(</span>
3350
- <a id="__codelineno-0-570" name="__codelineno-0-570"></a> <span class="n">MultiValueDateFilter</span><span class="p">,</span>
3351
- <a id="__codelineno-0-571" name="__codelineno-0-571"></a> <span class="n">MultiValueDateTimeFilter</span><span class="p">,</span>
3352
- <a id="__codelineno-0-572" name="__codelineno-0-572"></a> <span class="n">MultiValueDecimalFilter</span><span class="p">,</span>
3353
- <a id="__codelineno-0-573" name="__codelineno-0-573"></a> <span class="n">MultiValueFloatFilter</span><span class="p">,</span>
3354
- <a id="__codelineno-0-574" name="__codelineno-0-574"></a> <span class="n">MultiValueNumberFilter</span><span class="p">,</span>
3355
- <a id="__codelineno-0-575" name="__codelineno-0-575"></a> <span class="n">MultiValueTimeFilter</span><span class="p">,</span>
3356
- <a id="__codelineno-0-576" name="__codelineno-0-576"></a> <span class="p">),</span>
3357
- <a id="__codelineno-0-577" name="__codelineno-0-577"></a> <span class="p">):</span>
3358
- <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>
3359
- <a id="__codelineno-0-579" name="__codelineno-0-579"></a>
3360
- <a id="__codelineno-0-580" name="__codelineno-0-580"></a> <span class="c1"># These filter types support only negation</span>
3361
- <a id="__codelineno-0-581" name="__codelineno-0-581"></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span>
3362
- <a id="__codelineno-0-582" name="__codelineno-0-582"></a> <span class="n">existing_filter</span><span class="p">,</span>
3363
- <a id="__codelineno-0-583" name="__codelineno-0-583"></a> <span class="p">(</span>
3364
- <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>
3365
- <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>
3366
- <a id="__codelineno-0-586" name="__codelineno-0-586"></a> <span class="n">TagFilter</span><span class="p">,</span>
3367
- <a id="__codelineno-0-587" name="__codelineno-0-587"></a> <span class="n">TreeNodeMultipleChoiceFilter</span><span class="p">,</span>
3368
- <a id="__codelineno-0-588" name="__codelineno-0-588"></a> <span class="p">),</span>
3369
- <a id="__codelineno-0-589" name="__codelineno-0-589"></a> <span class="p">):</span>
3370
- <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>
3371
- <a id="__codelineno-0-591" name="__codelineno-0-591"></a>
3372
- <a id="__codelineno-0-592" name="__codelineno-0-592"></a> <span class="k">elif</span> <span class="nb">isinstance</span><span class="p">(</span>
3373
- <a id="__codelineno-0-593" name="__codelineno-0-593"></a> <span class="n">existing_filter</span><span class="p">,</span>
3374
- <a id="__codelineno-0-594" name="__codelineno-0-594"></a> <span class="p">(</span>
3375
- <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>
3376
- <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>
3377
- <a id="__codelineno-0-597" name="__codelineno-0-597"></a> <span class="n">MultiValueCharFilter</span><span class="p">,</span>
3378
- <a id="__codelineno-0-598" name="__codelineno-0-598"></a> <span class="n">MultiValueMACAddressFilter</span><span class="p">,</span>
3379
- <a id="__codelineno-0-599" name="__codelineno-0-599"></a> <span class="p">),</span>
3380
- <a id="__codelineno-0-600" name="__codelineno-0-600"></a> <span class="p">):</span>
3381
- <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>
3382
- <a id="__codelineno-0-602" name="__codelineno-0-602"></a>
3383
- <a id="__codelineno-0-603" name="__codelineno-0-603"></a> <span class="k">else</span><span class="p">:</span>
3384
- <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>
3385
- <a id="__codelineno-0-605" name="__codelineno-0-605"></a>
3386
- <a id="__codelineno-0-606" name="__codelineno-0-606"></a> <span class="k">return</span> <span class="n">lookup_map</span>
3387
- <a id="__codelineno-0-607" name="__codelineno-0-607"></a>
3388
- <a id="__codelineno-0-608" name="__codelineno-0-608"></a> <span class="nd">@classmethod</span>
3389
- <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>
3390
- <a id="__codelineno-0-610" name="__codelineno-0-610"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3391
- <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>
3392
- <a id="__codelineno-0-612" name="__codelineno-0-612"></a><span class="sd"> the form `&lt;field_name&gt;__&lt;lookup_expr&gt;`</span>
3393
- <a id="__codelineno-0-613" name="__codelineno-0-613"></a><span class="sd"> &quot;&quot;&quot;</span>
3394
- <a id="__codelineno-0-614" name="__codelineno-0-614"></a> <span class="n">magic_filters</span> <span class="o">=</span> <span class="p">{}</span>
3395
- <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>
3396
- <a id="__codelineno-0-616" name="__codelineno-0-616"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3397
- <a id="__codelineno-0-617" name="__codelineno-0-617"></a>
3398
- <a id="__codelineno-0-618" name="__codelineno-0-618"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
3399
- <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>
3400
- <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>
3401
- <a id="__codelineno-0-621" name="__codelineno-0-621"></a> <span class="c1"># Do not augment this filter type with more lookup expressions</span>
3402
- <a id="__codelineno-0-622" name="__codelineno-0-622"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3403
- <a id="__codelineno-0-623" name="__codelineno-0-623"></a>
3404
- <a id="__codelineno-0-624" name="__codelineno-0-624"></a> <span class="c1"># Get properties of the existing filter for later use</span>
3405
- <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>
3406
- <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>
3407
- <a id="__codelineno-0-627" name="__codelineno-0-627"></a>
3408
- <a id="__codelineno-0-628" name="__codelineno-0-628"></a> <span class="c1"># If there isn&#39;t a model field, return.</span>
3409
- <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>
3410
- <a id="__codelineno-0-630" name="__codelineno-0-630"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3411
- <a id="__codelineno-0-631" name="__codelineno-0-631"></a>
3412
- <a id="__codelineno-0-632" name="__codelineno-0-632"></a> <span class="c1"># Create new filters for each lookup expression in the map</span>
3413
- <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>
3414
- <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>
3415
- <a id="__codelineno-0-635" name="__codelineno-0-635"></a>
3416
- <a id="__codelineno-0-636" name="__codelineno-0-636"></a> <span class="k">try</span><span class="p">:</span>
3417
- <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>
3418
- <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>
3419
- <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>
3420
- <a id="__codelineno-0-640" name="__codelineno-0-640"></a> <span class="c1"># is the same as the default type for the field</span>
3421
- <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>
3422
- <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>
3423
- <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>
3424
- <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>
3425
- <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>
3426
- <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>
3427
- <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>
3428
- <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>
3429
- <a id="__codelineno-0-649" name="__codelineno-0-649"></a> <span class="p">)</span>
3430
- <a id="__codelineno-0-650" name="__codelineno-0-650"></a> <span class="k">else</span><span class="p">:</span>
3431
- <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>
3432
- <a id="__codelineno-0-652" name="__codelineno-0-652"></a> <span class="c1"># Will raise FieldLookupError if the lookup is invalid</span>
3433
- <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>
3434
- <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>
3435
- <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>
3436
- <a id="__codelineno-0-656" name="__codelineno-0-656"></a> <span class="k">continue</span>
3437
- <a id="__codelineno-0-657" name="__codelineno-0-657"></a>
3438
- <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>
3439
- <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>
3440
- <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>
3441
- <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>
3442
- <a id="__codelineno-0-662" name="__codelineno-0-662"></a>
3443
- <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>
3444
- <a id="__codelineno-0-664" name="__codelineno-0-664"></a>
3445
- <a id="__codelineno-0-665" name="__codelineno-0-665"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3446
- <a id="__codelineno-0-666" name="__codelineno-0-666"></a>
3447
- <a id="__codelineno-0-667" name="__codelineno-0-667"></a> <span class="nd">@classmethod</span>
3448
- <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>
3449
- <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3450
- <a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="sd"> Allow filters to be added post-generation on import.</span>
3451
- <a id="__codelineno-0-671" name="__codelineno-0-671"></a>
3452
- <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>
3453
- <a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> &quot;&quot;&quot;</span>
3454
- <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>
3455
- <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>
3456
- <a id="__codelineno-0-676" name="__codelineno-0-676"></a>
3457
- <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>
3458
- <a id="__codelineno-0-678" name="__codelineno-0-678"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3459
- <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>
3460
- <a id="__codelineno-0-680" name="__codelineno-0-680"></a> <span class="p">)</span>
3461
- <a id="__codelineno-0-681" name="__codelineno-0-681"></a>
3462
- <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>
3463
- <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>
3464
- <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>
3465
- <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>
3466
- <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>
3467
- <a id="__codelineno-0-687" name="__codelineno-0-687"></a> <span class="p">)</span>
3468
- <a id="__codelineno-0-688" name="__codelineno-0-688"></a>
3469
- <a id="__codelineno-0-689" name="__codelineno-0-689"></a> <span class="nd">@classmethod</span>
3470
- <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>
3471
- <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>
3472
- <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>
3473
- <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>
3474
- <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>
3475
- <a id="__codelineno-0-695" name="__codelineno-0-695"></a> <span class="k">return</span> <span class="n">fields</span>
3476
- <a id="__codelineno-0-696" name="__codelineno-0-696"></a>
3477
- <a id="__codelineno-0-697" name="__codelineno-0-697"></a> <span class="nd">@classmethod</span>
3478
- <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>
3479
- <a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3480
- <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>
3481
- <a id="__codelineno-0-701" name="__codelineno-0-701"></a><span class="sd"> &quot;&quot;&quot;</span>
3482
- <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>
3483
- <a id="__codelineno-0-703" name="__codelineno-0-703"></a>
3484
- <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>
3485
- <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>
3486
- <a id="__codelineno-0-706" name="__codelineno-0-706"></a> <span class="n">new_filters</span> <span class="o">=</span> <span class="p">{}</span>
3487
- <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>
3488
- <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>
3489
- <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>
3490
- <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>
3491
- <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>
3492
- <a id="__codelineno-0-712" name="__codelineno-0-712"></a> <span class="p">)</span>
3493
- <a id="__codelineno-0-713" name="__codelineno-0-713"></a> <span class="p">)</span>
3494
- <a id="__codelineno-0-714" name="__codelineno-0-714"></a>
3495
- <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>
3496
- <a id="__codelineno-0-716" name="__codelineno-0-716"></a>
3497
- <a id="__codelineno-0-717" name="__codelineno-0-717"></a> <span class="k">return</span> <span class="n">filters</span>
3498
- <a id="__codelineno-0-718" name="__codelineno-0-718"></a>
3499
- <a id="__codelineno-0-719" name="__codelineno-0-719"></a> <span class="nd">@classmethod</span>
3500
- <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>
3501
- <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>
3502
- <a id="__codelineno-0-722" name="__codelineno-0-722"></a>
3503
- <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>
3504
- <a id="__codelineno-0-724" name="__codelineno-0-724"></a><span class="sd"> &quot;&quot;&quot;</span>
3505
- <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>
3506
- <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>
3507
- <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>
3508
- <a id="__codelineno-0-728" name="__codelineno-0-728"></a>
3509
- <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>
3510
- <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>
3511
- <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>
3512
- <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>
3513
- <a id="__codelineno-0-733" name="__codelineno-0-733"></a>
3514
- <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>
3515
- <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>
3516
- <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>
3517
- <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>
3518
- <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>
3519
- <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>
3520
- <a id="__codelineno-0-740" name="__codelineno-0-740"></a> <span class="k">else</span><span class="p">:</span>
3521
- <a id="__codelineno-0-741" name="__codelineno-0-741"></a> <span class="c1"># Trigger warning logs associated with generating self.errors</span>
3522
- <a id="__codelineno-0-742" name="__codelineno-0-742"></a> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span>
3523
- <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>
3524
- <a id="__codelineno-0-744" name="__codelineno-0-744"></a>
3525
- <a id="__codelineno-0-745" name="__codelineno-0-745"></a> <span class="nd">@property</span>
3526
- <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>
3527
- <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>
3528
- <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>
3529
- <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>
3530
- <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>
3531
- <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>
3532
- <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>
3533
- <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>
3534
- <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>
3535
- <a id="__codelineno-0-755" name="__codelineno-0-755"></a> <span class="k">else</span><span class="p">:</span>
3536
- <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>
3537
- <a id="__codelineno-0-757" name="__codelineno-0-757"></a>
3538
- <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>
3539
4765
  </code></pre></div></td></tr></table></div>
3540
4766
  </details>
3541
4767
 
@@ -3593,7 +4819,8 @@
3593
4819
 
3594
4820
  <details class="quote">
3595
4821
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3596
- <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>
3597
4824
  <span class="normal"><a href="#__codelineno-0-668">668</a></span>
3598
4825
  <span class="normal"><a href="#__codelineno-0-669">669</a></span>
3599
4826
  <span class="normal"><a href="#__codelineno-0-670">670</a></span>
@@ -3612,28 +4839,27 @@
3612
4839
  <span class="normal"><a href="#__codelineno-0-683">683</a></span>
3613
4840
  <span class="normal"><a href="#__codelineno-0-684">684</a></span>
3614
4841
  <span class="normal"><a href="#__codelineno-0-685">685</a></span>
3615
- <span class="normal"><a href="#__codelineno-0-686">686</a></span>
3616
- <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>
3617
- <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>
3618
- <a id="__codelineno-0-669" name="__codelineno-0-669"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3619
- <a id="__codelineno-0-670" name="__codelineno-0-670"></a><span class="sd"> Allow filters to be added post-generation on import.</span>
3620
- <a id="__codelineno-0-671" name="__codelineno-0-671"></a>
3621
- <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>
3622
- <a id="__codelineno-0-673" name="__codelineno-0-673"></a><span class="sd"> &quot;&quot;&quot;</span>
3623
- <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>
3624
- <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>
3625
- <a id="__codelineno-0-676" name="__codelineno-0-676"></a>
3626
- <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>
3627
- <a id="__codelineno-0-678" name="__codelineno-0-678"></a> <span class="k">raise</span> <span class="ne">AttributeError</span><span class="p">(</span>
3628
- <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>
3629
- <a id="__codelineno-0-680" name="__codelineno-0-680"></a> <span class="p">)</span>
3630
- <a id="__codelineno-0-681" name="__codelineno-0-681"></a>
3631
- <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>
3632
- <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>
3633
- <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>
3634
- <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>
3635
- <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>
3636
- <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>
3637
4863
  </code></pre></div></td></tr></table></div>
3638
4864
  </details>
3639
4865
  </div>
@@ -3661,23 +4887,23 @@
3661
4887
 
3662
4888
  <details class="quote">
3663
4889
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3664
- <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>
3665
4892
  <span class="normal"><a href="#__codelineno-0-720">720</a></span>
3666
4893
  <span class="normal"><a href="#__codelineno-0-721">721</a></span>
3667
4894
  <span class="normal"><a href="#__codelineno-0-722">722</a></span>
3668
4895
  <span class="normal"><a href="#__codelineno-0-723">723</a></span>
3669
4896
  <span class="normal"><a href="#__codelineno-0-724">724</a></span>
3670
4897
  <span class="normal"><a href="#__codelineno-0-725">725</a></span>
3671
- <span class="normal"><a href="#__codelineno-0-726">726</a></span>
3672
- <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>
3673
- <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>
3674
- <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>
3675
- <a id="__codelineno-0-722" name="__codelineno-0-722"></a>
3676
- <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>
3677
- <a id="__codelineno-0-724" name="__codelineno-0-724"></a><span class="sd"> &quot;&quot;&quot;</span>
3678
- <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>
3679
- <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>
3680
- <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>
3681
4907
  </code></pre></div></td></tr></table></div>
3682
4908
  </details>
3683
4909
  </div>
@@ -3704,7 +4930,8 @@
3704
4930
 
3705
4931
  <details class="quote">
3706
4932
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3707
- <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>
3708
4935
  <span class="normal"><a href="#__codelineno-0-698">698</a></span>
3709
4936
  <span class="normal"><a href="#__codelineno-0-699">699</a></span>
3710
4937
  <span class="normal"><a href="#__codelineno-0-700">700</a></span>
@@ -3723,28 +4950,27 @@
3723
4950
  <span class="normal"><a href="#__codelineno-0-713">713</a></span>
3724
4951
  <span class="normal"><a href="#__codelineno-0-714">714</a></span>
3725
4952
  <span class="normal"><a href="#__codelineno-0-715">715</a></span>
3726
- <span class="normal"><a href="#__codelineno-0-716">716</a></span>
3727
- <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>
3728
- <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>
3729
- <a id="__codelineno-0-699" name="__codelineno-0-699"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3730
- <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>
3731
- <a id="__codelineno-0-701" name="__codelineno-0-701"></a><span class="sd"> &quot;&quot;&quot;</span>
3732
- <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>
3733
- <a id="__codelineno-0-703" name="__codelineno-0-703"></a>
3734
- <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>
3735
- <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>
3736
- <a id="__codelineno-0-706" name="__codelineno-0-706"></a> <span class="n">new_filters</span> <span class="o">=</span> <span class="p">{}</span>
3737
- <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>
3738
- <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>
3739
- <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>
3740
- <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>
3741
- <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>
3742
- <a id="__codelineno-0-712" name="__codelineno-0-712"></a> <span class="p">)</span>
3743
- <a id="__codelineno-0-713" name="__codelineno-0-713"></a> <span class="p">)</span>
3744
- <a id="__codelineno-0-714" name="__codelineno-0-714"></a>
3745
- <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>
3746
- <a id="__codelineno-0-716" name="__codelineno-0-716"></a>
3747
- <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>
3748
4974
  </code></pre></div></td></tr></table></div>
3749
4975
  </details>
3750
4976
  </div>
@@ -3767,7 +4993,8 @@
3767
4993
 
3768
4994
  <details class="quote">
3769
4995
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
3770
- <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>
3771
4998
  <span class="normal"><a href="#__codelineno-0-735">735</a></span>
3772
4999
  <span class="normal"><a href="#__codelineno-0-736">736</a></span>
3773
5000
  <span class="normal"><a href="#__codelineno-0-737">737</a></span>
@@ -3775,17 +5002,16 @@
3775
5002
  <span class="normal"><a href="#__codelineno-0-739">739</a></span>
3776
5003
  <span class="normal"><a href="#__codelineno-0-740">740</a></span>
3777
5004
  <span class="normal"><a href="#__codelineno-0-741">741</a></span>
3778
- <span class="normal"><a href="#__codelineno-0-742">742</a></span>
3779
- <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>
3780
- <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>
3781
- <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>
3782
- <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>
3783
- <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>
3784
- <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>
3785
- <a id="__codelineno-0-740" name="__codelineno-0-740"></a> <span class="k">else</span><span class="p">:</span>
3786
- <a id="__codelineno-0-741" name="__codelineno-0-741"></a> <span class="c1"># Trigger warning logs associated with generating self.errors</span>
3787
- <a id="__codelineno-0-742" name="__codelineno-0-742"></a> <span class="bp">self</span><span class="o">.</span><span class="n">errors</span>
3788
- <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>
3789
5015
  </code></pre></div></td></tr></table></div>
3790
5016
  </details>
3791
5017
  </div>
@@ -3822,8 +5048,7 @@ extra lookup expressions on supported CustomField types.</p>
3822
5048
 
3823
5049
  <details class="quote">
3824
5050
  <summary>Source code in <code>nautobot/extras/filters/mixins.py</code></summary>
3825
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-53"> 53</a></span>
3826
- <span class="normal"><a href="#__codelineno-0-54"> 54</a></span>
5051
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-54"> 54</a></span>
3827
5052
  <span class="normal"><a href="#__codelineno-0-55"> 55</a></span>
3828
5053
  <span class="normal"><a href="#__codelineno-0-56"> 56</a></span>
3829
5054
  <span class="normal"><a href="#__codelineno-0-57"> 57</a></span>
@@ -3905,90 +5130,91 @@ extra lookup expressions on supported CustomField types.</p>
3905
5130
  <span class="normal"><a href="#__codelineno-0-133">133</a></span>
3906
5131
  <span class="normal"><a href="#__codelineno-0-134">134</a></span>
3907
5132
  <span class="normal"><a href="#__codelineno-0-135">135</a></span>
3908
- <span class="normal"><a href="#__codelineno-0-136">136</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-53" name="__codelineno-0-53"></a><span class="k">class</span> <span class="nc">CustomFieldModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
3909
- <a id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3910
- <a id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="sd"> Dynamically add a Filter for each CustomField applicable to the parent model. Add filters for</span>
3911
- <a id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="sd"> extra lookup expressions on supported CustomField types.</span>
3912
- <a id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="sd"> &quot;&quot;&quot;</span>
3913
- <a id="__codelineno-0-58" name="__codelineno-0-58"></a>
3914
- <a id="__codelineno-0-59" name="__codelineno-0-59"></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>
3915
- <a id="__codelineno-0-60" name="__codelineno-0-60"></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>
3916
- <a id="__codelineno-0-61" name="__codelineno-0-61"></a>
3917
- <a id="__codelineno-0-62" name="__codelineno-0-62"></a> <span class="n">custom_field_filter_classes</span> <span class="o">=</span> <span class="p">{</span>
3918
- <a id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_DATE</span><span class="p">:</span> <span class="n">CustomFieldDateFilter</span><span class="p">,</span>
3919
- <a id="__codelineno-0-64" name="__codelineno-0-64"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_BOOLEAN</span><span class="p">:</span> <span class="n">CustomFieldBooleanFilter</span><span class="p">,</span>
3920
- <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_INTEGER</span><span class="p">:</span> <span class="n">CustomFieldNumberFilter</span><span class="p">,</span>
3921
- <a id="__codelineno-0-66" name="__codelineno-0-66"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_JSON</span><span class="p">:</span> <span class="n">CustomFieldJSONFilter</span><span class="p">,</span>
3922
- <a id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_MULTISELECT</span><span class="p">:</span> <span class="n">CustomFieldMultiSelectFilter</span><span class="p">,</span>
3923
- <a id="__codelineno-0-68" name="__codelineno-0-68"></a> <span class="p">}</span>
3924
- <a id="__codelineno-0-69" name="__codelineno-0-69"></a>
3925
- <a id="__codelineno-0-70" name="__codelineno-0-70"></a> <span class="n">custom_fields</span> <span class="o">=</span> <span class="n">CustomField</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
3926
- <a id="__codelineno-0-71" name="__codelineno-0-71"></a> <span class="n">content_types</span><span class="o">=</span><span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
3927
- <a id="__codelineno-0-72" name="__codelineno-0-72"></a> <span class="p">)</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="n">filter_logic</span><span class="o">=</span><span class="n">CustomFieldFilterLogicChoices</span><span class="o">.</span><span class="n">FILTER_DISABLED</span><span class="p">)</span>
3928
- <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="k">for</span> <span class="n">cf</span> <span class="ow">in</span> <span class="n">custom_fields</span><span class="p">:</span>
3929
- <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="c1"># Determine filter class for this CustomField type, default to CustomFieldCharFilter</span>
3930
- <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="n">new_filter_name</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">add_prefix_to_cf_key</span><span class="p">()</span>
3931
- <a id="__codelineno-0-76" name="__codelineno-0-76"></a> <span class="n">filter_class</span> <span class="o">=</span> <span class="n">custom_field_filter_classes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">cf</span><span class="o">.</span><span class="n">type</span><span class="p">,</span> <span class="n">CustomFieldCharFilter</span><span class="p">)</span>
3932
- <a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="n">filter_class</span><span class="p">(</span><span class="n">field_name</span><span class="o">=</span><span class="n">cf</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">custom_field</span><span class="o">=</span><span class="n">cf</span><span class="p">)</span>
3933
- <a id="__codelineno-0-78" name="__codelineno-0-78"></a> <span class="n">new_filter</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">cf</span><span class="o">.</span><span class="n">label</span><span class="si">}</span><span class="s2">&quot;</span>
3934
- <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="c1"># Create base filter (cf_customfieldname)</span>
3935
- <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="bp">self</span><span class="o">.</span><span class="n">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>
3936
- <a id="__codelineno-0-81" name="__codelineno-0-81"></a>
3937
- <a id="__codelineno-0-82" name="__codelineno-0-82"></a> <span class="c1"># Create extra lookup expression filters (cf_customfieldname__lookup_expr)</span>
3938
- <a id="__codelineno-0-83" name="__codelineno-0-83"></a> <span class="bp">self</span><span class="o">.</span><span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
3939
- <a id="__codelineno-0-84" name="__codelineno-0-84"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_generate_custom_field_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">custom_field</span><span class="o">=</span><span class="n">cf</span><span class="p">)</span>
3940
- <a id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="p">)</span>
3941
- <a id="__codelineno-0-86" name="__codelineno-0-86"></a>
3942
- <a id="__codelineno-0-87" name="__codelineno-0-87"></a> <span class="nd">@staticmethod</span>
3943
- <a id="__codelineno-0-88" name="__codelineno-0-88"></a> <span class="k">def</span> <span class="nf">_get_custom_field_filter_lookup_dict</span><span class="p">(</span><span class="n">filter_type</span><span class="p">):</span>
3944
- <a id="__codelineno-0-89" name="__codelineno-0-89"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
3945
- <a id="__codelineno-0-90" name="__codelineno-0-90"></a> <span class="k">if</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">filter_type</span><span class="p">,</span> <span class="p">(</span><span class="n">CustomFieldMultiValueNumberFilter</span><span class="p">,</span> <span class="n">CustomFieldMultiValueDateFilter</span><span class="p">)):</span>
3946
- <a id="__codelineno-0-91" name="__codelineno-0-91"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">FILTER_NUMERIC_BASED_LOOKUP_MAP</span>
3947
- <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="k">else</span><span class="p">:</span>
3948
- <a id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">FILTER_CHAR_BASED_LOOKUP_MAP</span>
3949
- <a id="__codelineno-0-94" name="__codelineno-0-94"></a>
3950
- <a id="__codelineno-0-95" name="__codelineno-0-95"></a> <span class="k">return</span> <span class="n">lookup_map</span>
3951
- <a id="__codelineno-0-96" name="__codelineno-0-96"></a>
3952
- <a id="__codelineno-0-97" name="__codelineno-0-97"></a> <span class="c1"># TODO 2.0: Transition CustomField filters to nautobot.core.filters.MultiValue* filters and</span>
3953
- <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="c1"># leverage BaseFilterSet to add dynamic lookup expression filters. Remove CustomField.filter_logic field</span>
3954
- <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="nd">@classmethod</span>
3955
- <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="k">def</span> <span class="nf">_generate_custom_field_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">custom_field</span><span class="p">):</span>
3956
- <a id="__codelineno-0-101" name="__codelineno-0-101"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
3957
- <a id="__codelineno-0-102" name="__codelineno-0-102"></a><span class="sd"> For specific filter types, new filters are created based on defined lookup expressions in</span>
3958
- <a id="__codelineno-0-103" name="__codelineno-0-103"></a><span class="sd"> the form `&lt;field_name&gt;__&lt;lookup_expr&gt;`. Copied from nautobot.core.filters.BaseFilterSet</span>
3959
- <a id="__codelineno-0-104" name="__codelineno-0-104"></a><span class="sd"> and updated to work with custom fields.</span>
3960
- <a id="__codelineno-0-105" name="__codelineno-0-105"></a><span class="sd"> &quot;&quot;&quot;</span>
3961
- <a id="__codelineno-0-106" name="__codelineno-0-106"></a> <span class="n">magic_filters</span> <span class="o">=</span> <span class="p">{}</span>
3962
- <a id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="n">custom_field_type_to_filter_map</span> <span class="o">=</span> <span class="p">{</span>
3963
- <a id="__codelineno-0-108" name="__codelineno-0-108"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_DATE</span><span class="p">:</span> <span class="n">CustomFieldMultiValueDateFilter</span><span class="p">,</span>
3964
- <a id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_INTEGER</span><span class="p">:</span> <span class="n">CustomFieldMultiValueNumberFilter</span><span class="p">,</span>
3965
- <a id="__codelineno-0-110" name="__codelineno-0-110"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_SELECT</span><span class="p">:</span> <span class="n">CustomFieldMultiValueCharFilter</span><span class="p">,</span>
3966
- <a id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_TEXT</span><span class="p">:</span> <span class="n">CustomFieldMultiValueCharFilter</span><span class="p">,</span>
3967
- <a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_URL</span><span class="p">:</span> <span class="n">CustomFieldMultiValueCharFilter</span><span class="p">,</span>
3968
- <a id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="p">}</span>
3969
- <a id="__codelineno-0-114" name="__codelineno-0-114"></a>
3970
- <a id="__codelineno-0-115" name="__codelineno-0-115"></a> <span class="k">if</span> <span class="n">custom_field</span><span class="o">.</span><span class="n">type</span> <span class="ow">in</span> <span class="n">custom_field_type_to_filter_map</span><span class="p">:</span>
3971
- <a id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="n">filter_type</span> <span class="o">=</span> <span class="n">custom_field_type_to_filter_map</span><span class="p">[</span><span class="n">custom_field</span><span class="o">.</span><span class="n">type</span><span class="p">]</span>
3972
- <a id="__codelineno-0-117" name="__codelineno-0-117"></a> <span class="k">else</span><span class="p">:</span>
3973
- <a id="__codelineno-0-118" name="__codelineno-0-118"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3974
- <a id="__codelineno-0-119" name="__codelineno-0-119"></a>
3975
- <a id="__codelineno-0-120" name="__codelineno-0-120"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
3976
- <a id="__codelineno-0-121" name="__codelineno-0-121"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_get_custom_field_filter_lookup_dict</span><span class="p">(</span><span class="n">filter_type</span><span class="p">)</span>
3977
- <a id="__codelineno-0-122" name="__codelineno-0-122"></a>
3978
- <a id="__codelineno-0-123" name="__codelineno-0-123"></a> <span class="c1"># Create new filters for each lookup expression in the map</span>
3979
- <a id="__codelineno-0-124" name="__codelineno-0-124"></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>
3980
- <a id="__codelineno-0-125" name="__codelineno-0-125"></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>
3981
- <a id="__codelineno-0-126" name="__codelineno-0-126"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="n">filter_type</span><span class="p">(</span>
3982
- <a id="__codelineno-0-127" name="__codelineno-0-127"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">custom_field</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
3983
- <a id="__codelineno-0-128" name="__codelineno-0-128"></a> <span class="n">lookup_expr</span><span class="o">=</span><span class="n">lookup_expr</span><span class="p">,</span>
3984
- <a id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="n">custom_field</span><span class="o">=</span><span class="n">custom_field</span><span class="p">,</span>
3985
- <a id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">custom_field</span><span class="o">.</span><span class="n">label</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">verbose_lookup_expr</span><span class="p">(</span><span class="n">lookup_expr</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">,</span>
3986
- <a id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="n">exclude</span><span class="o">=</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>
3987
- <a id="__codelineno-0-132" name="__codelineno-0-132"></a> <span class="p">)</span>
3988
- <a id="__codelineno-0-133" name="__codelineno-0-133"></a>
3989
- <a id="__codelineno-0-134" name="__codelineno-0-134"></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>
3990
- <a id="__codelineno-0-135" name="__codelineno-0-135"></a>
3991
- <a id="__codelineno-0-136" name="__codelineno-0-136"></a> <span class="k">return</span> <span class="n">magic_filters</span>
5133
+ <span class="normal"><a href="#__codelineno-0-136">136</a></span>
5134
+ <span class="normal"><a href="#__codelineno-0-137">137</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-54" name="__codelineno-0-54"></a><span class="k">class</span> <span class="nc">CustomFieldModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
5135
+ <a id="__codelineno-0-55" name="__codelineno-0-55"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5136
+ <a id="__codelineno-0-56" name="__codelineno-0-56"></a><span class="sd"> Dynamically add a Filter for each CustomField applicable to the parent model. Add filters for</span>
5137
+ <a id="__codelineno-0-57" name="__codelineno-0-57"></a><span class="sd"> extra lookup expressions on supported CustomField types.</span>
5138
+ <a id="__codelineno-0-58" name="__codelineno-0-58"></a><span class="sd"> &quot;&quot;&quot;</span>
5139
+ <a id="__codelineno-0-59" name="__codelineno-0-59"></a>
5140
+ <a id="__codelineno-0-60" name="__codelineno-0-60"></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>
5141
+ <a id="__codelineno-0-61" name="__codelineno-0-61"></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>
5142
+ <a id="__codelineno-0-62" name="__codelineno-0-62"></a>
5143
+ <a id="__codelineno-0-63" name="__codelineno-0-63"></a> <span class="n">custom_field_filter_classes</span> <span class="o">=</span> <span class="p">{</span>
5144
+ <a id="__codelineno-0-64" name="__codelineno-0-64"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_DATE</span><span class="p">:</span> <span class="n">CustomFieldDateFilter</span><span class="p">,</span>
5145
+ <a id="__codelineno-0-65" name="__codelineno-0-65"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_BOOLEAN</span><span class="p">:</span> <span class="n">CustomFieldBooleanFilter</span><span class="p">,</span>
5146
+ <a id="__codelineno-0-66" name="__codelineno-0-66"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_INTEGER</span><span class="p">:</span> <span class="n">CustomFieldNumberFilter</span><span class="p">,</span>
5147
+ <a id="__codelineno-0-67" name="__codelineno-0-67"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_JSON</span><span class="p">:</span> <span class="n">CustomFieldJSONFilter</span><span class="p">,</span>
5148
+ <a id="__codelineno-0-68" name="__codelineno-0-68"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_MULTISELECT</span><span class="p">:</span> <span class="n">CustomFieldMultiSelectFilter</span><span class="p">,</span>
5149
+ <a id="__codelineno-0-69" name="__codelineno-0-69"></a> <span class="p">}</span>
5150
+ <a id="__codelineno-0-70" name="__codelineno-0-70"></a>
5151
+ <a id="__codelineno-0-71" name="__codelineno-0-71"></a> <span class="n">custom_fields</span> <span class="o">=</span> <span class="n">CustomField</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span>
5152
+ <a id="__codelineno-0-72" name="__codelineno-0-72"></a> <span class="n">content_types</span><span class="o">=</span><span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
5153
+ <a id="__codelineno-0-73" name="__codelineno-0-73"></a> <span class="p">)</span><span class="o">.</span><span class="n">exclude</span><span class="p">(</span><span class="n">filter_logic</span><span class="o">=</span><span class="n">CustomFieldFilterLogicChoices</span><span class="o">.</span><span class="n">FILTER_DISABLED</span><span class="p">)</span>
5154
+ <a id="__codelineno-0-74" name="__codelineno-0-74"></a> <span class="k">for</span> <span class="n">cf</span> <span class="ow">in</span> <span class="n">custom_fields</span><span class="p">:</span>
5155
+ <a id="__codelineno-0-75" name="__codelineno-0-75"></a> <span class="c1"># Determine filter class for this CustomField type, default to CustomFieldCharFilter</span>
5156
+ <a id="__codelineno-0-76" name="__codelineno-0-76"></a> <span class="n">new_filter_name</span> <span class="o">=</span> <span class="n">cf</span><span class="o">.</span><span class="n">add_prefix_to_cf_key</span><span class="p">()</span>
5157
+ <a id="__codelineno-0-77" name="__codelineno-0-77"></a> <span class="n">filter_class</span> <span class="o">=</span> <span class="n">custom_field_filter_classes</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">cf</span><span class="o">.</span><span class="n">type</span><span class="p">,</span> <span class="n">CustomFieldCharFilter</span><span class="p">)</span>
5158
+ <a id="__codelineno-0-78" name="__codelineno-0-78"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="n">filter_class</span><span class="p">(</span><span class="n">field_name</span><span class="o">=</span><span class="n">cf</span><span class="o">.</span><span class="n">key</span><span class="p">,</span> <span class="n">custom_field</span><span class="o">=</span><span class="n">cf</span><span class="p">)</span>
5159
+ <a id="__codelineno-0-79" name="__codelineno-0-79"></a> <span class="n">new_filter</span><span class="o">.</span><span class="n">label</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">cf</span><span class="o">.</span><span class="n">label</span><span class="si">}</span><span class="s2">&quot;</span>
5160
+ <a id="__codelineno-0-80" name="__codelineno-0-80"></a> <span class="c1"># Create base filter (cf_customfieldname)</span>
5161
+ <a id="__codelineno-0-81" name="__codelineno-0-81"></a> <span class="bp">self</span><span class="o">.</span><span class="n">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>
5162
+ <a id="__codelineno-0-82" name="__codelineno-0-82"></a>
5163
+ <a id="__codelineno-0-83" name="__codelineno-0-83"></a> <span class="c1"># Create extra lookup expression filters (cf_customfieldname__lookup_expr)</span>
5164
+ <a id="__codelineno-0-84" name="__codelineno-0-84"></a> <span class="bp">self</span><span class="o">.</span><span class="n">filters</span><span class="o">.</span><span class="n">update</span><span class="p">(</span>
5165
+ <a id="__codelineno-0-85" name="__codelineno-0-85"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_generate_custom_field_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">custom_field</span><span class="o">=</span><span class="n">cf</span><span class="p">)</span>
5166
+ <a id="__codelineno-0-86" name="__codelineno-0-86"></a> <span class="p">)</span>
5167
+ <a id="__codelineno-0-87" name="__codelineno-0-87"></a>
5168
+ <a id="__codelineno-0-88" name="__codelineno-0-88"></a> <span class="nd">@staticmethod</span>
5169
+ <a id="__codelineno-0-89" name="__codelineno-0-89"></a> <span class="k">def</span> <span class="nf">_get_custom_field_filter_lookup_dict</span><span class="p">(</span><span class="n">filter_type</span><span class="p">):</span>
5170
+ <a id="__codelineno-0-90" name="__codelineno-0-90"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
5171
+ <a id="__codelineno-0-91" name="__codelineno-0-91"></a> <span class="k">if</span> <span class="nb">issubclass</span><span class="p">(</span><span class="n">filter_type</span><span class="p">,</span> <span class="p">(</span><span class="n">CustomFieldMultiValueNumberFilter</span><span class="p">,</span> <span class="n">CustomFieldMultiValueDateFilter</span><span class="p">)):</span>
5172
+ <a id="__codelineno-0-92" name="__codelineno-0-92"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">FILTER_NUMERIC_BASED_LOOKUP_MAP</span>
5173
+ <a id="__codelineno-0-93" name="__codelineno-0-93"></a> <span class="k">else</span><span class="p">:</span>
5174
+ <a id="__codelineno-0-94" name="__codelineno-0-94"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="n">FILTER_CHAR_BASED_LOOKUP_MAP</span>
5175
+ <a id="__codelineno-0-95" name="__codelineno-0-95"></a>
5176
+ <a id="__codelineno-0-96" name="__codelineno-0-96"></a> <span class="k">return</span> <span class="n">lookup_map</span>
5177
+ <a id="__codelineno-0-97" name="__codelineno-0-97"></a>
5178
+ <a id="__codelineno-0-98" name="__codelineno-0-98"></a> <span class="c1"># TODO 2.0: Transition CustomField filters to nautobot.core.filters.MultiValue* filters and</span>
5179
+ <a id="__codelineno-0-99" name="__codelineno-0-99"></a> <span class="c1"># leverage BaseFilterSet to add dynamic lookup expression filters. Remove CustomField.filter_logic field</span>
5180
+ <a id="__codelineno-0-100" name="__codelineno-0-100"></a> <span class="nd">@classmethod</span>
5181
+ <a id="__codelineno-0-101" name="__codelineno-0-101"></a> <span class="k">def</span> <span class="nf">_generate_custom_field_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">custom_field</span><span class="p">):</span>
5182
+ <a id="__codelineno-0-102" name="__codelineno-0-102"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5183
+ <a id="__codelineno-0-103" name="__codelineno-0-103"></a><span class="sd"> For specific filter types, new filters are created based on defined lookup expressions in</span>
5184
+ <a id="__codelineno-0-104" name="__codelineno-0-104"></a><span class="sd"> the form `&lt;field_name&gt;__&lt;lookup_expr&gt;`. Copied from nautobot.core.filters.BaseFilterSet</span>
5185
+ <a id="__codelineno-0-105" name="__codelineno-0-105"></a><span class="sd"> and updated to work with custom fields.</span>
5186
+ <a id="__codelineno-0-106" name="__codelineno-0-106"></a><span class="sd"> &quot;&quot;&quot;</span>
5187
+ <a id="__codelineno-0-107" name="__codelineno-0-107"></a> <span class="n">magic_filters</span> <span class="o">=</span> <span class="p">{}</span>
5188
+ <a id="__codelineno-0-108" name="__codelineno-0-108"></a> <span class="n">custom_field_type_to_filter_map</span> <span class="o">=</span> <span class="p">{</span>
5189
+ <a id="__codelineno-0-109" name="__codelineno-0-109"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_DATE</span><span class="p">:</span> <span class="n">CustomFieldMultiValueDateFilter</span><span class="p">,</span>
5190
+ <a id="__codelineno-0-110" name="__codelineno-0-110"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_INTEGER</span><span class="p">:</span> <span class="n">CustomFieldMultiValueNumberFilter</span><span class="p">,</span>
5191
+ <a id="__codelineno-0-111" name="__codelineno-0-111"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_SELECT</span><span class="p">:</span> <span class="n">CustomFieldMultiValueCharFilter</span><span class="p">,</span>
5192
+ <a id="__codelineno-0-112" name="__codelineno-0-112"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_TEXT</span><span class="p">:</span> <span class="n">CustomFieldMultiValueCharFilter</span><span class="p">,</span>
5193
+ <a id="__codelineno-0-113" name="__codelineno-0-113"></a> <span class="n">CustomFieldTypeChoices</span><span class="o">.</span><span class="n">TYPE_URL</span><span class="p">:</span> <span class="n">CustomFieldMultiValueCharFilter</span><span class="p">,</span>
5194
+ <a id="__codelineno-0-114" name="__codelineno-0-114"></a> <span class="p">}</span>
5195
+ <a id="__codelineno-0-115" name="__codelineno-0-115"></a>
5196
+ <a id="__codelineno-0-116" name="__codelineno-0-116"></a> <span class="k">if</span> <span class="n">custom_field</span><span class="o">.</span><span class="n">type</span> <span class="ow">in</span> <span class="n">custom_field_type_to_filter_map</span><span class="p">:</span>
5197
+ <a id="__codelineno-0-117" name="__codelineno-0-117"></a> <span class="n">filter_type</span> <span class="o">=</span> <span class="n">custom_field_type_to_filter_map</span><span class="p">[</span><span class="n">custom_field</span><span class="o">.</span><span class="n">type</span><span class="p">]</span>
5198
+ <a id="__codelineno-0-118" name="__codelineno-0-118"></a> <span class="k">else</span><span class="p">:</span>
5199
+ <a id="__codelineno-0-119" name="__codelineno-0-119"></a> <span class="k">return</span> <span class="n">magic_filters</span>
5200
+ <a id="__codelineno-0-120" name="__codelineno-0-120"></a>
5201
+ <a id="__codelineno-0-121" name="__codelineno-0-121"></a> <span class="c1"># Choose the lookup expression map based on the filter type</span>
5202
+ <a id="__codelineno-0-122" name="__codelineno-0-122"></a> <span class="n">lookup_map</span> <span class="o">=</span> <span class="bp">cls</span><span class="o">.</span><span class="n">_get_custom_field_filter_lookup_dict</span><span class="p">(</span><span class="n">filter_type</span><span class="p">)</span>
5203
+ <a id="__codelineno-0-123" name="__codelineno-0-123"></a>
5204
+ <a id="__codelineno-0-124" name="__codelineno-0-124"></a> <span class="c1"># Create new filters for each lookup expression in the map</span>
5205
+ <a id="__codelineno-0-125" name="__codelineno-0-125"></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>
5206
+ <a id="__codelineno-0-126" name="__codelineno-0-126"></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>
5207
+ <a id="__codelineno-0-127" name="__codelineno-0-127"></a> <span class="n">new_filter</span> <span class="o">=</span> <span class="n">filter_type</span><span class="p">(</span>
5208
+ <a id="__codelineno-0-128" name="__codelineno-0-128"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">custom_field</span><span class="o">.</span><span class="n">key</span><span class="p">,</span>
5209
+ <a id="__codelineno-0-129" name="__codelineno-0-129"></a> <span class="n">lookup_expr</span><span class="o">=</span><span class="n">lookup_expr</span><span class="p">,</span>
5210
+ <a id="__codelineno-0-130" name="__codelineno-0-130"></a> <span class="n">custom_field</span><span class="o">=</span><span class="n">custom_field</span><span class="p">,</span>
5211
+ <a id="__codelineno-0-131" name="__codelineno-0-131"></a> <span class="n">label</span><span class="o">=</span><span class="sa">f</span><span class="s2">&quot;</span><span class="si">{</span><span class="n">custom_field</span><span class="o">.</span><span class="n">label</span><span class="si">}</span><span class="s2"> (</span><span class="si">{</span><span class="n">verbose_lookup_expr</span><span class="p">(</span><span class="n">lookup_expr</span><span class="p">)</span><span class="si">}</span><span class="s2">)&quot;</span><span class="p">,</span>
5212
+ <a id="__codelineno-0-132" name="__codelineno-0-132"></a> <span class="n">exclude</span><span class="o">=</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>
5213
+ <a id="__codelineno-0-133" name="__codelineno-0-133"></a> <span class="p">)</span>
5214
+ <a id="__codelineno-0-134" name="__codelineno-0-134"></a>
5215
+ <a id="__codelineno-0-135" name="__codelineno-0-135"></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>
5216
+ <a id="__codelineno-0-136" name="__codelineno-0-136"></a>
5217
+ <a id="__codelineno-0-137" name="__codelineno-0-137"></a> <span class="k">return</span> <span class="n">magic_filters</span>
3992
5218
  </code></pre></div></td></tr></table></div>
3993
5219
  </details>
3994
5220
 
@@ -4031,21 +5257,21 @@ extra lookup expressions on supported CustomField types.</p>
4031
5257
 
4032
5258
  <details class="quote">
4033
5259
  <summary>Source code in <code>nautobot/extras/plugins/__init__.py</code></summary>
4034
- <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>
4035
- <span class="normal"><a href="#__codelineno-0-457">457</a></span>
4036
- <span class="normal"><a href="#__codelineno-0-458">458</a></span>
4037
- <span class="normal"><a href="#__codelineno-0-459">459</a></span>
4038
- <span class="normal"><a href="#__codelineno-0-460">460</a></span>
4039
- <span class="normal"><a href="#__codelineno-0-461">461</a></span>
4040
- <span class="normal"><a href="#__codelineno-0-462">462</a></span>
4041
- <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>
4042
- <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>
4043
- <a id="__codelineno-0-458" name="__codelineno-0-458"></a>
4044
- <a id="__codelineno-0-459" name="__codelineno-0-459"></a> <span class="n">model</span> <span class="o">=</span> <span class="kc">None</span>
4045
- <a id="__codelineno-0-460" name="__codelineno-0-460"></a>
4046
- <a id="__codelineno-0-461" name="__codelineno-0-461"></a> <span class="n">filterset_fields</span> <span class="o">=</span> <span class="p">{}</span>
4047
- <a id="__codelineno-0-462" name="__codelineno-0-462"></a>
4048
- <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>
4049
5275
  </code></pre></div></td></tr></table></div>
4050
5276
  </details>
4051
5277
 
@@ -4092,7 +5318,8 @@ keyword argument on filter initialization (defaults to <code>slug</code>).</p>
4092
5318
 
4093
5319
  <details class="quote">
4094
5320
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4095
- <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>
4096
5323
  <span class="normal"><a href="#__codelineno-0-391">391</a></span>
4097
5324
  <span class="normal"><a href="#__codelineno-0-392">392</a></span>
4098
5325
  <span class="normal"><a href="#__codelineno-0-393">393</a></span>
@@ -4141,58 +5368,57 @@ keyword argument on filter initialization (defaults to <code>slug</code>).</p>
4141
5368
  <span class="normal"><a href="#__codelineno-0-436">436</a></span>
4142
5369
  <span class="normal"><a href="#__codelineno-0-437">437</a></span>
4143
5370
  <span class="normal"><a href="#__codelineno-0-438">438</a></span>
4144
- <span class="normal"><a href="#__codelineno-0-439">439</a></span>
4145
- <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>
4146
- <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>
4147
- <a id="__codelineno-0-392" name="__codelineno-0-392"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4148
- <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>
4149
- <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>
4150
- <a id="__codelineno-0-395" name="__codelineno-0-395"></a><span class="sd"> keyword argument on filter initialization (defaults to `slug`).</span>
4151
- <a id="__codelineno-0-396" name="__codelineno-0-396"></a><span class="sd"> &quot;&quot;&quot;</span>
4152
- <a id="__codelineno-0-397" name="__codelineno-0-397"></a>
4153
- <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>
4154
- <a id="__codelineno-0-399" name="__codelineno-0-399"></a>
4155
- <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>
4156
- <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>
4157
- <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>
4158
- <a id="__codelineno-0-403" name="__codelineno-0-403"></a>
4159
- <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>
4160
- <a id="__codelineno-0-405" name="__codelineno-0-405"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4161
- <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>
4162
- <a id="__codelineno-0-407" name="__codelineno-0-407"></a><span class="sd"> the natural key in the generated filter.</span>
4163
- <a id="__codelineno-0-408" name="__codelineno-0-408"></a><span class="sd"> &quot;&quot;&quot;</span>
4164
- <a id="__codelineno-0-409" name="__codelineno-0-409"></a>
4165
- <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="c1"># Null value filtering</span>
4166
- <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>
4167
- <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>
4168
- <a id="__codelineno-0-413" name="__codelineno-0-413"></a>
4169
- <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>
4170
- <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>
4171
- <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>
4172
- <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>
4173
- <a id="__codelineno-0-418" name="__codelineno-0-418"></a>
4174
- <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>
4175
- <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="k">try</span><span class="p">:</span>
4176
- <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>
4177
- <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>
4178
- <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>
4179
- <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>
4180
- <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="k">else</span><span class="p">:</span>
4181
- <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>
4182
- <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>
4183
- <a id="__codelineno-0-428" name="__codelineno-0-428"></a>
4184
- <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>
4185
- <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>
4186
- <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>
4187
- <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>
4188
- <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="k">else</span><span class="p">:</span>
4189
- <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>
4190
- <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>
4191
- <a id="__codelineno-0-436" name="__codelineno-0-436"></a>
4192
- <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>
4193
- <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>
4194
- <a id="__codelineno-0-439" name="__codelineno-0-439"></a>
4195
- <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>
4196
5422
  </code></pre></div></td></tr></table></div>
4197
5423
  </details>
4198
5424
 
@@ -4225,7 +5451,8 @@ the natural key in the generated filter.</p>
4225
5451
 
4226
5452
  <details class="quote">
4227
5453
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4228
- <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>
4229
5456
  <span class="normal"><a href="#__codelineno-0-405">405</a></span>
4230
5457
  <span class="normal"><a href="#__codelineno-0-406">406</a></span>
4231
5458
  <span class="normal"><a href="#__codelineno-0-407">407</a></span>
@@ -4260,44 +5487,43 @@ the natural key in the generated filter.</p>
4260
5487
  <span class="normal"><a href="#__codelineno-0-436">436</a></span>
4261
5488
  <span class="normal"><a href="#__codelineno-0-437">437</a></span>
4262
5489
  <span class="normal"><a href="#__codelineno-0-438">438</a></span>
4263
- <span class="normal"><a href="#__codelineno-0-439">439</a></span>
4264
- <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>
4265
- <a id="__codelineno-0-405" name="__codelineno-0-405"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4266
- <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>
4267
- <a id="__codelineno-0-407" name="__codelineno-0-407"></a><span class="sd"> the natural key in the generated filter.</span>
4268
- <a id="__codelineno-0-408" name="__codelineno-0-408"></a><span class="sd"> &quot;&quot;&quot;</span>
4269
- <a id="__codelineno-0-409" name="__codelineno-0-409"></a>
4270
- <a id="__codelineno-0-410" name="__codelineno-0-410"></a> <span class="c1"># Null value filtering</span>
4271
- <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>
4272
- <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>
4273
- <a id="__codelineno-0-413" name="__codelineno-0-413"></a>
4274
- <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>
4275
- <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>
4276
- <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>
4277
- <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>
4278
- <a id="__codelineno-0-418" name="__codelineno-0-418"></a>
4279
- <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>
4280
- <a id="__codelineno-0-420" name="__codelineno-0-420"></a> <span class="k">try</span><span class="p">:</span>
4281
- <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>
4282
- <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>
4283
- <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>
4284
- <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>
4285
- <a id="__codelineno-0-425" name="__codelineno-0-425"></a> <span class="k">else</span><span class="p">:</span>
4286
- <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>
4287
- <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>
4288
- <a id="__codelineno-0-428" name="__codelineno-0-428"></a>
4289
- <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>
4290
- <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>
4291
- <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>
4292
- <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>
4293
- <a id="__codelineno-0-433" name="__codelineno-0-433"></a> <span class="k">else</span><span class="p">:</span>
4294
- <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>
4295
- <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>
4296
- <a id="__codelineno-0-436" name="__codelineno-0-436"></a>
4297
- <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>
4298
- <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>
4299
- <a id="__codelineno-0-439" name="__codelineno-0-439"></a>
4300
- <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>
4301
5527
  </code></pre></div></td></tr></table></div>
4302
5528
  </details>
4303
5529
  </div>
@@ -4335,27 +5561,27 @@ are needed.</p>
4335
5561
 
4336
5562
  <details class="quote">
4337
5563
  <summary>Source code in <code>nautobot/extras/filters/__init__.py</code></summary>
4338
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-368">368</a></span>
4339
- <span class="normal"><a href="#__codelineno-0-369">369</a></span>
4340
- <span class="normal"><a href="#__codelineno-0-370">370</a></span>
4341
- <span class="normal"><a href="#__codelineno-0-371">371</a></span>
4342
- <span class="normal"><a href="#__codelineno-0-372">372</a></span>
4343
- <span class="normal"><a href="#__codelineno-0-373">373</a></span>
5564
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-373">373</a></span>
4344
5565
  <span class="normal"><a href="#__codelineno-0-374">374</a></span>
4345
5566
  <span class="normal"><a href="#__codelineno-0-375">375</a></span>
4346
5567
  <span class="normal"><a href="#__codelineno-0-376">376</a></span>
4347
5568
  <span class="normal"><a href="#__codelineno-0-377">377</a></span>
4348
- <span class="normal"><a href="#__codelineno-0-378">378</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-368" name="__codelineno-0-368"></a><span class="k">class</span> <span class="nc">NautobotFilterSet</span><span class="p">(</span>
4349
- <a id="__codelineno-0-369" name="__codelineno-0-369"></a> <span class="n">BaseFilterSet</span><span class="p">,</span>
4350
- <a id="__codelineno-0-370" name="__codelineno-0-370"></a> <span class="n">CreatedUpdatedModelFilterSetMixin</span><span class="p">,</span>
4351
- <a id="__codelineno-0-371" name="__codelineno-0-371"></a> <span class="n">RelationshipModelFilterSetMixin</span><span class="p">,</span>
4352
- <a id="__codelineno-0-372" name="__codelineno-0-372"></a> <span class="n">CustomFieldModelFilterSetMixin</span><span class="p">,</span>
4353
- <a id="__codelineno-0-373" name="__codelineno-0-373"></a><span class="p">):</span>
4354
- <a id="__codelineno-0-374" name="__codelineno-0-374"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4355
- <a id="__codelineno-0-375" name="__codelineno-0-375"></a><span class="sd"> This class exists to combine common functionality and is used as a base class throughout the codebase where all of</span>
4356
- <a id="__codelineno-0-376" name="__codelineno-0-376"></a><span class="sd"> BaseFilterSet, CreatedUpdatedModelFilterSetMixin, RelationshipModelFilterSetMixin and CustomFieldModelFilterSetMixin</span>
4357
- <a id="__codelineno-0-377" name="__codelineno-0-377"></a><span class="sd"> are needed.</span>
4358
- <a id="__codelineno-0-378" name="__codelineno-0-378"></a><span class="sd"> &quot;&quot;&quot;</span>
5569
+ <span class="normal"><a href="#__codelineno-0-378">378</a></span>
5570
+ <span class="normal"><a href="#__codelineno-0-379">379</a></span>
5571
+ <span class="normal"><a href="#__codelineno-0-380">380</a></span>
5572
+ <span class="normal"><a href="#__codelineno-0-381">381</a></span>
5573
+ <span class="normal"><a href="#__codelineno-0-382">382</a></span>
5574
+ <span class="normal"><a href="#__codelineno-0-383">383</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-373" name="__codelineno-0-373"></a><span class="k">class</span> <span class="nc">NautobotFilterSet</span><span class="p">(</span>
5575
+ <a id="__codelineno-0-374" name="__codelineno-0-374"></a> <span class="n">BaseFilterSet</span><span class="p">,</span>
5576
+ <a id="__codelineno-0-375" name="__codelineno-0-375"></a> <span class="n">CreatedUpdatedModelFilterSetMixin</span><span class="p">,</span>
5577
+ <a id="__codelineno-0-376" name="__codelineno-0-376"></a> <span class="n">RelationshipModelFilterSetMixin</span><span class="p">,</span>
5578
+ <a id="__codelineno-0-377" name="__codelineno-0-377"></a> <span class="n">CustomFieldModelFilterSetMixin</span><span class="p">,</span>
5579
+ <a id="__codelineno-0-378" name="__codelineno-0-378"></a><span class="p">):</span>
5580
+ <a id="__codelineno-0-379" name="__codelineno-0-379"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5581
+ <a id="__codelineno-0-380" name="__codelineno-0-380"></a><span class="sd"> This class exists to combine common functionality and is used as a base class throughout the codebase where all of</span>
5582
+ <a id="__codelineno-0-381" name="__codelineno-0-381"></a><span class="sd"> BaseFilterSet, CreatedUpdatedModelFilterSetMixin, RelationshipModelFilterSetMixin and CustomFieldModelFilterSetMixin</span>
5583
+ <a id="__codelineno-0-382" name="__codelineno-0-382"></a><span class="sd"> are needed.</span>
5584
+ <a id="__codelineno-0-383" name="__codelineno-0-383"></a><span class="sd"> &quot;&quot;&quot;</span>
4359
5585
  </code></pre></div></td></tr></table></div>
4360
5586
  </details>
4361
5587
 
@@ -4395,7 +5621,8 @@ argument to test for the existence of related objects.</p>
4395
5621
 
4396
5622
  <details class="quote">
4397
5623
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4398
- <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>
4399
5626
  <span class="normal"><a href="#__codelineno-0-126">126</a></span>
4400
5627
  <span class="normal"><a href="#__codelineno-0-127">127</a></span>
4401
5628
  <span class="normal"><a href="#__codelineno-0-128">128</a></span>
@@ -4426,40 +5653,39 @@ argument to test for the existence of related objects.</p>
4426
5653
  <span class="normal"><a href="#__codelineno-0-153">153</a></span>
4427
5654
  <span class="normal"><a href="#__codelineno-0-154">154</a></span>
4428
5655
  <span class="normal"><a href="#__codelineno-0-155">155</a></span>
4429
- <span class="normal"><a href="#__codelineno-0-156">156</a></span>
4430
- <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>
4431
- <a id="__codelineno-0-126" name="__codelineno-0-126"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4432
- <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>
4433
- <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>
4434
- <a id="__codelineno-0-129" name="__codelineno-0-129"></a><span class="sd"> model.</span>
4435
- <a id="__codelineno-0-130" name="__codelineno-0-130"></a>
4436
- <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>
4437
- <a id="__codelineno-0-132" name="__codelineno-0-132"></a><span class="sd"> argument to test for the existence of related objects.</span>
4438
- <a id="__codelineno-0-133" name="__codelineno-0-133"></a>
4439
- <a id="__codelineno-0-134" name="__codelineno-0-134"></a><span class="sd"> Example:</span>
4440
- <a id="__codelineno-0-135" name="__codelineno-0-135"></a>
4441
- <a id="__codelineno-0-136" name="__codelineno-0-136"></a><span class="sd"> has_interfaces = RelatedMembershipBooleanFilter(</span>
4442
- <a id="__codelineno-0-137" name="__codelineno-0-137"></a><span class="sd"> field_name=&quot;interfaces&quot;,</span>
4443
- <a id="__codelineno-0-138" name="__codelineno-0-138"></a><span class="sd"> label=&quot;Has interfaces&quot;,</span>
4444
- <a id="__codelineno-0-139" name="__codelineno-0-139"></a><span class="sd"> )</span>
4445
- <a id="__codelineno-0-140" name="__codelineno-0-140"></a><span class="sd"> &quot;&quot;&quot;</span>
4446
- <a id="__codelineno-0-141" name="__codelineno-0-141"></a>
4447
- <a id="__codelineno-0-142" name="__codelineno-0-142"></a> <span class="k">def</span> <span class="fm">__init__</span><span class="p">(</span>
4448
- <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>
4449
- <a id="__codelineno-0-144" name="__codelineno-0-144"></a> <span class="p">):</span>
4450
- <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>
4451
- <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>
4452
- <a id="__codelineno-0-147" name="__codelineno-0-147"></a>
4453
- <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>
4454
- <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>
4455
- <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>
4456
- <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>
4457
- <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>
4458
- <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>
4459
- <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>
4460
- <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>
4461
- <a id="__codelineno-0-156" name="__codelineno-0-156"></a> <span class="o">**</span><span class="n">kwargs</span><span class="p">,</span>
4462
- <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>
4463
5689
  </code></pre></div></td></tr></table></div>
4464
5690
  </details>
4465
5691
 
@@ -4504,8 +5730,7 @@ argument to test for the existence of related objects.</p>
4504
5730
 
4505
5731
  <details class="quote">
4506
5732
  <summary>Source code in <code>nautobot/extras/filters/mixins.py</code></summary>
4507
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-218">218</a></span>
4508
- <span class="normal"><a href="#__codelineno-0-219">219</a></span>
5733
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-219">219</a></span>
4509
5734
  <span class="normal"><a href="#__codelineno-0-220">220</a></span>
4510
5735
  <span class="normal"><a href="#__codelineno-0-221">221</a></span>
4511
5736
  <span class="normal"><a href="#__codelineno-0-222">222</a></span>
@@ -4566,69 +5791,70 @@ argument to test for the existence of related objects.</p>
4566
5791
  <span class="normal"><a href="#__codelineno-0-277">277</a></span>
4567
5792
  <span class="normal"><a href="#__codelineno-0-278">278</a></span>
4568
5793
  <span class="normal"><a href="#__codelineno-0-279">279</a></span>
4569
- <span class="normal"><a href="#__codelineno-0-280">280</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-218" name="__codelineno-0-218"></a><span class="k">class</span> <span class="nc">RelationshipModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
4570
- <a id="__codelineno-0-219" name="__codelineno-0-219"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4571
- <a id="__codelineno-0-220" name="__codelineno-0-220"></a><span class="sd"> Filterset for relationships applicable to the parent model.</span>
4572
- <a id="__codelineno-0-221" name="__codelineno-0-221"></a><span class="sd"> &quot;&quot;&quot;</span>
4573
- <a id="__codelineno-0-222" name="__codelineno-0-222"></a>
4574
- <a id="__codelineno-0-223" name="__codelineno-0-223"></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>
4575
- <a id="__codelineno-0-224" name="__codelineno-0-224"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
4576
- <a id="__codelineno-0-225" name="__codelineno-0-225"></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>
4577
- <a id="__codelineno-0-226" name="__codelineno-0-226"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span> <span class="o">=</span> <span class="p">[]</span>
4578
- <a id="__codelineno-0-227" name="__codelineno-0-227"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
4579
- <a id="__codelineno-0-228" name="__codelineno-0-228"></a>
4580
- <a id="__codelineno-0-229" name="__codelineno-0-229"></a> <span class="k">def</span> <span class="nf">_append_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">model</span><span class="p">):</span>
4581
- <a id="__codelineno-0-230" name="__codelineno-0-230"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4582
- <a id="__codelineno-0-231" name="__codelineno-0-231"></a><span class="sd"> Append form fields for all Relationships assigned to this model.</span>
4583
- <a id="__codelineno-0-232" name="__codelineno-0-232"></a><span class="sd"> &quot;&quot;&quot;</span>
4584
- <a id="__codelineno-0-233" name="__codelineno-0-233"></a> <span class="n">query</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">source_hidden</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span>
4585
- <a id="__codelineno-0-234" name="__codelineno-0-234"></a> <span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">destination_hidden</span><span class="o">=</span><span class="kc">False</span>
4586
- <a id="__codelineno-0-235" name="__codelineno-0-235"></a> <span class="p">)</span>
4587
- <a id="__codelineno-0-236" name="__codelineno-0-236"></a> <span class="n">relationships</span> <span class="o">=</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">select_related</span><span class="p">(</span><span class="s2">&quot;source_type&quot;</span><span class="p">,</span> <span class="s2">&quot;destination_type&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
4588
- <a id="__codelineno-0-237" name="__codelineno-0-237"></a>
4589
- <a id="__codelineno-0-238" name="__codelineno-0-238"></a> <span class="k">for</span> <span class="n">rel</span> <span class="ow">in</span> <span class="n">relationships</span><span class="o">.</span><span class="n">iterator</span><span class="p">():</span>
4590
- <a id="__codelineno-0-239" name="__codelineno-0-239"></a> <span class="k">if</span> <span class="n">rel</span><span class="o">.</span><span class="n">source_type</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">rel</span><span class="o">.</span><span class="n">source_hidden</span><span class="p">:</span>
4591
- <a id="__codelineno-0-240" name="__codelineno-0-240"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">([</span><span class="n">rel</span><span class="p">],</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">,</span> <span class="n">model</span><span class="p">)</span>
4592
- <a id="__codelineno-0-241" name="__codelineno-0-241"></a> <span class="k">if</span> <span class="n">rel</span><span class="o">.</span><span class="n">destination_type</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">rel</span><span class="o">.</span><span class="n">destination_hidden</span><span class="p">:</span>
4593
- <a id="__codelineno-0-242" name="__codelineno-0-242"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">([</span><span class="n">rel</span><span class="p">],</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">,</span> <span class="n">model</span><span class="p">)</span>
4594
- <a id="__codelineno-0-243" name="__codelineno-0-243"></a>
4595
- <a id="__codelineno-0-244" name="__codelineno-0-244"></a> <span class="k">def</span> <span class="nf">_append_relationships_side</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">relationships</span><span class="p">,</span> <span class="n">initial_side</span><span class="p">,</span> <span class="n">model</span><span class="p">):</span>
4596
- <a id="__codelineno-0-245" name="__codelineno-0-245"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4597
- <a id="__codelineno-0-246" name="__codelineno-0-246"></a><span class="sd"> Helper method to _append_relationships, for processing one &quot;side&quot; of the relationships for this model.</span>
4598
- <a id="__codelineno-0-247" name="__codelineno-0-247"></a><span class="sd"> &quot;&quot;&quot;</span>
4599
- <a id="__codelineno-0-248" name="__codelineno-0-248"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
4600
- <a id="__codelineno-0-249" name="__codelineno-0-249"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
4601
- <a id="__codelineno-0-250" name="__codelineno-0-250"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span>
4602
- <a id="__codelineno-0-251" name="__codelineno-0-251"></a> <span class="k">else</span><span class="p">:</span>
4603
- <a id="__codelineno-0-252" name="__codelineno-0-252"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">initial_side</span>
4604
- <a id="__codelineno-0-253" name="__codelineno-0-253"></a> <span class="n">peer_side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">OPPOSITE</span><span class="p">[</span><span class="n">side</span><span class="p">]</span>
4605
- <a id="__codelineno-0-254" name="__codelineno-0-254"></a>
4606
- <a id="__codelineno-0-255" name="__codelineno-0-255"></a> <span class="c1"># If this model is on the &quot;source&quot; side of the relationship, then the field will be named</span>
4607
- <a id="__codelineno-0-256" name="__codelineno-0-256"></a> <span class="c1"># &quot;cr_&lt;relationship-slug&gt;__destination&quot; since it&#39;s used to pick the destination object(s).</span>
4608
- <a id="__codelineno-0-257" name="__codelineno-0-257"></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>
4609
- <a id="__codelineno-0-258" name="__codelineno-0-258"></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>
4610
- <a id="__codelineno-0-259" name="__codelineno-0-259"></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>
4611
- <a id="__codelineno-0-260" name="__codelineno-0-260"></a>
4612
- <a id="__codelineno-0-261" name="__codelineno-0-261"></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>
4613
- <a id="__codelineno-0-262" name="__codelineno-0-262"></a> <span class="c1"># This is a symmetric relationship that we already processed from the opposing &quot;initial_side&quot;.</span>
4614
- <a id="__codelineno-0-263" name="__codelineno-0-263"></a> <span class="c1"># No need to process it a second time!</span>
4615
- <a id="__codelineno-0-264" name="__codelineno-0-264"></a> <span class="k">continue</span>
4616
- <a id="__codelineno-0-265" name="__codelineno-0-265"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">==</span> <span class="s2">&quot;source&quot;</span><span class="p">:</span>
4617
- <a id="__codelineno-0-266" name="__codelineno-0-266"></a> <span class="n">choice_model</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="o">.</span><span class="n">model_class</span><span class="p">()</span>
4618
- <a id="__codelineno-0-267" name="__codelineno-0-267"></a> <span class="k">elif</span> <span class="n">peer_side</span> <span class="o">==</span> <span class="s2">&quot;destination&quot;</span><span class="p">:</span>
4619
- <a id="__codelineno-0-268" name="__codelineno-0-268"></a> <span class="n">choice_model</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="o">.</span><span class="n">model_class</span><span class="p">()</span>
4620
- <a id="__codelineno-0-269" name="__codelineno-0-269"></a> <span class="k">else</span><span class="p">:</span>
4621
- <a id="__codelineno-0-270" name="__codelineno-0-270"></a> <span class="n">choice_model</span> <span class="o">=</span> <span class="n">model</span>
4622
- <a id="__codelineno-0-271" name="__codelineno-0-271"></a> <span class="c1"># Check for invalid_relationship unit test</span>
4623
- <a id="__codelineno-0-272" name="__codelineno-0-272"></a> <span class="k">if</span> <span class="n">choice_model</span><span class="p">:</span>
4624
- <a id="__codelineno-0-273" name="__codelineno-0-273"></a> <span class="bp">self</span><span class="o">.</span><span class="n">filters</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">RelationshipFilter</span><span class="p">(</span>
4625
- <a id="__codelineno-0-274" name="__codelineno-0-274"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
4626
- <a id="__codelineno-0-275" name="__codelineno-0-275"></a> <span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">,</span>
4627
- <a id="__codelineno-0-276" name="__codelineno-0-276"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">field_name</span><span class="p">,</span>
4628
- <a id="__codelineno-0-277" name="__codelineno-0-277"></a> <span class="n">queryset</span><span class="o">=</span><span class="n">choice_model</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
4629
- <a id="__codelineno-0-278" name="__codelineno-0-278"></a> <span class="n">qs</span><span class="o">=</span><span class="n">model</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
4630
- <a id="__codelineno-0-279" name="__codelineno-0-279"></a> <span class="p">)</span>
4631
- <a id="__codelineno-0-280" name="__codelineno-0-280"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
5794
+ <span class="normal"><a href="#__codelineno-0-280">280</a></span>
5795
+ <span class="normal"><a href="#__codelineno-0-281">281</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-219" name="__codelineno-0-219"></a><span class="k">class</span> <span class="nc">RelationshipModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
5796
+ <a id="__codelineno-0-220" name="__codelineno-0-220"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5797
+ <a id="__codelineno-0-221" name="__codelineno-0-221"></a><span class="sd"> Filterset for relationships applicable to the parent model.</span>
5798
+ <a id="__codelineno-0-222" name="__codelineno-0-222"></a><span class="sd"> &quot;&quot;&quot;</span>
5799
+ <a id="__codelineno-0-223" name="__codelineno-0-223"></a>
5800
+ <a id="__codelineno-0-224" name="__codelineno-0-224"></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>
5801
+ <a id="__codelineno-0-225" name="__codelineno-0-225"></a> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="o">=</span> <span class="n">ContentType</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">get_for_model</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
5802
+ <a id="__codelineno-0-226" name="__codelineno-0-226"></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>
5803
+ <a id="__codelineno-0-227" name="__codelineno-0-227"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span> <span class="o">=</span> <span class="p">[]</span>
5804
+ <a id="__codelineno-0-228" name="__codelineno-0-228"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships</span><span class="p">(</span><span class="n">model</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">_meta</span><span class="o">.</span><span class="n">model</span><span class="p">)</span>
5805
+ <a id="__codelineno-0-229" name="__codelineno-0-229"></a>
5806
+ <a id="__codelineno-0-230" name="__codelineno-0-230"></a> <span class="k">def</span> <span class="nf">_append_relationships</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">model</span><span class="p">):</span>
5807
+ <a id="__codelineno-0-231" name="__codelineno-0-231"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5808
+ <a id="__codelineno-0-232" name="__codelineno-0-232"></a><span class="sd"> Append form fields for all Relationships assigned to this model.</span>
5809
+ <a id="__codelineno-0-233" name="__codelineno-0-233"></a><span class="sd"> &quot;&quot;&quot;</span>
5810
+ <a id="__codelineno-0-234" name="__codelineno-0-234"></a> <span class="n">query</span> <span class="o">=</span> <span class="n">Q</span><span class="p">(</span><span class="n">source_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">source_hidden</span><span class="o">=</span><span class="kc">False</span><span class="p">)</span> <span class="o">|</span> <span class="n">Q</span><span class="p">(</span>
5811
+ <a id="__codelineno-0-235" name="__codelineno-0-235"></a> <span class="n">destination_type</span><span class="o">=</span><span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span><span class="p">,</span> <span class="n">destination_hidden</span><span class="o">=</span><span class="kc">False</span>
5812
+ <a id="__codelineno-0-236" name="__codelineno-0-236"></a> <span class="p">)</span>
5813
+ <a id="__codelineno-0-237" name="__codelineno-0-237"></a> <span class="n">relationships</span> <span class="o">=</span> <span class="n">Relationship</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">select_related</span><span class="p">(</span><span class="s2">&quot;source_type&quot;</span><span class="p">,</span> <span class="s2">&quot;destination_type&quot;</span><span class="p">)</span><span class="o">.</span><span class="n">filter</span><span class="p">(</span><span class="n">query</span><span class="p">)</span>
5814
+ <a id="__codelineno-0-238" name="__codelineno-0-238"></a>
5815
+ <a id="__codelineno-0-239" name="__codelineno-0-239"></a> <span class="k">for</span> <span class="n">rel</span> <span class="ow">in</span> <span class="n">relationships</span><span class="o">.</span><span class="n">iterator</span><span class="p">():</span>
5816
+ <a id="__codelineno-0-240" name="__codelineno-0-240"></a> <span class="k">if</span> <span class="n">rel</span><span class="o">.</span><span class="n">source_type</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">rel</span><span class="o">.</span><span class="n">source_hidden</span><span class="p">:</span>
5817
+ <a id="__codelineno-0-241" name="__codelineno-0-241"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">([</span><span class="n">rel</span><span class="p">],</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_SOURCE</span><span class="p">,</span> <span class="n">model</span><span class="p">)</span>
5818
+ <a id="__codelineno-0-242" name="__codelineno-0-242"></a> <span class="k">if</span> <span class="n">rel</span><span class="o">.</span><span class="n">destination_type</span> <span class="o">==</span> <span class="bp">self</span><span class="o">.</span><span class="n">obj_type</span> <span class="ow">and</span> <span class="ow">not</span> <span class="n">rel</span><span class="o">.</span><span class="n">destination_hidden</span><span class="p">:</span>
5819
+ <a id="__codelineno-0-243" name="__codelineno-0-243"></a> <span class="bp">self</span><span class="o">.</span><span class="n">_append_relationships_side</span><span class="p">([</span><span class="n">rel</span><span class="p">],</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_DESTINATION</span><span class="p">,</span> <span class="n">model</span><span class="p">)</span>
5820
+ <a id="__codelineno-0-244" name="__codelineno-0-244"></a>
5821
+ <a id="__codelineno-0-245" name="__codelineno-0-245"></a> <span class="k">def</span> <span class="nf">_append_relationships_side</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">relationships</span><span class="p">,</span> <span class="n">initial_side</span><span class="p">,</span> <span class="n">model</span><span class="p">):</span>
5822
+ <a id="__codelineno-0-246" name="__codelineno-0-246"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5823
+ <a id="__codelineno-0-247" name="__codelineno-0-247"></a><span class="sd"> Helper method to _append_relationships, for processing one &quot;side&quot; of the relationships for this model.</span>
5824
+ <a id="__codelineno-0-248" name="__codelineno-0-248"></a><span class="sd"> &quot;&quot;&quot;</span>
5825
+ <a id="__codelineno-0-249" name="__codelineno-0-249"></a> <span class="k">for</span> <span class="n">relationship</span> <span class="ow">in</span> <span class="n">relationships</span><span class="p">:</span>
5826
+ <a id="__codelineno-0-250" name="__codelineno-0-250"></a> <span class="k">if</span> <span class="n">relationship</span><span class="o">.</span><span class="n">symmetric</span><span class="p">:</span>
5827
+ <a id="__codelineno-0-251" name="__codelineno-0-251"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">RelationshipSideChoices</span><span class="o">.</span><span class="n">SIDE_PEER</span>
5828
+ <a id="__codelineno-0-252" name="__codelineno-0-252"></a> <span class="k">else</span><span class="p">:</span>
5829
+ <a id="__codelineno-0-253" name="__codelineno-0-253"></a> <span class="n">side</span> <span class="o">=</span> <span class="n">initial_side</span>
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>
5831
+ <a id="__codelineno-0-255" name="__codelineno-0-255"></a>
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>
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>
5837
+ <a id="__codelineno-0-261" name="__codelineno-0-261"></a>
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>
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>
5840
+ <a id="__codelineno-0-264" name="__codelineno-0-264"></a> <span class="c1"># No need to process it a second time!</span>
5841
+ <a id="__codelineno-0-265" name="__codelineno-0-265"></a> <span class="k">continue</span>
5842
+ <a id="__codelineno-0-266" name="__codelineno-0-266"></a> <span class="k">if</span> <span class="n">peer_side</span> <span class="o">==</span> <span class="s2">&quot;source&quot;</span><span class="p">:</span>
5843
+ <a id="__codelineno-0-267" name="__codelineno-0-267"></a> <span class="n">choice_model</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">source_type</span><span class="o">.</span><span class="n">model_class</span><span class="p">()</span>
5844
+ <a id="__codelineno-0-268" name="__codelineno-0-268"></a> <span class="k">elif</span> <span class="n">peer_side</span> <span class="o">==</span> <span class="s2">&quot;destination&quot;</span><span class="p">:</span>
5845
+ <a id="__codelineno-0-269" name="__codelineno-0-269"></a> <span class="n">choice_model</span> <span class="o">=</span> <span class="n">relationship</span><span class="o">.</span><span class="n">destination_type</span><span class="o">.</span><span class="n">model_class</span><span class="p">()</span>
5846
+ <a id="__codelineno-0-270" name="__codelineno-0-270"></a> <span class="k">else</span><span class="p">:</span>
5847
+ <a id="__codelineno-0-271" name="__codelineno-0-271"></a> <span class="n">choice_model</span> <span class="o">=</span> <span class="n">model</span>
5848
+ <a id="__codelineno-0-272" name="__codelineno-0-272"></a> <span class="c1"># Check for invalid_relationship unit test</span>
5849
+ <a id="__codelineno-0-273" name="__codelineno-0-273"></a> <span class="k">if</span> <span class="n">choice_model</span><span class="p">:</span>
5850
+ <a id="__codelineno-0-274" name="__codelineno-0-274"></a> <span class="bp">self</span><span class="o">.</span><span class="n">filters</span><span class="p">[</span><span class="n">field_name</span><span class="p">]</span> <span class="o">=</span> <span class="n">RelationshipFilter</span><span class="p">(</span>
5851
+ <a id="__codelineno-0-275" name="__codelineno-0-275"></a> <span class="n">relationship</span><span class="o">=</span><span class="n">relationship</span><span class="p">,</span>
5852
+ <a id="__codelineno-0-276" name="__codelineno-0-276"></a> <span class="n">side</span><span class="o">=</span><span class="n">side</span><span class="p">,</span>
5853
+ <a id="__codelineno-0-277" name="__codelineno-0-277"></a> <span class="n">field_name</span><span class="o">=</span><span class="n">field_name</span><span class="p">,</span>
5854
+ <a id="__codelineno-0-278" name="__codelineno-0-278"></a> <span class="n">queryset</span><span class="o">=</span><span class="n">choice_model</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
5855
+ <a id="__codelineno-0-279" name="__codelineno-0-279"></a> <span class="n">qs</span><span class="o">=</span><span class="n">model</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
5856
+ <a id="__codelineno-0-280" name="__codelineno-0-280"></a> <span class="p">)</span>
5857
+ <a id="__codelineno-0-281" name="__codelineno-0-281"></a> <span class="bp">self</span><span class="o">.</span><span class="n">relationships</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">field_name</span><span class="p">)</span>
4632
5858
  </code></pre></div></td></tr></table></div>
4633
5859
  </details>
4634
5860
 
@@ -4674,21 +5900,21 @@ argument to test for the existence of related objects.</p>
4674
5900
 
4675
5901
  <details class="quote">
4676
5902
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4677
- <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>
4678
5905
  <span class="normal"><a href="#__codelineno-0-444">444</a></span>
4679
5906
  <span class="normal"><a href="#__codelineno-0-445">445</a></span>
4680
5907
  <span class="normal"><a href="#__codelineno-0-446">446</a></span>
4681
5908
  <span class="normal"><a href="#__codelineno-0-447">447</a></span>
4682
5909
  <span class="normal"><a href="#__codelineno-0-448">448</a></span>
4683
- <span class="normal"><a href="#__codelineno-0-449">449</a></span>
4684
- <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>
4685
- <a id="__codelineno-0-444" name="__codelineno-0-444"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4686
- <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>
4687
- <a id="__codelineno-0-446" name="__codelineno-0-446"></a>
4688
- <a id="__codelineno-0-447" name="__codelineno-0-447"></a><span class="sd"> See the docstring for `nautobot.core.filters.MappedPredicatesFilterMixin` for usage.</span>
4689
- <a id="__codelineno-0-448" name="__codelineno-0-448"></a><span class="sd"> &quot;&quot;&quot;</span>
4690
- <a id="__codelineno-0-449" name="__codelineno-0-449"></a>
4691
- <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>
4692
5918
  </code></pre></div></td></tr></table></div>
4693
5919
  </details>
4694
5920
 
@@ -4733,17 +5959,17 @@ argument to test for the existence of related objects.</p>
4733
5959
 
4734
5960
  <details class="quote">
4735
5961
  <summary>Source code in <code>nautobot/extras/filters/mixins.py</code></summary>
4736
- <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-340">340</a></span>
4737
- <span class="normal"><a href="#__codelineno-0-341">341</a></span>
4738
- <span class="normal"><a href="#__codelineno-0-342">342</a></span>
5962
+ <div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span></span><span class="normal"><a href="#__codelineno-0-342">342</a></span>
4739
5963
  <span class="normal"><a href="#__codelineno-0-343">343</a></span>
4740
5964
  <span class="normal"><a href="#__codelineno-0-344">344</a></span>
4741
- <span class="normal"><a href="#__codelineno-0-345">345</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-340" name="__codelineno-0-340"></a><span class="k">class</span> <span class="nc">StatusModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
4742
- <a id="__codelineno-0-341" name="__codelineno-0-341"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4743
- <a id="__codelineno-0-342" name="__codelineno-0-342"></a><span class="sd"> Mixin to add a `status` filter field to a FilterSet.</span>
4744
- <a id="__codelineno-0-343" name="__codelineno-0-343"></a><span class="sd"> &quot;&quot;&quot;</span>
4745
- <a id="__codelineno-0-344" name="__codelineno-0-344"></a>
4746
- <a id="__codelineno-0-345" name="__codelineno-0-345"></a> <span class="n">status</span> <span class="o">=</span> <span class="n">StatusFilter</span><span class="p">()</span>
5965
+ <span class="normal"><a href="#__codelineno-0-345">345</a></span>
5966
+ <span class="normal"><a href="#__codelineno-0-346">346</a></span>
5967
+ <span class="normal"><a href="#__codelineno-0-347">347</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-342" name="__codelineno-0-342"></a><span class="k">class</span> <span class="nc">StatusModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
5968
+ <a id="__codelineno-0-343" name="__codelineno-0-343"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5969
+ <a id="__codelineno-0-344" name="__codelineno-0-344"></a><span class="sd"> Mixin to add a `status` filter field to a FilterSet.</span>
5970
+ <a id="__codelineno-0-345" name="__codelineno-0-345"></a><span class="sd"> &quot;&quot;&quot;</span>
5971
+ <a id="__codelineno-0-346" name="__codelineno-0-346"></a>
5972
+ <a id="__codelineno-0-347" name="__codelineno-0-347"></a> <span class="n">status</span> <span class="o">=</span> <span class="n">StatusFilter</span><span class="p">()</span>
4747
5973
  </code></pre></div></td></tr></table></div>
4748
5974
  </details>
4749
5975
 
@@ -4806,7 +6032,8 @@ argument to test for the existence of related objects.</p>
4806
6032
  <span class="normal"><a href="#__codelineno-0-22">22</a></span>
4807
6033
  <span class="normal"><a href="#__codelineno-0-23">23</a></span>
4808
6034
  <span class="normal"><a href="#__codelineno-0-24">24</a></span>
4809
- <span class="normal"><a href="#__codelineno-0-25">25</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="k">class</span> <span class="nc">TenancyModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
6035
+ <span class="normal"><a href="#__codelineno-0-25">25</a></span>
6036
+ <span class="normal"><a href="#__codelineno-0-26">26</a></span></pre></div></td><td class="code"><div><pre><span></span><code><a id="__codelineno-0-7" name="__codelineno-0-7"></a><span class="k">class</span> <span class="nc">TenancyModelFilterSetMixin</span><span class="p">(</span><span class="n">django_filters</span><span class="o">.</span><span class="n">FilterSet</span><span class="p">):</span>
4810
6037
  <a id="__codelineno-0-8" name="__codelineno-0-8"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4811
6038
  <a id="__codelineno-0-9" name="__codelineno-0-9"></a><span class="sd"> An inheritable FilterSet for models which support Tenant assignment.</span>
4812
6039
  <a id="__codelineno-0-10" name="__codelineno-0-10"></a><span class="sd"> &quot;&quot;&quot;</span>
@@ -4814,7 +6041,7 @@ argument to test for the existence of related objects.</p>
4814
6041
  <a id="__codelineno-0-12" name="__codelineno-0-12"></a> <span class="n">tenant_group</span> <span class="o">=</span> <span class="n">TreeNodeMultipleChoiceFilter</span><span class="p">(</span>
4815
6042
  <a id="__codelineno-0-13" name="__codelineno-0-13"></a> <span class="n">queryset</span><span class="o">=</span><span class="n">TenantGroup</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
4816
6043
  <a id="__codelineno-0-14" name="__codelineno-0-14"></a> <span class="n">field_name</span><span class="o">=</span><span class="s2">&quot;tenant__tenant_group&quot;</span><span class="p">,</span>
4817
- <a id="__codelineno-0-15" name="__codelineno-0-15"></a> <span class="n">to_field_name</span><span class="o">=</span><span class="s2">&quot;slug&quot;</span><span class="p">,</span>
6044
+ <a id="__codelineno-0-15" name="__codelineno-0-15"></a> <span class="n">to_field_name</span><span class="o">=</span><span class="s2">&quot;name&quot;</span><span class="p">,</span>
4818
6045
  <a id="__codelineno-0-16" name="__codelineno-0-16"></a> <span class="n">label</span><span class="o">=</span><span class="s2">&quot;Tenant Group (slug or ID)&quot;</span><span class="p">,</span>
4819
6046
  <a id="__codelineno-0-17" name="__codelineno-0-17"></a> <span class="p">)</span>
4820
6047
  <a id="__codelineno-0-18" name="__codelineno-0-18"></a> <span class="n">tenant_id</span> <span class="o">=</span> <span class="n">django_filters</span><span class="o">.</span><span class="n">ModelMultipleChoiceFilter</span><span class="p">(</span>
@@ -4823,8 +6050,9 @@ argument to test for the existence of related objects.</p>
4823
6050
  <a id="__codelineno-0-21" name="__codelineno-0-21"></a> <span class="p">)</span>
4824
6051
  <a id="__codelineno-0-22" name="__codelineno-0-22"></a> <span class="n">tenant</span> <span class="o">=</span> <span class="n">NaturalKeyOrPKMultipleChoiceFilter</span><span class="p">(</span>
4825
6052
  <a id="__codelineno-0-23" name="__codelineno-0-23"></a> <span class="n">queryset</span><span class="o">=</span><span class="n">Tenant</span><span class="o">.</span><span class="n">objects</span><span class="o">.</span><span class="n">all</span><span class="p">(),</span>
4826
- <a id="__codelineno-0-24" name="__codelineno-0-24"></a> <span class="n">label</span><span class="o">=</span><span class="s2">&quot;Tenant (slug or ID)&quot;</span><span class="p">,</span>
4827
- <a id="__codelineno-0-25" name="__codelineno-0-25"></a> <span class="p">)</span>
6053
+ <a id="__codelineno-0-24" name="__codelineno-0-24"></a> <span class="n">to_field_name</span><span class="o">=</span><span class="s2">&quot;name&quot;</span><span class="p">,</span>
6054
+ <a id="__codelineno-0-25" name="__codelineno-0-25"></a> <span class="n">label</span><span class="o">=</span><span class="s2">&quot;Tenant (name or ID)&quot;</span><span class="p">,</span>
6055
+ <a id="__codelineno-0-26" name="__codelineno-0-26"></a> <span class="p">)</span>
4828
6056
  </code></pre></div></td></tr></table></div>
4829
6057
  </details>
4830
6058
 
@@ -4879,7 +6107,8 @@ would match both "Athens" and "Durham".</p>
4879
6107
 
4880
6108
  <details class="quote">
4881
6109
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
4882
- <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>
4883
6112
  <span class="normal"><a href="#__codelineno-0-470">470</a></span>
4884
6113
  <span class="normal"><a href="#__codelineno-0-471">471</a></span>
4885
6114
  <span class="normal"><a href="#__codelineno-0-472">472</a></span>
@@ -4933,63 +6162,62 @@ would match both "Athens" and "Durham".</p>
4933
6162
  <span class="normal"><a href="#__codelineno-0-520">520</a></span>
4934
6163
  <span class="normal"><a href="#__codelineno-0-521">521</a></span>
4935
6164
  <span class="normal"><a href="#__codelineno-0-522">522</a></span>
4936
- <span class="normal"><a href="#__codelineno-0-523">523</a></span>
4937
- <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>
4938
- <a id="__codelineno-0-470" name="__codelineno-0-470"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4939
- <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>
4940
- <a id="__codelineno-0-472" name="__codelineno-0-472"></a>
4941
- <a id="__codelineno-0-473" name="__codelineno-0-473"></a><span class="sd"> For example, if we have:</span>
4942
- <a id="__codelineno-0-474" name="__codelineno-0-474"></a>
4943
- <a id="__codelineno-0-475" name="__codelineno-0-475"></a><span class="sd"> Region &quot;Earth&quot;</span>
4944
- <a id="__codelineno-0-476" name="__codelineno-0-476"></a><span class="sd"> Region &quot;USA&quot;</span>
4945
- <a id="__codelineno-0-477" name="__codelineno-0-477"></a><span class="sd"> Region &quot;GA&quot; &lt;- Site &quot;Athens&quot;</span>
4946
- <a id="__codelineno-0-478" name="__codelineno-0-478"></a><span class="sd"> Region &quot;NC&quot; &lt;- Site &quot;Durham&quot;</span>
4947
- <a id="__codelineno-0-479" name="__codelineno-0-479"></a>
4948
- <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>
4949
- <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>
4950
- <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>
4951
- <a id="__codelineno-0-483" name="__codelineno-0-483"></a><span class="sd"> would match both &quot;Athens&quot; and &quot;Durham&quot;.</span>
4952
- <a id="__codelineno-0-484" name="__codelineno-0-484"></a><span class="sd"> &quot;&quot;&quot;</span>
4953
- <a id="__codelineno-0-485" name="__codelineno-0-485"></a>
4954
- <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>
4955
- <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>
4956
- <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>
4957
- <a id="__codelineno-0-489" name="__codelineno-0-489"></a>
4958
- <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>
4959
- <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
4960
- <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>
4961
- <a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> &quot;&quot;&quot;</span>
4962
- <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
4963
- <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="c1"># django-tree-queries</span>
4964
- <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>
4965
- <a id="__codelineno-0-497" name="__codelineno-0-497"></a>
4966
- <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>
4967
- <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>
4968
- <a id="__codelineno-0-500" name="__codelineno-0-500"></a>
4969
- <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>
4970
- <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="n">predicates</span> <span class="o">=</span> <span class="p">[]</span>
4971
- <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>
4972
- <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>
4973
- <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>
4974
- <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>
4975
- <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="n">val</span> <span class="o">=</span> <span class="kc">None</span>
4976
- <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>
4977
- <a id="__codelineno-0-509" name="__codelineno-0-509"></a>
4978
- <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>
4979
- <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="c1"># listed of descendant objects.</span>
4980
- <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>
4981
- <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>
4982
- <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>
4983
- <a id="__codelineno-0-515" name="__codelineno-0-515"></a>
4984
- <a id="__codelineno-0-516" name="__codelineno-0-516"></a> <span class="k">return</span> <span class="n">query</span>
4985
- <a id="__codelineno-0-517" name="__codelineno-0-517"></a>
4986
- <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>
4987
- <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>
4988
- <a id="__codelineno-0-520" name="__codelineno-0-520"></a> <span class="k">return</span> <span class="n">qs</span>
4989
- <a id="__codelineno-0-521" name="__codelineno-0-521"></a>
4990
- <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>
4991
- <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>
4992
- <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>
4993
6221
  </code></pre></div></td></tr></table></div>
4994
6222
  </details>
4995
6223
 
@@ -5021,7 +6249,8 @@ would match both "Athens" and "Durham".</p>
5021
6249
 
5022
6250
  <details class="quote">
5023
6251
  <summary>Source code in <code>nautobot/core/filters.py</code></summary>
5024
- <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>
5025
6254
  <span class="normal"><a href="#__codelineno-0-491">491</a></span>
5026
6255
  <span class="normal"><a href="#__codelineno-0-492">492</a></span>
5027
6256
  <span class="normal"><a href="#__codelineno-0-493">493</a></span>
@@ -5046,34 +6275,33 @@ would match both "Athens" and "Durham".</p>
5046
6275
  <span class="normal"><a href="#__codelineno-0-512">512</a></span>
5047
6276
  <span class="normal"><a href="#__codelineno-0-513">513</a></span>
5048
6277
  <span class="normal"><a href="#__codelineno-0-514">514</a></span>
5049
- <span class="normal"><a href="#__codelineno-0-515">515</a></span>
5050
- <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>
5051
- <a id="__codelineno-0-491" name="__codelineno-0-491"></a><span class="w"> </span><span class="sd">&quot;&quot;&quot;</span>
5052
- <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>
5053
- <a id="__codelineno-0-493" name="__codelineno-0-493"></a><span class="sd"> &quot;&quot;&quot;</span>
5054
- <a id="__codelineno-0-494" name="__codelineno-0-494"></a> <span class="k">if</span> <span class="n">value</span><span class="p">:</span>
5055
- <a id="__codelineno-0-495" name="__codelineno-0-495"></a> <span class="c1"># django-tree-queries</span>
5056
- <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>
5057
- <a id="__codelineno-0-497" name="__codelineno-0-497"></a>
5058
- <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>
5059
- <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>
5060
- <a id="__codelineno-0-500" name="__codelineno-0-500"></a>
5061
- <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>
5062
- <a id="__codelineno-0-502" name="__codelineno-0-502"></a> <span class="n">predicates</span> <span class="o">=</span> <span class="p">[]</span>
5063
- <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>
5064
- <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>
5065
- <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>
5066
- <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>
5067
- <a id="__codelineno-0-507" name="__codelineno-0-507"></a> <span class="n">val</span> <span class="o">=</span> <span class="kc">None</span>
5068
- <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>
5069
- <a id="__codelineno-0-509" name="__codelineno-0-509"></a>
5070
- <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>
5071
- <a id="__codelineno-0-511" name="__codelineno-0-511"></a> <span class="c1"># listed of descendant objects.</span>
5072
- <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>
5073
- <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>
5074
- <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>
5075
- <a id="__codelineno-0-515" name="__codelineno-0-515"></a>
5076
- <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>
5077
6305
  </code></pre></div></td></tr></table></div>
5078
6306
  </details>
5079
6307
  </div>
@@ -5112,42 +6340,6 @@ would match both "Athens" and "Durham".</p>
5112
6340
 
5113
6341
  <footer class="md-footer">
5114
6342
 
5115
-
5116
- <nav class="md-footer__inner md-grid" aria-label="Footer" >
5117
-
5118
-
5119
- <a href="datasources.html" class="md-footer__link md-footer__link--prev" aria-label="Previous: nautobot.apps.datasources" rel="prev">
5120
- <div class="md-footer__button md-icon">
5121
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M20 11v2H8l5.5 5.5-1.42 1.42L4.16 12l7.92-7.92L13.5 5.5 8 11h12Z"/></svg>
5122
- </div>
5123
- <div class="md-footer__title">
5124
- <div class="md-ellipsis">
5125
- <span class="md-footer__direction">
5126
- Previous
5127
- </span>
5128
- nautobot.apps.datasources
5129
- </div>
5130
- </div>
5131
- </a>
5132
-
5133
-
5134
-
5135
- <a href="forms.html" class="md-footer__link md-footer__link--next" aria-label="Next: nautobot.apps.forms" rel="next">
5136
- <div class="md-footer__title">
5137
- <div class="md-ellipsis">
5138
- <span class="md-footer__direction">
5139
- Next
5140
- </span>
5141
- nautobot.apps.forms
5142
- </div>
5143
- </div>
5144
- <div class="md-footer__button md-icon">
5145
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><path d="M4 11v2h12l-5.5 5.5 1.42 1.42L19.84 12l-7.92-7.92L10.5 5.5 16 11H4Z"/></svg>
5146
- </div>
5147
- </a>
5148
-
5149
- </nav>
5150
-
5151
6343
  <div class="md-footer-meta md-typeset">
5152
6344
  <div class="md-footer-meta__inner md-grid">
5153
6345
  <div class="md-copyright">
@@ -5175,32 +6367,42 @@ would match both "Athens" and "Durham".</p>
5175
6367
 
5176
6368
 
5177
6369
 
6370
+
6371
+
5178
6372
  <a href="https://blog.networktocode.com/blog/tags/nautobot" target="_blank" rel="noopener" title="Network to Code Blog" class="md-social__link">
5179
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M0 64c0-17.7 14.3-32 32-32 229.8 0 416 186.2 416 416 0 17.7-14.3 32-32 32s-32-14.3-32-32C384 253.6 226.4 96 32 96 14.3 96 0 81.7 0 64zm128 352c0 35.3-28.7 64-64 64S0 451.3 0 416s28.7-64 64-64 64 28.7 64 64zM32 160c159.1 0 288 128.9 288 288 0 17.7-14.3 32-32 32s-32-14.3-32-32c0-123.7-100.3-224-224-224-17.7 0-32-14.3-32-32s14.3-32 32-32z"/></svg>
6373
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M0 64c0-17.7 14.3-32 32-32 229.8 0 416 186.2 416 416 0 17.7-14.3 32-32 32s-32-14.3-32-32C384 253.6 226.4 96 32 96 14.3 96 0 81.7 0 64zm0 352a64 64 0 1 1 128 0 64 64 0 1 1-128 0zm32-256c159.1 0 288 128.9 288 288 0 17.7-14.3 32-32 32s-32-14.3-32-32c0-123.7-100.3-224-224-224-17.7 0-32-14.3-32-32s14.3-32 32-32z"/></svg>
5180
6374
  </a>
5181
6375
 
5182
6376
 
5183
6377
 
6378
+
6379
+
5184
6380
  <a href="https://www.youtube.com/playlist?list=PLjA0bhxgryJ2Ts4GJMDA-tPzVWEncv4pb" target="_blank" rel="noopener" title="Nautobot Videos" class="md-social__link">
5185
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"/></svg>
6381
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 576 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M549.655 124.083c-6.281-23.65-24.787-42.276-48.284-48.597C458.781 64 288 64 288 64S117.22 64 74.629 75.486c-23.497 6.322-42.003 24.947-48.284 48.597-11.412 42.867-11.412 132.305-11.412 132.305s0 89.438 11.412 132.305c6.281 23.65 24.787 41.5 48.284 47.821C117.22 448 288 448 288 448s170.78 0 213.371-11.486c23.497-6.321 42.003-24.171 48.284-47.821 11.412-42.867 11.412-132.305 11.412-132.305s0-89.438-11.412-132.305zm-317.51 213.508V175.185l142.739 81.205-142.739 81.201z"/></svg>
5186
6382
  </a>
5187
6383
 
5188
6384
 
5189
6385
 
6386
+
6387
+
5190
6388
  <a href="https://www.networktocode.com/community/" target="_blank" rel="noopener" title="Network to Code Community" class="md-social__link">
5191
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M94.12 315.1c0 25.9-21.16 47.06-47.06 47.06S0 341 0 315.1c0-25.9 21.16-47.06 47.06-47.06h47.06v47.06zm23.72 0c0-25.9 21.16-47.06 47.06-47.06s47.06 21.16 47.06 47.06v117.84c0 25.9-21.16 47.06-47.06 47.06s-47.06-21.16-47.06-47.06V315.1zm47.06-188.98c-25.9 0-47.06-21.16-47.06-47.06S139 32 164.9 32s47.06 21.16 47.06 47.06v47.06H164.9zm0 23.72c25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06H47.06C21.16 243.96 0 222.8 0 196.9s21.16-47.06 47.06-47.06H164.9zm188.98 47.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06h-47.06V196.9zm-23.72 0c0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06V79.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06V196.9zM283.1 385.88c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06v-47.06h47.06zm0-23.72c-25.9 0-47.06-21.16-47.06-47.06 0-25.9 21.16-47.06 47.06-47.06h117.84c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06H283.1z"/></svg>
6389
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M94.12 315.1c0 25.9-21.16 47.06-47.06 47.06S0 341 0 315.1c0-25.9 21.16-47.06 47.06-47.06h47.06v47.06zm23.72 0c0-25.9 21.16-47.06 47.06-47.06s47.06 21.16 47.06 47.06v117.84c0 25.9-21.16 47.06-47.06 47.06s-47.06-21.16-47.06-47.06V315.1zm47.06-188.98c-25.9 0-47.06-21.16-47.06-47.06S139 32 164.9 32s47.06 21.16 47.06 47.06v47.06H164.9zm0 23.72c25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06H47.06C21.16 243.96 0 222.8 0 196.9s21.16-47.06 47.06-47.06H164.9zm188.98 47.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06s-21.16 47.06-47.06 47.06h-47.06V196.9zm-23.72 0c0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06V79.06c0-25.9 21.16-47.06 47.06-47.06 25.9 0 47.06 21.16 47.06 47.06V196.9zM283.1 385.88c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06-25.9 0-47.06-21.16-47.06-47.06v-47.06h47.06zm0-23.72c-25.9 0-47.06-21.16-47.06-47.06 0-25.9 21.16-47.06 47.06-47.06h117.84c25.9 0 47.06 21.16 47.06 47.06 0 25.9-21.16 47.06-47.06 47.06H283.1z"/></svg>
5192
6390
  </a>
5193
6391
 
5194
6392
 
5195
6393
 
6394
+
6395
+
5196
6396
  <a href="https://github.com/nautobot/nautobot" target="_blank" rel="noopener" title="GitHub Repo" class="md-social__link">
5197
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
6397
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 496 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M165.9 397.4c0 2-2.3 3.6-5.2 3.6-3.3.3-5.6-1.3-5.6-3.6 0-2 2.3-3.6 5.2-3.6 3-.3 5.6 1.3 5.6 3.6zm-31.1-4.5c-.7 2 1.3 4.3 4.3 4.9 2.6 1 5.6 0 6.2-2s-1.3-4.3-4.3-5.2c-2.6-.7-5.5.3-6.2 2.3zm44.2-1.7c-2.9.7-4.9 2.6-4.6 4.9.3 2 2.9 3.3 5.9 2.6 2.9-.7 4.9-2.6 4.6-4.6-.3-1.9-3-3.2-5.9-2.9zM244.8 8C106.1 8 0 113.3 0 252c0 110.9 69.8 205.8 169.5 239.2 12.8 2.3 17.3-5.6 17.3-12.1 0-6.2-.3-40.4-.3-61.4 0 0-70 15-84.7-29.8 0 0-11.4-29.1-27.8-36.6 0 0-22.9-15.7 1.6-15.4 0 0 24.9 2 38.6 25.8 21.9 38.6 58.6 27.5 72.9 20.9 2.3-16 8.8-27.1 16-33.7-55.9-6.2-112.3-14.3-112.3-110.5 0-27.5 7.6-41.3 23.6-58.9-2.6-6.5-11.1-33.3 2.6-67.9 20.9-6.5 69 27 69 27 20-5.6 41.5-8.5 62.8-8.5s42.8 2.9 62.8 8.5c0 0 48.1-33.6 69-27 13.7 34.7 5.2 61.4 2.6 67.9 16 17.7 25.8 31.5 25.8 58.9 0 96.5-58.9 104.2-114.8 110.5 9.2 7.9 17 22.9 17 46.4 0 33.7-.3 75.4-.3 83.6 0 6.5 4.6 14.4 17.3 12.1C428.2 457.8 496 362.9 496 252 496 113.3 383.5 8 244.8 8zM97.2 352.9c-1.3 1-1 3.3.7 5.2 1.6 1.6 3.9 2.3 5.2 1 1.3-1 1-3.3-.7-5.2-1.6-1.6-3.9-2.3-5.2-1zm-10.8-8.1c-.7 1.3.3 2.9 2.3 3.9 1.6 1 3.6.7 4.3-.7.7-1.3-.3-2.9-2.3-3.9-2-.6-3.6-.3-4.3.7zm32.4 35.6c-1.6 1.3-1 4.3 1.3 6.2 2.3 2.3 5.2 2.6 6.5 1 1.3-1.3.7-4.3-1.3-6.2-2.2-2.3-5.2-2.6-6.5-1zm-11.4-14.7c-1.6 1-1.6 3.6 0 5.9 1.6 2.3 4.3 3.3 5.6 2.3 1.6-1.3 1.6-3.9 0-6.2-1.4-2.3-4-3.3-5.6-2z"/></svg>
5198
6398
  </a>
5199
6399
 
5200
6400
 
5201
6401
 
6402
+
6403
+
5202
6404
  <a href="https://twitter.com/networktocode" target="_blank" rel="noopener" title="Network to Code Twitter" class="md-social__link">
5203
- <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.2.1 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2022 Fonticons, Inc.--><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
6405
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><!--! Font Awesome Free 6.4.0 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free (Icons: CC BY 4.0, Fonts: SIL OFL 1.1, Code: MIT License) Copyright 2023 Fonticons, Inc.--><path d="M459.37 151.716c.325 4.548.325 9.097.325 13.645 0 138.72-105.583 298.558-298.558 298.558-59.452 0-114.68-17.219-161.137-47.106 8.447.974 16.568 1.299 25.34 1.299 49.055 0 94.213-16.568 130.274-44.832-46.132-.975-84.792-31.188-98.112-72.772 6.498.974 12.995 1.624 19.818 1.624 9.421 0 18.843-1.3 27.614-3.573-48.081-9.747-84.143-51.98-84.143-102.985v-1.299c13.969 7.797 30.214 12.67 47.431 13.319-28.264-18.843-46.781-51.005-46.781-87.391 0-19.492 5.197-37.36 14.294-52.954 51.655 63.675 129.3 105.258 216.365 109.807-1.624-7.797-2.599-15.918-2.599-24.04 0-57.828 46.782-104.934 104.934-104.934 30.213 0 57.502 12.67 76.67 33.137 23.715-4.548 46.456-13.32 66.599-25.34-7.798 24.366-24.366 44.833-46.132 57.827 21.117-2.273 41.584-8.122 60.426-16.243-14.292 20.791-32.161 39.308-52.628 54.253z"/></svg>
5204
6406
  </a>
5205
6407
 
5206
6408
  </div>
@@ -5214,14 +6416,13 @@ would match both "Athens" and "Durham".</p>
5214
6416
  <div class="md-dialog__inner md-typeset"></div>
5215
6417
  </div>
5216
6418
 
5217
- <script id="__config" type="application/json">{"base": "../../..", "features": ["navigation.tracking", "navigation.tabs", "navigation.tabs.sticky", "search.suggest", "search.highlight", "search.share"], "search": "../../../assets/javascripts/workers/search.16e2a7d4.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.config.lang": "en", "search.config.pipeline": "trimmer, stopWordFilter", "search.config.separator": "[\\s\\-]+", "search.placeholder": "Search", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version.title": "Select version"}}</script>
6419
+ <script id="__config" type="application/json">{"base": "../../..", "features": ["navigation.tracking", "navigation.tabs", "navigation.tabs.sticky", "search.suggest", "search.highlight", "search.share"], "search": "../../../assets/javascripts/workers/search.208ed371.min.js", "translations": {"clipboard.copied": "Copied to clipboard", "clipboard.copy": "Copy to clipboard", "search.result.more.one": "1 more on this page", "search.result.more.other": "# more on this page", "search.result.none": "No matching documents", "search.result.one": "1 matching document", "search.result.other": "# matching documents", "search.result.placeholder": "Type to start searching", "search.result.term.missing": "Missing", "select.version": "Select version"}}</script>
5218
6420
 
5219
6421
 
5220
- <script src="../../../assets/javascripts/bundle.5a2dcb6a.min.js"></script>
6422
+ <script src="../../../assets/javascripts/bundle.51198bba.min.js"></script>
5221
6423
 
5222
6424
  <script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
5223
6425
 
5224
6426
 
5225
-
5226
6427
  </body>
5227
6428
  </html>