nautobot 2.4.0b1__py3-none-any.whl → 2.4.1__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.

Potentially problematic release.


This version of nautobot might be problematic. Click here for more details.

Files changed (601) hide show
  1. nautobot/apps/__init__.py +1 -1
  2. nautobot/apps/api.py +8 -8
  3. nautobot/apps/change_logging.py +2 -2
  4. nautobot/apps/choices.py +4 -4
  5. nautobot/apps/events.py +3 -3
  6. nautobot/apps/factory.py +2 -2
  7. nautobot/apps/filters.py +1 -1
  8. nautobot/apps/forms.py +20 -20
  9. nautobot/apps/graphql.py +2 -2
  10. nautobot/apps/jobs.py +8 -8
  11. nautobot/apps/models.py +19 -19
  12. nautobot/apps/tables.py +1 -1
  13. nautobot/apps/testing.py +10 -10
  14. nautobot/apps/ui.py +2 -2
  15. nautobot/apps/utils.py +7 -7
  16. nautobot/apps/views.py +7 -7
  17. nautobot/circuits/api/serializers.py +1 -0
  18. nautobot/circuits/api/views.py +4 -8
  19. nautobot/circuits/tables.py +2 -1
  20. nautobot/circuits/templates/circuits/circuit_create.html +1 -7
  21. nautobot/circuits/views.py +3 -3
  22. nautobot/cloud/api/views.py +6 -10
  23. nautobot/cloud/models.py +1 -1
  24. nautobot/cloud/views.py +0 -16
  25. nautobot/core/api/constants.py +11 -0
  26. nautobot/core/api/fields.py +5 -5
  27. nautobot/core/api/filter_backends.py +3 -9
  28. nautobot/core/api/schema.py +13 -2
  29. nautobot/core/api/serializers.py +40 -34
  30. nautobot/core/api/views.py +56 -4
  31. nautobot/core/celery/log.py +4 -4
  32. nautobot/core/celery/schedulers.py +2 -2
  33. nautobot/core/choices.py +2 -2
  34. nautobot/core/events/__init__.py +3 -3
  35. nautobot/core/filters.py +67 -35
  36. nautobot/core/forms/__init__.py +19 -19
  37. nautobot/core/forms/fields.py +14 -11
  38. nautobot/core/forms/forms.py +33 -2
  39. nautobot/core/graphql/types.py +1 -1
  40. nautobot/core/jobs/__init__.py +28 -7
  41. nautobot/core/jobs/bulk_actions.py +285 -0
  42. nautobot/core/jobs/cleanup.py +48 -12
  43. nautobot/core/jobs/groups.py +1 -1
  44. nautobot/core/management/commands/validate_models.py +1 -1
  45. nautobot/core/models/__init__.py +3 -1
  46. nautobot/core/models/query_functions.py +2 -2
  47. nautobot/core/models/tree_queries.py +6 -3
  48. nautobot/core/settings.py +29 -2
  49. nautobot/core/settings.yaml +21 -0
  50. nautobot/core/tables.py +79 -61
  51. nautobot/core/templates/about.html +67 -0
  52. nautobot/core/templates/inc/media.html +3 -0
  53. nautobot/core/templates/inc/nav_menu.html +1 -0
  54. nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
  55. nautobot/core/templates/inc/tenant_table_row.html +11 -0
  56. nautobot/core/templates/nautobot_config.py.j2 +13 -0
  57. nautobot/core/templates/search.html +7 -0
  58. nautobot/core/templates/utilities/render_jinja2.html +1 -1
  59. nautobot/core/templates/utilities/templatetags/tag.html +1 -1
  60. nautobot/core/templates/utilities/theme_preview.html +7 -0
  61. nautobot/core/templatetags/helpers.py +11 -2
  62. nautobot/core/testing/__init__.py +8 -8
  63. nautobot/core/testing/api.py +170 -15
  64. nautobot/core/testing/filters.py +45 -10
  65. nautobot/core/testing/forms.py +2 -0
  66. nautobot/core/testing/integration.py +86 -4
  67. nautobot/core/testing/mixins.py +7 -2
  68. nautobot/core/testing/views.py +44 -29
  69. nautobot/core/tests/integration/test_app_home.py +0 -1
  70. nautobot/core/tests/integration/test_app_navbar.py +0 -1
  71. nautobot/core/tests/integration/test_filters.py +0 -2
  72. nautobot/core/tests/integration/test_home.py +0 -1
  73. nautobot/core/tests/integration/test_navbar.py +0 -1
  74. nautobot/core/tests/integration/test_view_authentication.py +1 -0
  75. nautobot/core/tests/runner.py +1 -1
  76. nautobot/core/tests/test_api.py +98 -1
  77. nautobot/core/tests/test_csv.py +25 -3
  78. nautobot/core/tests/test_filters.py +209 -246
  79. nautobot/core/tests/test_forms.py +1 -0
  80. nautobot/core/tests/test_jobs.py +460 -1
  81. nautobot/core/tests/test_models.py +9 -0
  82. nautobot/core/tests/test_settings_schema.py +7 -0
  83. nautobot/core/tests/test_tables.py +100 -0
  84. nautobot/core/tests/test_utils.py +63 -1
  85. nautobot/core/tests/test_views.py +30 -3
  86. nautobot/core/ui/nav.py +1 -0
  87. nautobot/core/ui/object_detail.py +15 -1
  88. nautobot/core/urls.py +11 -0
  89. nautobot/core/utils/lookup.py +11 -8
  90. nautobot/core/utils/querysets.py +64 -0
  91. nautobot/core/utils/requests.py +24 -9
  92. nautobot/core/views/__init__.py +42 -0
  93. nautobot/core/views/generic.py +131 -197
  94. nautobot/core/views/mixins.py +126 -38
  95. nautobot/core/views/renderers.py +6 -6
  96. nautobot/dcim/api/serializers.py +56 -64
  97. nautobot/dcim/api/views.py +47 -113
  98. nautobot/dcim/constants.py +6 -13
  99. nautobot/dcim/factory.py +6 -1
  100. nautobot/dcim/filters/__init__.py +31 -2
  101. nautobot/dcim/forms.py +36 -17
  102. nautobot/dcim/graphql/types.py +2 -2
  103. nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
  104. nautobot/dcim/models/__init__.py +1 -1
  105. nautobot/dcim/models/device_component_templates.py +2 -2
  106. nautobot/dcim/models/device_components.py +22 -20
  107. nautobot/dcim/models/devices.py +10 -1
  108. nautobot/dcim/models/locations.py +3 -3
  109. nautobot/dcim/models/power.py +6 -5
  110. nautobot/dcim/models/racks.py +4 -4
  111. nautobot/dcim/tables/__init__.py +3 -3
  112. nautobot/dcim/tables/devices.py +7 -5
  113. nautobot/dcim/tables/devicetypes.py +2 -2
  114. nautobot/dcim/tables/racks.py +1 -1
  115. nautobot/dcim/templates/dcim/controller_create.html +1 -7
  116. nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
  117. nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
  118. nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
  119. nautobot/dcim/templates/dcim/device.html +1 -9
  120. nautobot/dcim/templates/dcim/device_edit.html +36 -37
  121. nautobot/dcim/templates/dcim/location.html +1 -9
  122. nautobot/dcim/templates/dcim/location_edit.html +1 -7
  123. nautobot/dcim/templates/dcim/rack.html +1 -9
  124. nautobot/dcim/templates/dcim/rack_edit.html +1 -7
  125. nautobot/dcim/templates/dcim/rackreservation.html +1 -9
  126. nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
  127. nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
  128. nautobot/dcim/tests/integration/test_controller.py +62 -0
  129. nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
  130. nautobot/dcim/tests/integration/test_device_bulk_delete.py +189 -0
  131. nautobot/dcim/tests/integration/test_device_bulk_edit.py +181 -0
  132. nautobot/dcim/tests/test_api.py +16 -5
  133. nautobot/dcim/tests/test_filters.py +33 -0
  134. nautobot/dcim/tests/test_forms.py +51 -2
  135. nautobot/dcim/tests/test_graphql.py +52 -0
  136. nautobot/dcim/tests/test_jobs.py +118 -0
  137. nautobot/dcim/tests/test_models.py +52 -9
  138. nautobot/dcim/tests/test_views.py +21 -83
  139. nautobot/dcim/views.py +1 -13
  140. nautobot/extras/api/customfields.py +2 -2
  141. nautobot/extras/api/serializers.py +90 -85
  142. nautobot/extras/api/views.py +22 -27
  143. nautobot/extras/constants.py +2 -0
  144. nautobot/extras/filters/__init__.py +8 -6
  145. nautobot/extras/forms/base.py +2 -2
  146. nautobot/extras/forms/forms.py +139 -31
  147. nautobot/extras/forms/mixins.py +14 -6
  148. nautobot/extras/group_sync.py +3 -3
  149. nautobot/extras/health_checks.py +1 -2
  150. nautobot/extras/jobs.py +85 -18
  151. nautobot/extras/managers.py +3 -1
  152. nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
  153. nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
  154. nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
  155. nautobot/extras/models/__init__.py +1 -1
  156. nautobot/extras/models/contacts.py +1 -1
  157. nautobot/extras/models/customfields.py +12 -11
  158. nautobot/extras/models/groups.py +11 -9
  159. nautobot/extras/models/jobs.py +23 -4
  160. nautobot/extras/models/models.py +2 -2
  161. nautobot/extras/plugins/__init__.py +13 -2
  162. nautobot/extras/plugins/marketplace_manifest.yml +84 -79
  163. nautobot/extras/plugins/tables.py +16 -14
  164. nautobot/extras/plugins/views.py +65 -69
  165. nautobot/extras/registry.py +1 -1
  166. nautobot/extras/secrets/__init__.py +2 -2
  167. nautobot/extras/tables.py +7 -5
  168. nautobot/extras/templates/extras/dynamicgroup.html +1 -9
  169. nautobot/extras/templates/extras/job_detail.html +16 -0
  170. nautobot/extras/templates/extras/job_edit.html +1 -0
  171. nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
  172. nautobot/extras/templates/extras/marketplace.html +29 -11
  173. nautobot/extras/templates/extras/plugin_detail.html +32 -15
  174. nautobot/extras/templates/extras/plugins_tiles.html +21 -10
  175. nautobot/extras/templatetags/job_buttons.py +4 -4
  176. nautobot/extras/test_jobs/api_test_job.py +1 -1
  177. nautobot/extras/test_jobs/atomic_transaction.py +2 -2
  178. nautobot/extras/test_jobs/dry_run.py +1 -1
  179. nautobot/extras/test_jobs/fail.py +5 -5
  180. nautobot/extras/test_jobs/file_output.py +1 -1
  181. nautobot/extras/test_jobs/file_upload_fail.py +1 -1
  182. nautobot/extras/test_jobs/file_upload_pass.py +1 -1
  183. nautobot/extras/test_jobs/ipaddress_vars.py +3 -1
  184. nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
  185. nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
  186. nautobot/extras/test_jobs/log_redaction.py +1 -1
  187. nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
  188. nautobot/extras/test_jobs/modify_db.py +1 -1
  189. nautobot/extras/test_jobs/object_var_optional.py +1 -1
  190. nautobot/extras/test_jobs/object_var_required.py +1 -1
  191. nautobot/extras/test_jobs/object_vars.py +1 -1
  192. nautobot/extras/test_jobs/pass.py +3 -3
  193. nautobot/extras/test_jobs/profiling.py +1 -1
  194. nautobot/extras/test_jobs/relative_import.py +3 -3
  195. nautobot/extras/test_jobs/singleton.py +16 -0
  196. nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
  197. nautobot/extras/test_jobs/task_queues.py +1 -1
  198. nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
  199. nautobot/extras/tests/test_api.py +13 -13
  200. nautobot/extras/tests/test_customfields.py +1 -1
  201. nautobot/extras/tests/test_datasources.py +2 -1
  202. nautobot/extras/tests/test_dynamicgroups.py +1 -1
  203. nautobot/extras/tests/test_filters.py +6 -6
  204. nautobot/extras/tests/test_forms.py +33 -1
  205. nautobot/extras/tests/test_jobs.py +178 -32
  206. nautobot/extras/tests/test_models.py +16 -10
  207. nautobot/extras/tests/test_plugins.py +62 -9
  208. nautobot/extras/tests/test_relationships.py +120 -9
  209. nautobot/extras/tests/test_views.py +56 -194
  210. nautobot/extras/utils.py +3 -2
  211. nautobot/extras/views.py +30 -98
  212. nautobot/ipam/api/fields.py +3 -3
  213. nautobot/ipam/api/serializers.py +41 -33
  214. nautobot/ipam/api/views.py +68 -117
  215. nautobot/ipam/factory.py +1 -1
  216. nautobot/ipam/filters.py +3 -2
  217. nautobot/ipam/lookups.py +101 -62
  218. nautobot/ipam/models.py +66 -16
  219. nautobot/ipam/querysets.py +2 -2
  220. nautobot/ipam/tables.py +23 -7
  221. nautobot/ipam/templates/ipam/ipaddress.html +1 -9
  222. nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
  223. nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
  224. nautobot/ipam/templates/ipam/prefix.html +1 -9
  225. nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
  226. nautobot/ipam/templates/ipam/vlan.html +1 -9
  227. nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
  228. nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
  229. nautobot/ipam/tests/test_api.py +436 -3
  230. nautobot/ipam/tests/test_forms.py +49 -47
  231. nautobot/ipam/tests/test_migrations.py +30 -30
  232. nautobot/ipam/tests/test_models.py +95 -34
  233. nautobot/ipam/tests/test_querysets.py +63 -1
  234. nautobot/ipam/tests/test_views.py +3 -0
  235. nautobot/ipam/utils/__init__.py +36 -6
  236. nautobot/ipam/views.py +61 -87
  237. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  238. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  239. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
  240. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  241. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  242. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  243. nautobot/project-static/docs/404.html +46 -4
  244. nautobot/project-static/docs/apps/index.html +46 -4
  245. nautobot/project-static/docs/apps/nautobot-apps.html +47 -6
  246. nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
  247. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.88dd0f4e.min.js} +2 -2
  248. nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.88dd0f4e.min.js.map} +2 -2
  249. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +62 -10
  250. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +59 -7
  251. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +374 -122
  252. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +90 -18
  253. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +95 -21
  254. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +53 -6
  255. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +52 -5
  256. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +79 -17
  257. nautobot/project-static/docs/code-reference/nautobot/apps/events.html +102 -28
  258. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +108 -21
  259. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +131 -38
  260. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +239 -65
  261. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +581 -165
  262. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +109 -36
  263. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +453 -167
  264. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +493 -211
  265. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +60 -8
  266. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +71 -15
  267. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +407 -55
  268. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +620 -205
  269. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +858 -412
  270. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +59 -7
  271. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +448 -186
  272. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +365 -147
  273. nautobot/project-static/docs/development/apps/api/configuration-view.html +46 -4
  274. nautobot/project-static/docs/development/apps/api/database-backend-config.html +46 -4
  275. nautobot/project-static/docs/development/apps/api/models/django-admin.html +46 -4
  276. nautobot/project-static/docs/development/apps/api/models/global-search.html +46 -4
  277. nautobot/project-static/docs/development/apps/api/models/graphql.html +46 -4
  278. nautobot/project-static/docs/development/apps/api/models/index.html +46 -4
  279. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +46 -4
  280. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +46 -4
  281. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +46 -4
  282. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +46 -4
  283. nautobot/project-static/docs/development/apps/api/platform-features/index.html +46 -4
  284. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +46 -4
  285. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +46 -4
  286. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +46 -4
  287. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +46 -4
  288. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +68 -7
  289. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +46 -4
  290. nautobot/project-static/docs/development/apps/api/prometheus.html +46 -4
  291. nautobot/project-static/docs/development/apps/api/setup.html +46 -4
  292. nautobot/project-static/docs/development/apps/api/testing.html +46 -4
  293. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +46 -4
  294. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +46 -4
  295. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +46 -4
  296. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +46 -4
  297. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +46 -4
  298. nautobot/project-static/docs/development/apps/api/views/base-template.html +46 -4
  299. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +46 -4
  300. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +46 -4
  301. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +46 -4
  302. nautobot/project-static/docs/development/apps/api/views/index.html +46 -4
  303. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +46 -4
  304. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +46 -4
  305. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +46 -4
  306. nautobot/project-static/docs/development/apps/api/views/notes.html +46 -4
  307. nautobot/project-static/docs/development/apps/api/views/rest-api.html +52 -6
  308. nautobot/project-static/docs/development/apps/api/views/urls.html +46 -4
  309. nautobot/project-static/docs/development/apps/index.html +46 -4
  310. nautobot/project-static/docs/development/apps/migration/code-updates.html +46 -4
  311. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +46 -4
  312. nautobot/project-static/docs/development/apps/migration/from-v1.html +46 -4
  313. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +46 -4
  314. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +46 -4
  315. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +46 -4
  316. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +46 -4
  317. nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +50 -8
  318. nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +46 -4
  319. nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +211 -14
  320. nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +46 -4
  321. nautobot/project-static/docs/development/apps/porting-from-netbox.html +46 -4
  322. nautobot/project-static/docs/development/core/application-registry.html +46 -4
  323. nautobot/project-static/docs/development/core/best-practices.html +46 -4
  324. nautobot/project-static/docs/development/core/bootstrap-ui.html +46 -4
  325. nautobot/project-static/docs/development/core/caching.html +46 -4
  326. nautobot/project-static/docs/development/core/controllers.html +46 -4
  327. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +73 -74
  328. nautobot/project-static/docs/development/core/generic-views.html +46 -4
  329. nautobot/project-static/docs/development/core/getting-started.html +249 -224
  330. nautobot/project-static/docs/development/core/homepage.html +49 -7
  331. nautobot/project-static/docs/development/core/index.html +46 -4
  332. nautobot/project-static/docs/development/core/{local-k8s.html → minikube-dev-environment-for-k8s-jobs.html} +469 -168
  333. nautobot/project-static/docs/development/core/model-checklist.html +56 -12
  334. nautobot/project-static/docs/development/core/model-features.html +46 -4
  335. nautobot/project-static/docs/development/core/natural-keys.html +46 -4
  336. nautobot/project-static/docs/development/core/navigation-menu.html +46 -4
  337. nautobot/project-static/docs/development/core/release-checklist.html +49 -7
  338. nautobot/project-static/docs/development/core/role-internals.html +46 -4
  339. nautobot/project-static/docs/development/core/settings.html +46 -4
  340. nautobot/project-static/docs/development/core/style-guide.html +49 -7
  341. nautobot/project-static/docs/development/core/templates.html +46 -4
  342. nautobot/project-static/docs/development/core/testing.html +46 -4
  343. nautobot/project-static/docs/development/core/ui-component-framework.html +369 -273
  344. nautobot/project-static/docs/development/core/user-preferences.html +46 -4
  345. nautobot/project-static/docs/development/index.html +46 -4
  346. nautobot/project-static/docs/development/jobs/index.html +216 -122
  347. nautobot/project-static/docs/development/jobs/migration/from-v1.html +46 -4
  348. nautobot/project-static/docs/index.html +54 -23
  349. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
  350. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
  351. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
  352. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
  353. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
  354. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
  355. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
  356. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
  357. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
  358. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
  359. nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
  360. nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
  361. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
  362. nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
  363. nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
  364. nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
  365. nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
  366. nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
  367. nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
  368. nautobot/project-static/docs/objects.inv +0 -0
  369. nautobot/project-static/docs/overview/application_stack.html +47 -7
  370. nautobot/project-static/docs/overview/design_philosophy.html +46 -4
  371. nautobot/project-static/docs/release-notes/index.html +52 -12
  372. nautobot/project-static/docs/release-notes/version-1.0.html +234 -193
  373. nautobot/project-static/docs/release-notes/version-1.1.html +231 -190
  374. nautobot/project-static/docs/release-notes/version-1.2.html +306 -265
  375. nautobot/project-static/docs/release-notes/version-1.3.html +332 -291
  376. nautobot/project-static/docs/release-notes/version-1.4.html +417 -377
  377. nautobot/project-static/docs/release-notes/version-1.5.html +605 -566
  378. nautobot/project-static/docs/release-notes/version-1.6.html +904 -447
  379. nautobot/project-static/docs/release-notes/version-2.0.html +528 -489
  380. nautobot/project-static/docs/release-notes/version-2.1.html +363 -324
  381. nautobot/project-static/docs/release-notes/version-2.2.html +356 -317
  382. nautobot/project-static/docs/release-notes/version-2.3.html +997 -352
  383. nautobot/project-static/docs/release-notes/version-2.4.html +525 -101
  384. nautobot/project-static/docs/requirements.txt +2 -2
  385. nautobot/project-static/docs/search/search_index.json +1 -1
  386. nautobot/project-static/docs/sitemap.xml +295 -287
  387. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  388. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +46 -4
  389. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +46 -4
  390. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +48 -6
  391. nautobot/project-static/docs/user-guide/administration/configuration/index.html +46 -4
  392. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +46 -4
  393. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +110 -8
  394. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +46 -4
  395. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +46 -4
  396. nautobot/project-static/docs/user-guide/administration/guides/docker.html +46 -4
  397. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +46 -4
  398. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +46 -4
  399. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +46 -4
  400. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +46 -4
  401. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +46 -4
  402. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +48 -6
  403. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +46 -4
  404. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +46 -4
  405. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +46 -4
  406. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +66 -8
  407. nautobot/project-static/docs/user-guide/administration/installation/index.html +46 -4
  408. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +47 -5
  409. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +46 -4
  410. nautobot/project-static/docs/user-guide/administration/installation/services.html +46 -4
  411. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +46 -4
  412. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +46 -4
  413. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +46 -4
  414. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +46 -4
  415. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +46 -4
  416. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +46 -4
  417. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +46 -4
  418. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +46 -4
  419. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +46 -4
  420. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +49 -8
  421. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +46 -4
  422. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +46 -4
  423. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +46 -4
  424. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +46 -4
  425. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +46 -4
  426. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +46 -4
  427. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +46 -4
  428. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +46 -4
  429. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +46 -4
  430. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +46 -4
  431. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +46 -4
  432. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +46 -4
  433. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +46 -4
  434. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +46 -4
  435. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +46 -4
  436. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +46 -4
  437. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +46 -4
  438. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +46 -4
  439. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +46 -4
  440. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +46 -4
  441. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +46 -4
  442. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +46 -4
  443. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +46 -4
  444. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +46 -4
  445. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +46 -4
  446. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +46 -4
  447. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +46 -4
  448. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +46 -4
  449. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +46 -4
  450. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +46 -4
  451. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +46 -4
  452. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +46 -4
  453. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +46 -4
  454. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +46 -4
  455. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +46 -4
  456. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +46 -4
  457. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +46 -4
  458. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +46 -4
  459. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +46 -4
  460. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +46 -4
  461. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +46 -4
  462. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +46 -4
  463. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +46 -4
  464. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +46 -4
  465. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +46 -4
  466. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +46 -4
  467. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +46 -4
  468. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +46 -4
  469. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +46 -4
  470. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +46 -4
  471. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +46 -4
  472. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +46 -4
  473. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +46 -4
  474. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +46 -4
  475. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +46 -4
  476. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +46 -4
  477. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +46 -4
  478. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +50 -12
  479. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +46 -4
  480. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +46 -4
  481. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +46 -4
  482. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +46 -4
  483. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +46 -4
  484. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +46 -4
  485. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +46 -4
  486. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +46 -4
  487. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +46 -4
  488. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +46 -4
  489. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +46 -4
  490. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +46 -4
  491. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +49 -7
  492. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +46 -4
  493. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +46 -4
  494. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +46 -4
  495. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +46 -4
  496. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +46 -4
  497. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +46 -4
  498. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +46 -4
  499. nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +46 -4
  500. nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +46 -4
  501. nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +46 -4
  502. nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +46 -4
  503. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +46 -4
  504. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +46 -4
  505. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +46 -4
  506. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +46 -4
  507. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +46 -4
  508. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +46 -4
  509. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +46 -4
  510. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +46 -4
  511. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +46 -4
  512. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +46 -4
  513. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +46 -4
  514. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +51 -7
  515. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +46 -4
  516. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
  517. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
  518. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
  519. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
  520. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
  521. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
  522. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
  523. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
  524. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
  525. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
  526. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
  527. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
  528. nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
  529. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +46 -4
  530. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +46 -4
  531. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +49 -7
  532. nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
  533. nautobot/project-static/docs/user-guide/index.html +46 -4
  534. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +46 -4
  535. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +50 -8
  536. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +46 -4
  537. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +46 -4
  538. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +46 -4
  539. nautobot/project-static/docs/user-guide/platform-functionality/events.html +46 -4
  540. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +46 -4
  541. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +46 -4
  542. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +46 -4
  543. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +46 -4
  544. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +46 -4
  545. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +46 -4
  546. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +50 -7
  547. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +46 -4
  548. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +49 -7
  549. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +46 -4
  550. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +46 -4
  551. nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
  552. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +46 -4
  553. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +46 -4
  554. nautobot/project-static/docs/user-guide/platform-functionality/note.html +46 -4
  555. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +46 -4
  556. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +47 -5
  557. nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +46 -4
  558. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +46 -4
  559. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +94 -25
  560. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +74 -5
  561. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +46 -4
  562. nautobot/project-static/docs/user-guide/platform-functionality/role.html +46 -4
  563. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +46 -4
  564. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +46 -4
  565. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +46 -4
  566. nautobot/project-static/docs/user-guide/platform-functionality/status.html +46 -4
  567. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +46 -4
  568. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +46 -4
  569. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +46 -4
  570. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +46 -4
  571. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +46 -4
  572. nautobot/project-static/js/forms.js +1 -1
  573. nautobot/tenancy/api/views.py +9 -13
  574. nautobot/tenancy/views.py +4 -2
  575. nautobot/users/admin.py +1 -1
  576. nautobot/users/api/serializers.py +5 -4
  577. nautobot/users/api/views.py +3 -3
  578. nautobot/virtualization/api/serializers.py +4 -4
  579. nautobot/virtualization/api/views.py +5 -24
  580. nautobot/virtualization/filters.py +20 -3
  581. nautobot/virtualization/models.py +1 -1
  582. nautobot/virtualization/tables.py +2 -2
  583. nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
  584. nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
  585. nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
  586. nautobot/virtualization/tests/test_filters.py +17 -0
  587. nautobot/wireless/filters.py +2 -2
  588. nautobot/wireless/forms.py +1 -1
  589. nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
  590. nautobot/wireless/tests/integration/__init__.py +0 -0
  591. nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
  592. nautobot/wireless/tests/test_filters.py +29 -1
  593. nautobot/wireless/tests/test_views.py +22 -1
  594. nautobot/wireless/views.py +0 -10
  595. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/METADATA +6 -6
  596. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/RECORD +600 -550
  597. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/WHEEL +1 -1
  598. nautobot/core/fixtures/user-data.json +0 -59
  599. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/LICENSE.txt +0 -0
  600. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/NOTICE +0 -0
  601. {nautobot-2.4.0b1.dist-info → nautobot-2.4.1.dist-info}/entry_points.txt +0 -0
@@ -116,6 +116,7 @@ from nautobot.extras.models import (
116
116
  CustomField,
117
117
  CustomFieldChoice,
118
118
  ExternalIntegration,
119
+ JobResult,
119
120
  Relationship,
120
121
  RelationshipAssociation,
121
122
  Role,
@@ -128,6 +129,7 @@ from nautobot.ipam.choices import IPAddressTypeChoices
128
129
  from nautobot.ipam.models import IPAddress, Namespace, Prefix, VLAN, VLANGroup, VRF
129
130
  from nautobot.tenancy.models import Tenant
130
131
  from nautobot.users.models import ObjectPermission
132
+ from nautobot.virtualization.models import Cluster, ClusterType
131
133
 
132
134
  # Use the proper swappable User model
133
135
  User = get_user_model()
@@ -1150,9 +1152,15 @@ module-bays:
1150
1152
  }
1151
1153
 
1152
1154
  response = self.client.post(url, data)
1155
+ job_result = JobResult.objects.filter(name="Bulk Edit Objects").first()
1156
+ # Assert successfull redirect to Job Results; whcih means no form validation error was raised
1157
+ self.assertRedirects(
1158
+ response,
1159
+ reverse("extras:jobresult", args=[job_result.pk]),
1160
+ status_code=302,
1161
+ target_status_code=200,
1162
+ )
1153
1163
  self.assertHttpStatus(response, 302)
1154
- for instance in self._get_queryset().filter(pk__in=pk_list):
1155
- self.assertEqual(instance.u_height, data["u_height"])
1156
1164
 
1157
1165
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
1158
1166
  def test_rack_height_bulk_edit_invalid(self):
@@ -1168,7 +1176,12 @@ module-bays:
1168
1176
  }
1169
1177
 
1170
1178
  response = self.client.post(url, data)
1171
- self.assertBodyContains(response, "failed validation")
1179
+ response_content = response.content.decode(response.charset)
1180
+ self.assertHttpStatus(response, 200)
1181
+ self.assertInHTML(
1182
+ '<strong class="panel-title">U height</strong>: <ul class="errorlist"><li>Ensure this value is greater than or equal to 0.</li></ul>',
1183
+ response_content,
1184
+ )
1172
1185
 
1173
1186
 
1174
1187
  class ModuleTypeTestCase(
@@ -2045,6 +2058,9 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2045
2058
 
2046
2059
  rack_group = RackGroup.objects.create(location=locations[0], name="Rack Group 1")
2047
2060
 
2061
+ cluster_type = ClusterType.objects.create(name="Cluster Type 1")
2062
+ cluster = Cluster.objects.create(name="Cluster 1", cluster_type=cluster_type)
2063
+
2048
2064
  rack_status = Status.objects.get_for_model(Rack).first()
2049
2065
  racks = (
2050
2066
  Rack.objects.create(
@@ -2216,6 +2232,8 @@ class DeviceTestCase(ViewTestCases.PrimaryObjectViewTestCase):
2216
2232
  "status": statuses[2].pk,
2217
2233
  "location": locations[1].pk,
2218
2234
  "rack": racks[1].pk,
2235
+ "cluster": cluster.pk,
2236
+ "comments": "An older device",
2219
2237
  "position": None,
2220
2238
  "face": DeviceFaceChoices.FACE_FRONT,
2221
2239
  "secrets_group": secrets_groups[1].pk,
@@ -4574,46 +4592,6 @@ class SoftwareImageFileTestCase(ViewTestCases.PrimaryObjectViewTestCase):
4574
4592
  "download_url": "https://example.com/software_image_file_test_case.bin",
4575
4593
  }
4576
4594
 
4577
- @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
4578
- def test_correct_handling_for_model_protected_error(self):
4579
- platform = Platform.objects.first()
4580
- software_version_status = Status.objects.get_for_model(SoftwareVersion).first()
4581
- software_image_file_status = Status.objects.get_for_model(SoftwareImageFile).first()
4582
- software_version = SoftwareVersion.objects.create(
4583
- platform=platform, version="Test version 1.0.0", status=software_version_status
4584
- )
4585
- software_image_file = SoftwareImageFile.objects.create(
4586
- software_version=software_version,
4587
- image_file_name="software_image_file_qs_test_1.bin",
4588
- status=software_image_file_status,
4589
- )
4590
- device_type = DeviceType.objects.first()
4591
- device_role = Role.objects.get_for_model(Device).first()
4592
- device_status = Status.objects.get_for_model(Device).first()
4593
- location = Location.objects.filter(location_type__name="Campus").first()
4594
- Device.objects.create(
4595
- device_type=device_type,
4596
- role=device_role,
4597
- name="Device 1",
4598
- location=location,
4599
- status=device_status,
4600
- software_version=software_version,
4601
- )
4602
- device_type_to_software_image_file = DeviceTypeToSoftwareImageFile.objects.create(
4603
- device_type=device_type, software_image_file=software_image_file
4604
- )
4605
-
4606
- self.add_permissions("dcim.delete_softwareimagefile")
4607
- pk_list = [software_image_file.pk]
4608
- data = {
4609
- "pk": pk_list,
4610
- "confirm": True,
4611
- "_confirm": True, # Form button
4612
- }
4613
- response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
4614
- # Assert protected error message included in the response body
4615
- self.assertBodyContains(response, f"<span>{device_type_to_software_image_file}</span>", html=True)
4616
-
4617
4595
 
4618
4596
  class SoftwareVersionTestCase(ViewTestCases.PrimaryObjectViewTestCase):
4619
4597
  model = SoftwareVersion
@@ -4652,46 +4630,6 @@ class SoftwareVersionTestCase(ViewTestCases.PrimaryObjectViewTestCase):
4652
4630
  "pre_release": True,
4653
4631
  }
4654
4632
 
4655
- @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
4656
- def test_correct_handling_for_model_protected_error(self):
4657
- platform = Platform.objects.first()
4658
- software_version_status = Status.objects.get_for_model(SoftwareVersion).first()
4659
- software_image_file_status = Status.objects.get_for_model(SoftwareImageFile).first()
4660
- software_version = SoftwareVersion.objects.create(
4661
- platform=platform, version="Test version 1.0.0", status=software_version_status
4662
- )
4663
- software_image_file = SoftwareImageFile.objects.create(
4664
- software_version=software_version,
4665
- image_file_name="software_image_file_qs_test_1.bin",
4666
- status=software_image_file_status,
4667
- )
4668
- device_type = DeviceType.objects.first()
4669
- device_role = Role.objects.get_for_model(Device).first()
4670
- device_status = Status.objects.get_for_model(Device).first()
4671
- location = Location.objects.filter(location_type__name="Campus").first()
4672
- Device.objects.create(
4673
- device_type=device_type,
4674
- role=device_role,
4675
- name="Device 1",
4676
- location=location,
4677
- status=device_status,
4678
- software_version=software_version,
4679
- )
4680
- device_type_to_software_image_file = DeviceTypeToSoftwareImageFile.objects.create(
4681
- device_type=device_type, software_image_file=software_image_file
4682
- )
4683
-
4684
- self.add_permissions("dcim.delete_softwareversion")
4685
- pk_list = [software_version.pk]
4686
- data = {
4687
- "pk": pk_list,
4688
- "confirm": True,
4689
- "_confirm": True, # Form button
4690
- }
4691
- response = self.client.post(self._get_url("bulk_delete"), data, follow=True)
4692
- # Assert protected error message included in the response body
4693
- self.assertBodyContains(response, f"<span>{device_type_to_software_image_file}</span>", html=True)
4694
-
4695
4633
 
4696
4634
  class ControllerTestCase(ViewTestCases.PrimaryObjectViewTestCase):
4697
4635
  model = Controller
nautobot/dcim/views.py CHANGED
@@ -697,7 +697,7 @@ class RackReservationEditView(generic.ObjectEditView):
697
697
  model_form = forms.RackReservationForm
698
698
  template_name = "dcim/rackreservation_edit.html"
699
699
 
700
- def alter_obj(self, obj, request, args, kwargs):
700
+ def alter_obj(self, obj, request, url_args, url_kwargs):
701
701
  if not obj.present_in_database:
702
702
  if "rack" in request.GET:
703
703
  obj.rack = get_object_or_404(Rack, pk=request.GET.get("rack"))
@@ -4502,12 +4502,6 @@ class ControllerManagedDeviceGroupUIViewSet(NautobotUIViewSet):
4502
4502
 
4503
4503
  return obj
4504
4504
 
4505
- def extra_post_save_action(self, obj, form):
4506
- if form.cleaned_data.get("add_radio_profiles", None):
4507
- obj.radio_profiles.add(*form.cleaned_data["add_radio_profiles"])
4508
- if form.cleaned_data.get("remove_radio_profiles", None):
4509
- obj.radio_profiles.remove(*form.cleaned_data["remove_radio_profiles"])
4510
-
4511
4505
 
4512
4506
  #
4513
4507
  # Virtual Device Context
@@ -4534,9 +4528,3 @@ class VirtualDeviceContextUIViewSet(NautobotUIViewSet):
4534
4528
  **super().get_extra_context(request, instance),
4535
4529
  }
4536
4530
  return super().get_extra_context(request, instance)
4537
-
4538
- def extra_post_save_action(self, obj, form):
4539
- if form.cleaned_data.get("add_interfaces", None):
4540
- obj.prefixes.add(*form.cleaned_data["add_interfaces"])
4541
- if form.cleaned_data.get("remove_interfaces", None):
4542
- obj.prefixes.remove(*form.cleaned_data["remove_interfaces"])
@@ -42,8 +42,8 @@ class CustomFieldsDataField(Field):
42
42
  def custom_field_keys(self):
43
43
  return CustomField.objects.keys_for_model(self.parent.Meta.model)
44
44
 
45
- def to_representation(self, obj):
46
- return {key: obj.get(key) for key in self.custom_field_keys}
45
+ def to_representation(self, value):
46
+ return {key: value.get(key) for key in self.custom_field_keys}
47
47
 
48
48
  def to_internal_value(self, data):
49
49
  """Support updates to individual fields on an existing instance without needing to provide the entire dict."""
@@ -19,7 +19,6 @@ from nautobot.core.api import (
19
19
  ValidatedModelSerializer,
20
20
  )
21
21
  from nautobot.core.api.exceptions import SerializerNotFound
22
- from nautobot.core.api.fields import NautobotHyperlinkedRelatedField
23
22
  from nautobot.core.api.serializers import PolymorphicProxySerializer
24
23
  from nautobot.core.api.utils import (
25
24
  get_nested_serializer_depth,
@@ -136,12 +135,12 @@ class ConfigContextSerializer(ValidatedModelSerializer, TaggedModelSerializerMix
136
135
  owner = serializers.SerializerMethodField(read_only=True)
137
136
 
138
137
  # Conditional enablement of dynamic groups filtering
139
- def __init__(self, *args, **kwargs):
140
- super().__init__(*args, **kwargs)
141
-
138
+ @property
139
+ def fields(self):
140
+ fields = super().fields
142
141
  if not settings.CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED:
143
- # In the case of a nested serializer, we won't have a `dynamic_groups` field at all.
144
- self.fields.pop("dynamic_groups", None)
142
+ fields.pop("dynamic_groups", None)
143
+ return fields
145
144
 
146
145
  class Meta:
147
146
  model = ConfigContext
@@ -200,10 +199,7 @@ class ConfigContextSchemaSerializer(NautobotModelSerializer):
200
199
  #
201
200
 
202
201
 
203
- class ContactSerializer(NautobotModelSerializer):
204
- # needed since this is the reverse side of the M2M field.
205
- teams = NautobotHyperlinkedRelatedField(queryset=Team.objects.all(), many=True, required=False)
206
-
202
+ class ContactSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
207
203
  class Meta:
208
204
  model = Contact
209
205
  fields = "__all__"
@@ -212,15 +208,22 @@ class ContactSerializer(NautobotModelSerializer):
212
208
  extra_kwargs = {
213
209
  "email": {"default": ""},
214
210
  "phone": {"default": ""},
211
+ "teams": {"required": False},
215
212
  }
216
213
 
217
- def validate(self, data):
218
- attrs = data.copy()
219
- attrs.pop("teams", None)
214
+ def get_field_names(self, declared_fields, info):
215
+ """Add reverse M2M for teams to the fields for this serializer."""
216
+ field_names = list(super().get_field_names(declared_fields, info))
217
+ self.extend_field_names(field_names, "teams")
218
+ return field_names
219
+
220
+ def validate(self, attrs):
221
+ local_attrs = attrs.copy()
222
+ local_attrs.pop("teams", None)
220
223
  validator = UniqueTogetherValidator(queryset=Contact.objects.all(), fields=("name", "phone", "email"))
221
- validator(attrs, self)
222
- super().validate(attrs)
223
- return data
224
+ validator(local_attrs, self)
225
+ super().validate(local_attrs)
226
+ return attrs
224
227
 
225
228
 
226
229
  class ContactAssociationSerializer(NautobotModelSerializer):
@@ -235,18 +238,18 @@ class ContactAssociationSerializer(NautobotModelSerializer):
235
238
  "team": {"required": False},
236
239
  }
237
240
 
238
- def validate(self, data):
241
+ def validate(self, attrs):
239
242
  # Validate uniqueness of (associated object, associated object type, contact/team, role)
240
243
  unique_together_fields = None
241
244
 
242
- if data.get("contact") and data.get("role"):
245
+ if attrs.get("contact") and attrs.get("role"):
243
246
  unique_together_fields = (
244
247
  "associated_object_type",
245
248
  "associated_object_id",
246
249
  "contact",
247
250
  "role",
248
251
  )
249
- elif data.get("team") and data.get("role"):
252
+ elif attrs.get("team") and attrs.get("role"):
250
253
  unique_together_fields = (
251
254
  "associated_object_type",
252
255
  "associated_object_id",
@@ -259,11 +262,11 @@ class ContactAssociationSerializer(NautobotModelSerializer):
259
262
  queryset=ContactAssociation.objects.all(),
260
263
  fields=unique_together_fields,
261
264
  )
262
- validator(data, self)
265
+ validator(attrs, self)
263
266
 
264
- super().validate(data)
267
+ super().validate(attrs)
265
268
 
266
- return data
269
+ return attrs
267
270
 
268
271
 
269
272
  #
@@ -272,6 +275,7 @@ class ContactAssociationSerializer(NautobotModelSerializer):
272
275
 
273
276
 
274
277
  class ContentTypeSerializer(BaseModelSerializer):
278
+ id = serializers.IntegerField(read_only=True)
275
279
  url = serializers.HyperlinkedIdentityField(view_name="extras-api:contenttype-detail")
276
280
  display = serializers.SerializerMethodField()
277
281
 
@@ -280,8 +284,8 @@ class ContentTypeSerializer(BaseModelSerializer):
280
284
  fields = "__all__"
281
285
 
282
286
  @extend_schema_field(serializers.CharField)
283
- def get_display(self, obj):
284
- return obj.app_labeled_name
287
+ def get_display(self, instance):
288
+ return instance.app_labeled_name
285
289
 
286
290
 
287
291
  #
@@ -433,7 +437,7 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
433
437
  #
434
438
 
435
439
 
436
- class ExternalIntegrationSerializer(NautobotModelSerializer):
440
+ class ExternalIntegrationSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
437
441
  class Meta:
438
442
  model = ExternalIntegration
439
443
  fields = "__all__"
@@ -455,7 +459,7 @@ class FileProxySerializer(BaseModelSerializer):
455
459
  #
456
460
 
457
461
 
458
- class GitRepositorySerializer(NautobotModelSerializer):
462
+ class GitRepositorySerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
459
463
  """Git repositories defined as a data source."""
460
464
 
461
465
  provided_contents = MultipleChoiceJSONField(
@@ -502,17 +506,17 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
502
506
  model = ImageAttachment
503
507
  fields = "__all__"
504
508
 
505
- def validate(self, data):
509
+ def validate(self, attrs):
506
510
  # Validate that the parent object exists
507
511
  try:
508
- data["content_type"].get_object_for_this_type(id=data["object_id"])
512
+ attrs["content_type"].get_object_for_this_type(id=attrs["object_id"])
509
513
  except ObjectDoesNotExist:
510
- raise serializers.ValidationError(f"Invalid parent object: {data['content_type']} ID {data['object_id']}")
514
+ raise serializers.ValidationError(f"Invalid parent object: {attrs['content_type']} ID {attrs['object_id']}")
511
515
 
512
516
  # Enforce model validation
513
- super().validate(data)
517
+ super().validate(attrs)
514
518
 
515
- return data
519
+ return attrs
516
520
 
517
521
  @extend_schema_field(
518
522
  PolymorphicProxySerializer(
@@ -544,24 +548,24 @@ class JobSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
544
548
  model = Job
545
549
  fields = "__all__"
546
550
 
547
- def validate(self, data):
551
+ def validate(self, attrs):
548
552
  # note no validation for on creation of jobs because we do not support user creation of Job records via API
549
553
  if self.instance:
550
- has_sensitive_variables = data.get("has_sensitive_variables", self.instance.has_sensitive_variables)
551
- approval_required = data.get("approval_required", self.instance.approval_required)
554
+ has_sensitive_variables = attrs.get("has_sensitive_variables", self.instance.has_sensitive_variables)
555
+ approval_required = attrs.get("approval_required", self.instance.approval_required)
552
556
 
553
557
  if approval_required and has_sensitive_variables:
554
558
  error_message = "A job with sensitive variables cannot also be marked as requiring approval"
555
559
  errors = {}
556
560
 
557
- if "approval_required" in data:
561
+ if "approval_required" in attrs:
558
562
  errors["approval_required"] = [error_message]
559
- if "has_sensitive_variables" in data:
563
+ if "has_sensitive_variables" in attrs:
560
564
  errors["has_sensitive_variables"] = [error_message]
561
565
 
562
566
  raise serializers.ValidationError(errors)
563
567
 
564
- return super().validate(data)
568
+ return super().validate(attrs)
565
569
 
566
570
 
567
571
  class JobQueueSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
@@ -687,22 +691,22 @@ class JobHookSerializer(NautobotModelSerializer):
687
691
  model = JobHook
688
692
  fields = "__all__"
689
693
 
690
- def validate(self, data):
691
- validated_data = super().validate(data)
694
+ def validate(self, attrs):
695
+ validated_attrs = super().validate(attrs)
692
696
 
693
697
  conflicts = JobHook.check_for_conflicts(
694
698
  instance=self.instance,
695
- content_types=data.get("content_types"),
696
- job=data.get("job"),
697
- type_create=data.get("type_create"),
698
- type_update=data.get("type_update"),
699
- type_delete=data.get("type_delete"),
699
+ content_types=attrs.get("content_types"),
700
+ job=attrs.get("job"),
701
+ type_create=attrs.get("type_create"),
702
+ type_update=attrs.get("type_update"),
703
+ type_delete=attrs.get("type_delete"),
700
704
  )
701
705
 
702
706
  if conflicts:
703
707
  raise serializers.ValidationError(conflicts)
704
708
 
705
- return validated_data
709
+ return validated_attrs
706
710
 
707
711
 
708
712
  class JobCreationSerializer(BaseModelSerializer):
@@ -721,15 +725,15 @@ class JobCreationSerializer(BaseModelSerializer):
721
725
  model = ScheduledJob
722
726
  fields = ["url", "name", "start_time", "interval", "crontab"]
723
727
 
724
- def validate(self, data):
725
- data = super().validate(data)
728
+ def validate(self, attrs):
729
+ attrs = super().validate(attrs)
726
730
 
727
- if data["interval"] in choices.JobExecutionType.SCHEDULE_CHOICES:
728
- if "name" not in data:
731
+ if attrs["interval"] in choices.JobExecutionType.SCHEDULE_CHOICES:
732
+ if "name" not in attrs:
729
733
  raise serializers.ValidationError({"name": "Please provide a name for the job schedule."})
730
734
 
731
- if ("start_time" not in data and data["interval"] != choices.JobExecutionType.TYPE_CUSTOM) or (
732
- "start_time" in data and data["start_time"] < models.ScheduledJob.earliest_possible_time()
735
+ if ("start_time" not in attrs and attrs["interval"] != choices.JobExecutionType.TYPE_CUSTOM) or (
736
+ "start_time" in attrs and attrs["start_time"] < models.ScheduledJob.earliest_possible_time()
733
737
  ):
734
738
  raise serializers.ValidationError(
735
739
  {
@@ -737,15 +741,15 @@ class JobCreationSerializer(BaseModelSerializer):
737
741
  }
738
742
  )
739
743
 
740
- if data["interval"] == choices.JobExecutionType.TYPE_CUSTOM:
741
- if data.get("crontab") is None:
744
+ if attrs["interval"] == choices.JobExecutionType.TYPE_CUSTOM:
745
+ if attrs.get("crontab") is None:
742
746
  raise serializers.ValidationError({"crontab": "Please enter a valid crontab."})
743
747
  try:
744
- models.ScheduledJob.get_crontab(data["crontab"])
748
+ models.ScheduledJob.get_crontab(attrs["crontab"])
745
749
  except Exception as e:
746
750
  raise serializers.ValidationError({"crontab": e})
747
751
 
748
- return data
752
+ return attrs
749
753
 
750
754
 
751
755
  class JobInputSerializer(serializers.Serializer):
@@ -765,15 +769,18 @@ class JobMultiPartInputSerializer(serializers.Serializer):
765
769
  _task_queue = serializers.CharField(required=False, allow_blank=True)
766
770
  _job_queue = serializers.CharField(required=False, allow_blank=True)
767
771
 
768
- def validate(self, data):
769
- data = super().validate(data)
772
+ def validate(self, attrs):
773
+ attrs = super().validate(attrs)
770
774
 
771
- if "_schedule_interval" in data and data["_schedule_interval"] != JobExecutionType.TYPE_IMMEDIATELY:
772
- if "_schedule_name" not in data:
775
+ if "_schedule_interval" in attrs and attrs["_schedule_interval"] != JobExecutionType.TYPE_IMMEDIATELY:
776
+ if "_schedule_name" not in attrs:
773
777
  raise serializers.ValidationError({"_schedule_name": "Please provide a name for the job schedule."})
774
778
 
775
- if ("_schedule_start_time" not in data and data["_schedule_interval"] != JobExecutionType.TYPE_CUSTOM) or (
776
- "_schedule_start_time" in data and data["_schedule_start_time"] < ScheduledJob.earliest_possible_time()
779
+ if (
780
+ "_schedule_start_time" not in attrs and attrs["_schedule_interval"] != JobExecutionType.TYPE_CUSTOM
781
+ ) or (
782
+ "_schedule_start_time" in attrs
783
+ and attrs["_schedule_start_time"] < ScheduledJob.earliest_possible_time()
777
784
  ):
778
785
  raise serializers.ValidationError(
779
786
  {
@@ -781,15 +788,15 @@ class JobMultiPartInputSerializer(serializers.Serializer):
781
788
  }
782
789
  )
783
790
 
784
- if data["_schedule_interval"] == JobExecutionType.TYPE_CUSTOM:
785
- if data.get("_schedule_crontab") is None:
791
+ if attrs["_schedule_interval"] == JobExecutionType.TYPE_CUSTOM:
792
+ if attrs.get("_schedule_crontab") is None:
786
793
  raise serializers.ValidationError({"_schedule_crontab": "Please enter a valid crontab."})
787
794
  try:
788
- ScheduledJob.get_crontab(data["_schedule_crontab"])
795
+ ScheduledJob.get_crontab(attrs["_schedule_crontab"])
789
796
  except Exception as e:
790
797
  raise serializers.ValidationError({"_schedule_crontab": e})
791
798
 
792
- return data
799
+ return attrs
793
800
 
794
801
 
795
802
  class JobLogEntrySerializer(BaseModelSerializer):
@@ -816,7 +823,7 @@ class JobButtonSerializer(ValidatedModelSerializer, NotesSerializerMixin):
816
823
  #
817
824
 
818
825
 
819
- class MetadataTypeSerializer(NautobotModelSerializer):
826
+ class MetadataTypeSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
820
827
  content_types = ContentTypeField(
821
828
  queryset=ContentType.objects.filter(FeatureQuery("metadata").get_query()),
822
829
  many=True,
@@ -1073,18 +1080,18 @@ class TagSerializer(NautobotModelSerializer):
1073
1080
  "color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
1074
1081
  }
1075
1082
 
1076
- def validate(self, data):
1077
- data = super().validate(data)
1083
+ def validate(self, attrs):
1084
+ attrs = super().validate(attrs)
1078
1085
 
1079
1086
  # check if tag is assigned to any of the removed content_types
1080
- if self.instance is not None and self.instance.present_in_database and "content_types" in data:
1081
- content_types_id = [content_type.id for content_type in data["content_types"]]
1087
+ if self.instance is not None and self.instance.present_in_database and "content_types" in attrs:
1088
+ content_types_id = [content_type.id for content_type in attrs["content_types"]]
1082
1089
  errors = self.instance.validate_content_types_removal(content_types_id)
1083
1090
 
1084
1091
  if errors:
1085
1092
  raise serializers.ValidationError(errors)
1086
1093
 
1087
- return data
1094
+ return attrs
1088
1095
 
1089
1096
 
1090
1097
  #
@@ -1092,9 +1099,7 @@ class TagSerializer(NautobotModelSerializer):
1092
1099
  #
1093
1100
 
1094
1101
 
1095
- class TeamSerializer(NautobotModelSerializer):
1096
- contacts = NautobotHyperlinkedRelatedField(queryset=Contact.objects.all(), many=True, required=False)
1097
-
1102
+ class TeamSerializer(TaggedModelSerializerMixin, NautobotModelSerializer):
1098
1103
  class Meta:
1099
1104
  model = Team
1100
1105
  fields = "__all__"
@@ -1106,10 +1111,10 @@ class TeamSerializer(NautobotModelSerializer):
1106
1111
  # https://www.django-rest-framework.org/api-guide/validators/#optional-fields
1107
1112
  validators = []
1108
1113
 
1109
- def validate(self, data):
1114
+ def validate(self, attrs):
1110
1115
  validator = UniqueTogetherValidator(queryset=Team.objects.all(), fields=("name", "phone", "email"))
1111
- validator(data, self)
1112
- return super().validate(data)
1116
+ validator(attrs, self)
1117
+ return super().validate(attrs)
1113
1118
 
1114
1119
 
1115
1120
  #
@@ -1127,19 +1132,19 @@ class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
1127
1132
  model = Webhook
1128
1133
  fields = "__all__"
1129
1134
 
1130
- def validate(self, data):
1131
- validated_data = super().validate(data)
1135
+ def validate(self, attrs):
1136
+ validated_attrs = super().validate(attrs)
1132
1137
 
1133
1138
  conflicts = Webhook.check_for_conflicts(
1134
1139
  instance=self.instance,
1135
- content_types=data.get("content_types"),
1136
- payload_url=data.get("payload_url"),
1137
- type_create=data.get("type_create"),
1138
- type_update=data.get("type_update"),
1139
- type_delete=data.get("type_delete"),
1140
+ content_types=attrs.get("content_types"),
1141
+ payload_url=attrs.get("payload_url"),
1142
+ type_create=attrs.get("type_create"),
1143
+ type_update=attrs.get("type_update"),
1144
+ type_delete=attrs.get("type_delete"),
1140
1145
  )
1141
1146
 
1142
1147
  if conflicts:
1143
1148
  raise serializers.ValidationError(conflicts)
1144
1149
 
1145
- return validated_data
1150
+ return validated_attrs