nautobot 2.0.4__py3-none-any.whl → 2.1.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.

Potentially problematic release.


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

Files changed (812) hide show
  1. nautobot/circuits/navigation.py +0 -25
  2. nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -9
  3. nautobot/circuits/templates/circuits/providernetwork_retrieve.html +0 -2
  4. nautobot/circuits/tests/test_api.py +79 -2
  5. nautobot/circuits/tests/test_filters.py +1 -0
  6. nautobot/core/api/serializers.py +15 -5
  7. nautobot/core/api/views.py +18 -19
  8. nautobot/core/choices.py +1 -1
  9. nautobot/core/filters.py +12 -4
  10. nautobot/core/jobs/__init__.py +125 -3
  11. nautobot/core/management/commands/generate_test_data.py +6 -1
  12. nautobot/core/middleware.py +12 -4
  13. nautobot/core/models/fields.py +12 -2
  14. nautobot/core/settings.py +9 -8
  15. nautobot/core/tables.py +26 -31
  16. nautobot/core/templates/base_django.html +2 -2
  17. nautobot/core/templates/buttons/export.html +57 -30
  18. nautobot/core/templates/generic/object_list.html +2 -2
  19. nautobot/core/templates/generic/object_retrieve.html +8 -1
  20. nautobot/core/templates/home.html +5 -5
  21. nautobot/core/templates/inc/created_updated.html +2 -2
  22. nautobot/core/templates/inc/footer.html +2 -2
  23. nautobot/core/templates/inc/javascript.html +0 -10
  24. nautobot/core/templates/inc/media.html +2 -0
  25. nautobot/core/templates/inc/nav_menu.html +66 -68
  26. nautobot/core/templates/inc/object_details_advanced_panel.html +19 -0
  27. nautobot/core/templates/nautobot_config.py.j2 +10 -4
  28. nautobot/core/templates/panel_table.html +1 -1
  29. nautobot/core/templates/template.css +89 -0
  30. nautobot/core/templates/utilities/templatetags/table_config_form.html +1 -0
  31. nautobot/core/templatetags/buttons.py +7 -2
  32. nautobot/core/templatetags/helpers.py +9 -9
  33. nautobot/core/testing/views.py +34 -4
  34. nautobot/core/tests/integration/test_home.py +1 -43
  35. nautobot/core/tests/integration/test_navbar.py +10 -64
  36. nautobot/core/tests/integration/test_plugin_home.py +4 -5
  37. nautobot/core/tests/integration/test_plugin_navbar.py +20 -16
  38. nautobot/core/tests/integration/test_theme.py +4 -0
  39. nautobot/core/tests/test_api.py +14 -66
  40. nautobot/core/tests/test_filters.py +127 -0
  41. nautobot/core/tests/test_forms.py +4 -4
  42. nautobot/core/tests/test_graphql.py +165 -2
  43. nautobot/core/tests/test_jobs.py +112 -0
  44. nautobot/core/tests/test_openapi.py +6 -0
  45. nautobot/core/tests/test_utils.py +23 -20
  46. nautobot/core/tests/test_views.py +11 -85
  47. nautobot/core/urls.py +6 -1
  48. nautobot/core/utils/data.py +5 -1
  49. nautobot/core/utils/filtering.py +6 -4
  50. nautobot/core/utils/lookup.py +28 -0
  51. nautobot/core/utils/requests.py +2 -3
  52. nautobot/core/views/__init__.py +3 -4
  53. nautobot/core/views/generic.py +15 -11
  54. nautobot/core/views/mixins.py +9 -8
  55. nautobot/core/views/renderers.py +5 -0
  56. nautobot/core/views/utils.py +23 -24
  57. nautobot/dcim/api/serializers.py +8 -4
  58. nautobot/dcim/models/device_components.py +1 -0
  59. nautobot/dcim/models/devices.py +7 -6
  60. nautobot/dcim/navigation.py +10 -165
  61. nautobot/dcim/templates/dcim/location.html +1 -1
  62. nautobot/dcim/tests/features/locations.feature +143 -0
  63. nautobot/dcim/tests/test_api.py +8 -1
  64. nautobot/dcim/tests/test_filters.py +11 -3
  65. nautobot/dcim/views.py +5 -6
  66. nautobot/extras/admin.py +1 -1
  67. nautobot/extras/api/serializers.py +33 -0
  68. nautobot/extras/api/urls.py +6 -0
  69. nautobot/extras/api/views.py +45 -6
  70. nautobot/extras/context_managers.py +34 -8
  71. nautobot/extras/factory.py +28 -2
  72. nautobot/extras/filters/__init__.py +52 -0
  73. nautobot/extras/filters/mixins.py +4 -29
  74. nautobot/extras/forms/forms.py +43 -0
  75. nautobot/extras/jobs.py +39 -17
  76. nautobot/extras/migrations/0100_fileproxy_job_result.py +32 -0
  77. nautobot/extras/migrations/0101_externalintegration.py +61 -0
  78. nautobot/extras/migrations/0102_set_null_objectchange_contenttype.py +32 -0
  79. nautobot/extras/models/__init__.py +2 -0
  80. nautobot/extras/models/change_logging.py +2 -2
  81. nautobot/extras/models/customfields.py +2 -2
  82. nautobot/extras/models/models.py +101 -18
  83. nautobot/extras/models/relationships.py +13 -8
  84. nautobot/extras/navigation.py +17 -29
  85. nautobot/extras/signals.py +80 -59
  86. nautobot/extras/tables.py +28 -2
  87. nautobot/extras/templates/extras/externalintegration_retrieve.html +37 -0
  88. nautobot/extras/templates/extras/inc/jobresult.html +24 -0
  89. nautobot/extras/templates/extras/jobresult.html +24 -0
  90. nautobot/extras/templatetags/computed_fields.py +6 -13
  91. nautobot/extras/templatetags/custom_links.py +19 -12
  92. nautobot/extras/templatetags/job_buttons.py +34 -19
  93. nautobot/extras/templatetags/plugins.py +1 -1
  94. nautobot/extras/test_jobs/file_output.py +16 -0
  95. nautobot/extras/tests/test_api.py +92 -0
  96. nautobot/extras/tests/test_context_managers.py +94 -4
  97. nautobot/extras/tests/test_customfields.py +1 -1
  98. nautobot/extras/tests/test_filters.py +64 -2
  99. nautobot/extras/tests/test_jobs.py +75 -22
  100. nautobot/extras/tests/test_models.py +34 -0
  101. nautobot/extras/tests/test_relationships.py +2 -2
  102. nautobot/extras/tests/test_views.py +204 -4
  103. nautobot/extras/tests/test_webhooks.py +61 -25
  104. nautobot/extras/urls.py +1 -0
  105. nautobot/extras/views.py +27 -13
  106. nautobot/extras/webhooks.py +16 -25
  107. nautobot/ipam/fields.py +5 -0
  108. nautobot/ipam/forms.py +16 -0
  109. nautobot/ipam/models.py +13 -2
  110. nautobot/ipam/navigation.py +2 -59
  111. nautobot/ipam/tables.py +1 -1
  112. nautobot/ipam/templates/ipam/ipaddress.html +0 -9
  113. nautobot/ipam/templates/ipam/prefix.html +0 -9
  114. nautobot/ipam/tests/features/prefixes.feature +134 -0
  115. nautobot/ipam/tests/test_filters.py +5 -10
  116. nautobot/ipam/tests/test_models.py +7 -0
  117. nautobot/ipam/tests/test_views.py +8 -1
  118. nautobot/ipam/views.py +99 -58
  119. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css +191 -191
  120. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
  121. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css +1 -1
  122. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
  123. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +874 -881
  124. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
  125. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
  126. nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
  127. nautobot/project-static/css/base.css +138 -99
  128. nautobot/project-static/css/dark.css +65 -6
  129. nautobot/project-static/docs/404.html +45 -17
  130. nautobot/project-static/docs/apps/index.html +45 -17
  131. nautobot/project-static/docs/apps/nautobot-apps.html +45 -17
  132. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +45 -17
  133. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +45 -17
  134. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1598 -1458
  135. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +229 -152
  136. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +46 -18
  137. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +45 -17
  138. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +45 -17
  139. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +45 -17
  140. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +45 -17
  141. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +354 -433
  142. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +67 -39
  143. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +45 -17
  144. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +2083 -2234
  145. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1389 -1247
  146. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +45 -17
  147. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +45 -17
  148. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +129 -111
  149. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +3601 -3457
  150. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +45 -17
  151. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +45 -17
  152. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +320 -284
  153. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +3863 -3801
  154. nautobot/project-static/docs/development/apps/api/configuration-view.html +45 -17
  155. nautobot/project-static/docs/development/apps/api/database-backend-config.html +45 -17
  156. nautobot/project-static/docs/development/apps/api/models/django-admin.html +45 -17
  157. nautobot/project-static/docs/development/apps/api/models/global-search.html +45 -17
  158. nautobot/project-static/docs/development/apps/api/models/graphql.html +45 -17
  159. nautobot/project-static/docs/development/apps/api/models/index.html +45 -17
  160. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +45 -17
  161. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +45 -17
  162. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +45 -17
  163. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +45 -17
  164. nautobot/project-static/docs/development/apps/api/platform-features/index.html +45 -17
  165. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +45 -17
  166. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +45 -17
  167. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +45 -17
  168. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +45 -17
  169. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +45 -17
  170. nautobot/project-static/docs/development/apps/api/prometheus.html +45 -17
  171. nautobot/project-static/docs/development/apps/api/setup.html +45 -17
  172. nautobot/project-static/docs/development/apps/api/testing.html +45 -17
  173. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +45 -17
  174. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +45 -17
  175. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +45 -17
  176. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +45 -17
  177. nautobot/project-static/docs/development/apps/api/ui-extensions/object-detail-views.html +45 -17
  178. nautobot/project-static/docs/development/apps/api/ui-extensions/tabs.html +45 -17
  179. nautobot/project-static/docs/development/apps/api/views/base-template.html +45 -17
  180. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +45 -17
  181. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +45 -17
  182. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +45 -17
  183. nautobot/project-static/docs/development/apps/api/views/index.html +45 -17
  184. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +45 -17
  185. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +45 -17
  186. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +45 -17
  187. nautobot/project-static/docs/development/apps/api/views/notes.html +45 -17
  188. nautobot/project-static/docs/development/apps/api/views/rest-api.html +45 -17
  189. nautobot/project-static/docs/development/apps/api/views/urls.html +45 -17
  190. nautobot/project-static/docs/development/apps/api/views/view-overrides.html +45 -17
  191. nautobot/project-static/docs/development/apps/index.html +45 -17
  192. nautobot/project-static/docs/development/apps/migration/code-updates.html +45 -17
  193. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +45 -17
  194. nautobot/project-static/docs/development/apps/migration/from-v1.html +45 -17
  195. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +45 -17
  196. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +45 -17
  197. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +45 -17
  198. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +45 -17
  199. nautobot/project-static/docs/development/apps/porting-from-netbox.html +45 -17
  200. nautobot/project-static/docs/development/core/application-registry.html +45 -17
  201. nautobot/project-static/docs/development/core/best-practices.html +45 -17
  202. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +45 -17
  203. nautobot/project-static/docs/development/core/extending-models.html +45 -17
  204. nautobot/project-static/docs/development/core/generic-views.html +45 -17
  205. nautobot/project-static/docs/development/core/getting-started.html +45 -17
  206. nautobot/project-static/docs/development/core/homepage.html +45 -17
  207. nautobot/project-static/docs/development/core/index.html +45 -17
  208. nautobot/project-static/docs/development/core/model-features.html +45 -17
  209. nautobot/project-static/docs/development/core/natural-keys.html +45 -17
  210. nautobot/project-static/docs/development/core/navigation-menu.html +45 -22
  211. nautobot/project-static/docs/development/core/react-ui.html +45 -17
  212. nautobot/project-static/docs/development/core/release-checklist.html +46 -18
  213. nautobot/project-static/docs/development/core/role-internals.html +45 -17
  214. nautobot/project-static/docs/development/core/style-guide.html +45 -17
  215. nautobot/project-static/docs/development/core/templates.html +45 -17
  216. nautobot/project-static/docs/development/core/testing.html +45 -17
  217. nautobot/project-static/docs/development/core/user-preferences.html +45 -17
  218. nautobot/project-static/docs/development/index.html +45 -17
  219. nautobot/project-static/docs/development/jobs/index.html +281 -235
  220. nautobot/project-static/docs/development/jobs/migration/from-v1.html +45 -17
  221. nautobot/project-static/docs/index.html +45 -17
  222. nautobot/project-static/docs/media/nautobot_application_stack_low_level.png +0 -0
  223. nautobot/project-static/docs/media/nautobot_application_stack_low_level.txt +1 -0
  224. nautobot/project-static/docs/objects.inv +0 -0
  225. nautobot/project-static/docs/release-notes/index.html +48 -20
  226. nautobot/project-static/docs/release-notes/version-1.0.html +45 -17
  227. nautobot/project-static/docs/release-notes/version-1.1.html +45 -17
  228. nautobot/project-static/docs/release-notes/version-1.2.html +45 -17
  229. nautobot/project-static/docs/release-notes/version-1.3.html +45 -17
  230. nautobot/project-static/docs/release-notes/version-1.4.html +45 -17
  231. nautobot/project-static/docs/release-notes/version-1.5.html +45 -17
  232. nautobot/project-static/docs/release-notes/version-1.6.html +46 -18
  233. nautobot/project-static/docs/release-notes/version-2.0.html +372 -199
  234. nautobot/project-static/docs/release-notes/version-2.1.html +5724 -0
  235. nautobot/project-static/docs/requirements.txt +1 -1
  236. nautobot/project-static/docs/search/search_index.json +1 -1
  237. nautobot/project-static/docs/sitemap.xml +247 -237
  238. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  239. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +45 -17
  240. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +45 -17
  241. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +45 -17
  242. nautobot/project-static/docs/user-guide/administration/configuration/index.html +45 -17
  243. nautobot/project-static/docs/user-guide/administration/configuration/node-configuration.html +45 -17
  244. nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +110 -44
  245. nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +45 -17
  246. nautobot/project-static/docs/user-guide/administration/guides/caching.html +48 -20
  247. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +45 -17
  248. nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +45 -17
  249. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +45 -17
  250. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +45 -17
  251. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +45 -17
  252. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +49 -20
  253. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +45 -17
  254. nautobot/project-static/docs/user-guide/administration/installation/docker.html +45 -17
  255. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +45 -17
  256. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +45 -17
  257. nautobot/project-static/docs/user-guide/administration/installation/index.html +45 -17
  258. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +45 -17
  259. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +45 -17
  260. nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +45 -17
  261. nautobot/project-static/docs/user-guide/administration/installation/services.html +45 -17
  262. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +45 -17
  263. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +45 -17
  264. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +45 -17
  265. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +45 -17
  266. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +45 -17
  267. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +45 -17
  268. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +45 -17
  269. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +45 -17
  270. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +45 -17
  271. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +45 -17
  272. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +45 -17
  273. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +45 -17
  274. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +45 -17
  275. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +45 -17
  276. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +45 -17
  277. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +45 -17
  278. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +45 -17
  279. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +45 -17
  280. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +45 -17
  281. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +45 -17
  282. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +45 -17
  283. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +45 -17
  284. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +45 -17
  285. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +45 -17
  286. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +45 -17
  287. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +45 -17
  288. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +45 -17
  289. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +45 -17
  290. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +45 -17
  291. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +45 -17
  292. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +45 -17
  293. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +45 -17
  294. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +45 -17
  295. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +45 -17
  296. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +45 -17
  297. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +45 -17
  298. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +45 -17
  299. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +45 -17
  300. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +45 -17
  301. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +45 -17
  302. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +45 -17
  303. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +45 -17
  304. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +45 -17
  305. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +45 -17
  306. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +45 -17
  307. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +45 -17
  308. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +45 -17
  309. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +45 -17
  310. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +45 -17
  311. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +45 -17
  312. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +45 -17
  313. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +45 -17
  314. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +45 -17
  315. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +45 -17
  316. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +45 -17
  317. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +45 -17
  318. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +45 -17
  319. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +45 -17
  320. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +45 -17
  321. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +45 -17
  322. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +45 -17
  323. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +45 -17
  324. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +45 -17
  325. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +45 -17
  326. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +45 -17
  327. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +45 -17
  328. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +45 -17
  329. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +45 -17
  330. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +45 -17
  331. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +45 -17
  332. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +45 -17
  333. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +45 -17
  334. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +45 -17
  335. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +45 -17
  336. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +45 -17
  337. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +45 -17
  338. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +45 -17
  339. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +45 -17
  340. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +45 -17
  341. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +45 -17
  342. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +45 -17
  343. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +45 -17
  344. nautobot/project-static/docs/user-guide/index.html +45 -17
  345. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +111 -17
  346. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +45 -17
  347. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +45 -17
  348. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +45 -17
  349. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +45 -17
  350. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +48 -20
  351. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +5359 -0
  352. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +48 -20
  353. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +45 -17
  354. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +45 -17
  355. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +45 -17
  356. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +45 -17
  357. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +45 -17
  358. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +45 -17
  359. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +45 -17
  360. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +45 -17
  361. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +45 -17
  362. nautobot/project-static/docs/user-guide/platform-functionality/note.html +45 -17
  363. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +45 -17
  364. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +45 -17
  365. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +114 -45
  366. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +45 -17
  367. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +45 -17
  368. nautobot/project-static/docs/user-guide/platform-functionality/role.html +45 -17
  369. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +45 -17
  370. nautobot/project-static/docs/user-guide/platform-functionality/status.html +45 -17
  371. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +45 -17
  372. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +45 -17
  373. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +45 -17
  374. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +45 -17
  375. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +45 -17
  376. nautobot/project-static/fonts/UFL.txt +96 -0
  377. nautobot/project-static/fonts/Ubuntu-Bold.woff2 +0 -0
  378. nautobot/project-static/fonts/Ubuntu-BoldItalic.woff2 +0 -0
  379. nautobot/project-static/fonts/Ubuntu-Italic.woff2 +0 -0
  380. nautobot/project-static/fonts/Ubuntu-Medium.woff2 +0 -0
  381. nautobot/project-static/fonts/Ubuntu-MediumItalic.woff2 +0 -0
  382. nautobot/project-static/fonts/Ubuntu-Regular.woff2 +0 -0
  383. nautobot/project-static/fonts/UbuntuMono-Bold.woff2 +0 -0
  384. nautobot/project-static/fonts/UbuntuMono-BoldItalic.woff2 +0 -0
  385. nautobot/project-static/fonts/UbuntuMono-Italic.woff2 +0 -0
  386. nautobot/project-static/fonts/UbuntuMono-Regular.woff2 +0 -0
  387. nautobot/project-static/img/dark-theme.png +0 -0
  388. nautobot/project-static/img/light-theme.png +0 -0
  389. nautobot/project-static/img/nautobot_chevron.svg +5 -0
  390. nautobot/project-static/img/nautobot_chevron_header.svg +5 -0
  391. nautobot/project-static/img/system-theme.png +0 -0
  392. nautobot/tenancy/navigation.py +0 -13
  393. nautobot/ui/package-lock.json +2 -2
  394. nautobot/ui/package.json +1 -1
  395. nautobot/users/admin.py +44 -0
  396. nautobot/users/migrations/0007_alter_objectpermission_object_types.py +33 -0
  397. nautobot/users/models.py +3 -2
  398. nautobot/virtualization/navigation.py +1 -33
  399. nautobot/virtualization/tests/test_api.py +1 -1
  400. nautobot/virtualization/tests/test_filters.py +1 -1
  401. {nautobot-2.0.4.dist-info → nautobot-2.1.0b1.dist-info}/METADATA +2 -2
  402. {nautobot-2.0.4.dist-info → nautobot-2.1.0b1.dist-info}/RECORD +405 -786
  403. CHANGELOG.md +0 -3
  404. CONTRIBUTING.md +0 -3
  405. NOTICE +0 -8
  406. nautobot/docs/apps/index.md +0 -22
  407. nautobot/docs/apps/nautobot-apps.md +0 -10
  408. nautobot/docs/assets/app-icons/icon-ChatOps.png +0 -0
  409. nautobot/docs/assets/app-icons/icon-DataValidationEngine.png +0 -0
  410. nautobot/docs/assets/app-icons/icon-DeviceLifecycle.png +0 -0
  411. nautobot/docs/assets/app-icons/icon-DeviceOnboarding.png +0 -0
  412. nautobot/docs/assets/app-icons/icon-FirewallModels.png +0 -0
  413. nautobot/docs/assets/app-icons/icon-GoldenConfiguration.png +0 -0
  414. nautobot/docs/assets/app-icons/icon-NautobotPluginNornir.png +0 -0
  415. nautobot/docs/assets/app-icons/icon-SSoT.png +0 -0
  416. nautobot/docs/assets/extra.css +0 -139
  417. nautobot/docs/assets/favicon.ico +0 -0
  418. nautobot/docs/assets/nautobot_logo.png +0 -0
  419. nautobot/docs/assets/nautobot_logo.svg +0 -131
  420. nautobot/docs/assets/networktocode_bw.png +0 -0
  421. nautobot/docs/assets/overrides/partials/copyright.html +0 -20
  422. nautobot/docs/development/apps/api/configuration-view.md +0 -35
  423. nautobot/docs/development/apps/api/database-backend-config.md +0 -26
  424. nautobot/docs/development/apps/api/models/django-admin.md +0 -20
  425. nautobot/docs/development/apps/api/models/global-search.md +0 -11
  426. nautobot/docs/development/apps/api/models/graphql.md +0 -97
  427. nautobot/docs/development/apps/api/models/index.md +0 -81
  428. nautobot/docs/development/apps/api/nautobot-app-config.md +0 -84
  429. nautobot/docs/development/apps/api/platform-features/custom-validators.md +0 -30
  430. nautobot/docs/development/apps/api/platform-features/filter-extensions.md +0 -49
  431. nautobot/docs/development/apps/api/platform-features/git-repository-content.md +0 -62
  432. nautobot/docs/development/apps/api/platform-features/index.md +0 -1
  433. nautobot/docs/development/apps/api/platform-features/jinja2-filters.md +0 -28
  434. nautobot/docs/development/apps/api/platform-features/jobs.md +0 -29
  435. nautobot/docs/development/apps/api/platform-features/populating-extensibility-features.md +0 -58
  436. nautobot/docs/development/apps/api/platform-features/secrets-providers.md +0 -64
  437. nautobot/docs/development/apps/api/platform-features/uniquely-identify-objects.md +0 -63
  438. nautobot/docs/development/apps/api/prometheus.md +0 -25
  439. nautobot/docs/development/apps/api/setup.md +0 -132
  440. nautobot/docs/development/apps/api/testing.md +0 -55
  441. nautobot/docs/development/apps/api/ui-extensions/banners.md +0 -26
  442. nautobot/docs/development/apps/api/ui-extensions/home-page.md +0 -9
  443. nautobot/docs/development/apps/api/ui-extensions/index.md +0 -1
  444. nautobot/docs/development/apps/api/ui-extensions/navigation.md +0 -15
  445. nautobot/docs/development/apps/api/ui-extensions/object-detail-views.md +0 -74
  446. nautobot/docs/development/apps/api/ui-extensions/tabs.md +0 -52
  447. nautobot/docs/development/apps/api/views/base-template.md +0 -38
  448. nautobot/docs/development/apps/api/views/core-view-overrides.md +0 -26
  449. nautobot/docs/development/apps/api/views/django-generic-views.md +0 -23
  450. nautobot/docs/development/apps/api/views/help-documentation.md +0 -16
  451. nautobot/docs/development/apps/api/views/index.md +0 -3
  452. nautobot/docs/development/apps/api/views/nautobot-generic-views.md +0 -35
  453. nautobot/docs/development/apps/api/views/nautobotuiviewset.md +0 -147
  454. nautobot/docs/development/apps/api/views/nautobotuiviewsetrouter.md +0 -41
  455. nautobot/docs/development/apps/api/views/notes.md +0 -25
  456. nautobot/docs/development/apps/api/views/rest-api.md +0 -64
  457. nautobot/docs/development/apps/api/views/urls.md +0 -26
  458. nautobot/docs/development/apps/api/views/view-overrides.md +0 -50
  459. nautobot/docs/development/apps/index.md +0 -75
  460. nautobot/docs/development/apps/migration/code-updates.md +0 -160
  461. nautobot/docs/development/apps/migration/dependency-updates.md +0 -13
  462. nautobot/docs/development/apps/migration/from-v1.md +0 -56
  463. nautobot/docs/development/apps/migration/model-updates/dcim.md +0 -285
  464. nautobot/docs/development/apps/migration/model-updates/extras.md +0 -30
  465. nautobot/docs/development/apps/migration/model-updates/global.md +0 -5
  466. nautobot/docs/development/apps/migration/model-updates/ipam.md +0 -22
  467. nautobot/docs/development/apps/porting-from-netbox.md +0 -23
  468. nautobot/docs/development/core/application-registry.md +0 -216
  469. nautobot/docs/development/core/best-practices.md +0 -469
  470. nautobot/docs/development/core/docker-compose-advanced-use-cases.md +0 -228
  471. nautobot/docs/development/core/extending-models.md +0 -93
  472. nautobot/docs/development/core/generic-views.md +0 -65
  473. nautobot/docs/development/core/getting-started.md +0 -859
  474. nautobot/docs/development/core/homepage.md +0 -63
  475. nautobot/docs/development/core/index.md +0 -334
  476. nautobot/docs/development/core/model-features.md +0 -44
  477. nautobot/docs/development/core/natural-keys.md +0 -121
  478. nautobot/docs/development/core/navigation-menu.md +0 -142
  479. nautobot/docs/development/core/react-ui.md +0 -137
  480. nautobot/docs/development/core/release-checklist.md +0 -312
  481. nautobot/docs/development/core/role-internals.md +0 -28
  482. nautobot/docs/development/core/style-guide.md +0 -200
  483. nautobot/docs/development/core/templates.md +0 -101
  484. nautobot/docs/development/core/testing.md +0 -238
  485. nautobot/docs/development/core/user-preferences.md +0 -11
  486. nautobot/docs/development/index.md +0 -1
  487. nautobot/docs/development/jobs/index.md +0 -835
  488. nautobot/docs/development/jobs/migration/from-v1.md +0 -160
  489. nautobot/docs/generate_code_reference_pages.py +0 -20
  490. nautobot/docs/img/edge_dev_circuit_relationship.png +0 -0
  491. nautobot/docs/img/leaf_dev_no_circuit_relationship.png +0 -0
  492. nautobot/docs/img/relationship_w_json_filter.png +0 -0
  493. nautobot/docs/index.md +0 -105
  494. nautobot/docs/media/admin_ui_run_permission.png +0 -0
  495. nautobot/docs/media/development/homepage_changelog_panel.png +0 -0
  496. nautobot/docs/media/development/homepage_dcim_panel.png +0 -0
  497. nautobot/docs/media/development/index_bug_wf.jpg +0 -0
  498. nautobot/docs/media/development/index_feature_request_wf.jpg +0 -0
  499. nautobot/docs/media/development/index_release_cadence.drawio +0 -90
  500. nautobot/docs/media/development/index_release_cadence.jpg +0 -0
  501. nautobot/docs/media/installation/nautobot_ui_admin.png +0 -0
  502. nautobot/docs/media/installation/nautobot_ui_guest.png +0 -0
  503. nautobot/docs/media/models/dcim_cable_trace.png +0 -0
  504. nautobot/docs/media/models/dcim_cable_trace_circuit.png +0 -0
  505. nautobot/docs/media/models/dynamicgroup_filtering_01.png +0 -0
  506. nautobot/docs/media/models/dynamicgroup_workflow_advanced_1_01.png +0 -0
  507. nautobot/docs/media/models/dynamicgroup_workflow_advanced_1_02.png +0 -0
  508. nautobot/docs/media/models/dynamicgroup_workflow_advanced_1_03.png +0 -0
  509. nautobot/docs/media/models/dynamicgroup_workflow_advanced_1_04.png +0 -0
  510. nautobot/docs/media/models/dynamicgroup_workflow_advanced_1_05.png +0 -0
  511. nautobot/docs/media/models/dynamicgroup_workflow_advanced_2_01.png +0 -0
  512. nautobot/docs/media/models/dynamicgroup_workflow_advanced_2_02.png +0 -0
  513. nautobot/docs/media/models/dynamicgroup_workflow_advanced_2_03.png +0 -0
  514. nautobot/docs/media/models/dynamicgroup_workflow_advanced_2_04.png +0 -0
  515. nautobot/docs/media/models/dynamicgroup_workflow_advanced_2_05.png +0 -0
  516. nautobot/docs/media/models/dynamicgroup_workflow_advanced_2_06.png +0 -0
  517. nautobot/docs/media/models/dynamicgroup_workflow_advanced_2_07.png +0 -0
  518. nautobot/docs/media/models/dynamicgroup_workflow_basic_01.png +0 -0
  519. nautobot/docs/media/models/dynamicgroup_workflow_basic_02.png +0 -0
  520. nautobot/docs/media/models/dynamicgroup_workflow_basic_03.png +0 -0
  521. nautobot/docs/media/models/jobbutton_form.png +0 -0
  522. nautobot/docs/media/models/site_jobbuttons.png +0 -0
  523. nautobot/docs/media/nautobot_application_stack_high_level.drawio +0 -1
  524. nautobot/docs/media/nautobot_application_stack_high_level.png +0 -0
  525. nautobot/docs/media/nautobot_application_stack_low_level.drawio +0 -1
  526. nautobot/docs/media/nautobot_application_stack_low_level.png +0 -0
  527. nautobot/docs/media/nautobot_chatops.gif +0 -0
  528. nautobot/docs/media/nautobot_config_context.gif +0 -0
  529. nautobot/docs/media/nautobot_golden_config.gif +0 -0
  530. nautobot/docs/media/nautobot_graphql.gif +0 -0
  531. nautobot/docs/media/nautobot_mainpage.gif +0 -0
  532. nautobot/docs/media/nautobot_prefix_hierarchy.gif +0 -0
  533. nautobot/docs/media/plugins/plugin_admin_config.png +0 -0
  534. nautobot/docs/media/plugins/plugin_admin_ui.png +0 -0
  535. nautobot/docs/media/plugins/plugin_rest_api_endpoint.png +0 -0
  536. nautobot/docs/media/power_distribution.png +0 -0
  537. nautobot/docs/media/ss_config_contexts.png +0 -0
  538. nautobot/docs/media/ss_graphiql.png +0 -0
  539. nautobot/docs/media/ss_main_page.png +0 -0
  540. nautobot/docs/media/ss_plugin_chatops.png +0 -0
  541. nautobot/docs/media/ss_plugin_golden_config.png +0 -0
  542. nautobot/docs/media/ss_prefix_hierarchy.png +0 -0
  543. nautobot/docs/media/user-guide/administration/guides/s3-django-storage/user-guide-s3-1.png +0 -0
  544. nautobot/docs/media/user-guide/administration/guides/s3-django-storage/user-guide-s3-2.png +0 -0
  545. nautobot/docs/media/user-guide/administration/upgrading/from-v1/ipam/tenant-affinity.png +0 -0
  546. nautobot/docs/nautobot_logo.png +0 -0
  547. nautobot/docs/nautobot_logo.svg +0 -131
  548. nautobot/docs/release-notes/index.md +0 -3
  549. nautobot/docs/release-notes/version-1.0.md +0 -530
  550. nautobot/docs/release-notes/version-1.1.md +0 -337
  551. nautobot/docs/release-notes/version-1.2.md +0 -509
  552. nautobot/docs/release-notes/version-1.3.md +0 -554
  553. nautobot/docs/release-notes/version-1.4.md +0 -677
  554. nautobot/docs/release-notes/version-1.5.md +0 -840
  555. nautobot/docs/release-notes/version-1.6.md +0 -290
  556. nautobot/docs/release-notes/version-2.0.md +0 -1359
  557. nautobot/docs/requirements.txt +0 -12
  558. nautobot/docs/user-guide/administration/configuration/authentication/ldap.md +0 -286
  559. nautobot/docs/user-guide/administration/configuration/authentication/remote.md +0 -46
  560. nautobot/docs/user-guide/administration/configuration/authentication/sso.md +0 -528
  561. nautobot/docs/user-guide/administration/configuration/index.md +0 -190
  562. nautobot/docs/user-guide/administration/configuration/node-configuration.md +0 -31
  563. nautobot/docs/user-guide/administration/configuration/optional-settings.md +0 -1302
  564. nautobot/docs/user-guide/administration/configuration/required-settings.md +0 -244
  565. nautobot/docs/user-guide/administration/guides/caching.md +0 -108
  566. nautobot/docs/user-guide/administration/guides/celery-queues.md +0 -42
  567. nautobot/docs/user-guide/administration/guides/healthcheck.md +0 -11
  568. nautobot/docs/user-guide/administration/guides/permissions.md +0 -98
  569. nautobot/docs/user-guide/administration/guides/prometheus-metrics.md +0 -55
  570. nautobot/docs/user-guide/administration/guides/replicating-nautobot.md +0 -70
  571. nautobot/docs/user-guide/administration/guides/s3-django-storage.md +0 -145
  572. nautobot/docs/user-guide/administration/installation/app-install.md +0 -94
  573. nautobot/docs/user-guide/administration/installation/docker.md +0 -286
  574. nautobot/docs/user-guide/administration/installation/external-authentication.md +0 -9
  575. nautobot/docs/user-guide/administration/installation/http-server.md +0 -279
  576. nautobot/docs/user-guide/administration/installation/index.md +0 -101
  577. nautobot/docs/user-guide/administration/installation/install_system.md +0 -493
  578. nautobot/docs/user-guide/administration/installation/nautobot.md +0 -367
  579. nautobot/docs/user-guide/administration/installation/selinux-troubleshooting.md +0 -194
  580. nautobot/docs/user-guide/administration/installation/services.md +0 -340
  581. nautobot/docs/user-guide/administration/migration/migrating-from-netbox.md +0 -336
  582. nautobot/docs/user-guide/administration/migration/migrating-from-postgresql.md +0 -122
  583. nautobot/docs/user-guide/administration/tools/nautobot-server.md +0 -858
  584. nautobot/docs/user-guide/administration/tools/nautobot-shell.md +0 -263
  585. nautobot/docs/user-guide/administration/upgrading/database-backup.md +0 -11
  586. nautobot/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.md +0 -55
  587. nautobot/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.md +0 -73
  588. nautobot/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.md +0 -211
  589. nautobot/docs/user-guide/administration/upgrading/from-v1/ipam/index.md +0 -16
  590. nautobot/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.md +0 -157
  591. nautobot/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.md +0 -153
  592. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-api-behavior-changes.yaml +0 -82
  593. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-api-removed-fields.yaml +0 -175
  594. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-api-renamed-fields.yaml +0 -124
  595. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-location-changes.yaml +0 -241
  596. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-removals.yaml +0 -57
  597. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-renames.yaml +0 -5
  598. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-database-behavior-changes.yaml +0 -76
  599. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-database-removed-fields.yaml +0 -202
  600. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-database-renamed-fields.yaml +0 -343
  601. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-filters-corrected-fields.yaml +0 -31
  602. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-filters-enhanced-fields.yaml +0 -244
  603. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-filters-removed-fields.yaml +0 -595
  604. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-filters-renamed-fields.yaml +0 -253
  605. nautobot/docs/user-guide/administration/upgrading/from-v1/tables/v2-logging-renamed-loggers.yaml +0 -23
  606. nautobot/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.md +0 -574
  607. nautobot/docs/user-guide/administration/upgrading/upgrading.md +0 -127
  608. nautobot/docs/user-guide/core-data-model/circuits/circuit.md +0 -19
  609. nautobot/docs/user-guide/core-data-model/circuits/circuittermination.md +0 -10
  610. nautobot/docs/user-guide/core-data-model/circuits/circuittype.md +0 -8
  611. nautobot/docs/user-guide/core-data-model/circuits/provider.md +0 -5
  612. nautobot/docs/user-guide/core-data-model/circuits/providernetwork.md +0 -7
  613. nautobot/docs/user-guide/core-data-model/dcim/cable.md +0 -43
  614. nautobot/docs/user-guide/core-data-model/dcim/consoleport.md +0 -8
  615. nautobot/docs/user-guide/core-data-model/dcim/consoleporttemplate.md +0 -6
  616. nautobot/docs/user-guide/core-data-model/dcim/consoleserverport.md +0 -8
  617. nautobot/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.md +0 -6
  618. nautobot/docs/user-guide/core-data-model/dcim/device.md +0 -29
  619. nautobot/docs/user-guide/core-data-model/dcim/devicebay.md +0 -11
  620. nautobot/docs/user-guide/core-data-model/dcim/devicebaytemplate.md +0 -6
  621. nautobot/docs/user-guide/core-data-model/dcim/deviceredundancygroup.md +0 -279
  622. nautobot/docs/user-guide/core-data-model/dcim/devicetype.md +0 -44
  623. nautobot/docs/user-guide/core-data-model/dcim/frontport.md +0 -6
  624. nautobot/docs/user-guide/core-data-model/dcim/frontporttemplate.md +0 -6
  625. nautobot/docs/user-guide/core-data-model/dcim/interface.md +0 -34
  626. nautobot/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.md +0 -24
  627. nautobot/docs/user-guide/core-data-model/dcim/interfacetemplate.md +0 -6
  628. nautobot/docs/user-guide/core-data-model/dcim/inventoryitem.md +0 -10
  629. nautobot/docs/user-guide/core-data-model/dcim/location.md +0 -15
  630. nautobot/docs/user-guide/core-data-model/dcim/locationtype.md +0 -43
  631. nautobot/docs/user-guide/core-data-model/dcim/manufacturer.md +0 -3
  632. nautobot/docs/user-guide/core-data-model/dcim/platform.md +0 -19
  633. nautobot/docs/user-guide/core-data-model/dcim/powerfeed.md +0 -25
  634. nautobot/docs/user-guide/core-data-model/dcim/poweroutlet.md +0 -14
  635. nautobot/docs/user-guide/core-data-model/dcim/poweroutlettemplate.md +0 -6
  636. nautobot/docs/user-guide/core-data-model/dcim/powerpanel.md +0 -12
  637. nautobot/docs/user-guide/core-data-model/dcim/powerport.md +0 -15
  638. nautobot/docs/user-guide/core-data-model/dcim/powerporttemplate.md +0 -6
  639. nautobot/docs/user-guide/core-data-model/dcim/rack.md +0 -41
  640. nautobot/docs/user-guide/core-data-model/dcim/rackgroup.md +0 -7
  641. nautobot/docs/user-guide/core-data-model/dcim/rackreservation.md +0 -3
  642. nautobot/docs/user-guide/core-data-model/dcim/rearport.md +0 -9
  643. nautobot/docs/user-guide/core-data-model/dcim/rearporttemplate.md +0 -6
  644. nautobot/docs/user-guide/core-data-model/dcim/virtualchassis.md +0 -8
  645. nautobot/docs/user-guide/core-data-model/extras/configcontext.md +0 -78
  646. nautobot/docs/user-guide/core-data-model/extras/configcontextschema.md +0 -73
  647. nautobot/docs/user-guide/core-data-model/ipam/ipaddress.md +0 -69
  648. nautobot/docs/user-guide/core-data-model/ipam/media/ipam_namespace_documentation.drawio +0 -1
  649. nautobot/docs/user-guide/core-data-model/ipam/media/ipam_namespace_documentation.drawio.svg +0 -4
  650. nautobot/docs/user-guide/core-data-model/ipam/namespace.md +0 -18
  651. nautobot/docs/user-guide/core-data-model/ipam/prefix.md +0 -65
  652. nautobot/docs/user-guide/core-data-model/ipam/rir.md +0 -10
  653. nautobot/docs/user-guide/core-data-model/ipam/routetarget.md +0 -5
  654. nautobot/docs/user-guide/core-data-model/ipam/service.md +0 -8
  655. nautobot/docs/user-guide/core-data-model/ipam/vlan.md +0 -17
  656. nautobot/docs/user-guide/core-data-model/ipam/vlangroup.md +0 -5
  657. nautobot/docs/user-guide/core-data-model/ipam/vrf.md +0 -15
  658. nautobot/docs/user-guide/core-data-model/tenancy/tenant.md +0 -20
  659. nautobot/docs/user-guide/core-data-model/tenancy/tenantgroup.md +0 -5
  660. nautobot/docs/user-guide/core-data-model/virtualization/cluster.md +0 -5
  661. nautobot/docs/user-guide/core-data-model/virtualization/clustergroup.md +0 -3
  662. nautobot/docs/user-guide/core-data-model/virtualization/clustertype.md +0 -3
  663. nautobot/docs/user-guide/core-data-model/virtualization/virtualmachine.md +0 -17
  664. nautobot/docs/user-guide/core-data-model/virtualization/vminterface.md +0 -19
  665. nautobot/docs/user-guide/feature-guides/custom-fields.md +0 -350
  666. nautobot/docs/user-guide/feature-guides/getting-started/creating-devices.md +0 -130
  667. nautobot/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.md +0 -113
  668. nautobot/docs/user-guide/feature-guides/getting-started/index.md +0 -29
  669. nautobot/docs/user-guide/feature-guides/getting-started/interfaces.md +0 -100
  670. nautobot/docs/user-guide/feature-guides/getting-started/ipam.md +0 -104
  671. nautobot/docs/user-guide/feature-guides/getting-started/platforms.md +0 -78
  672. nautobot/docs/user-guide/feature-guides/getting-started/search-bar.md +0 -40
  673. nautobot/docs/user-guide/feature-guides/getting-started/tenants.md +0 -40
  674. nautobot/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.md +0 -87
  675. nautobot/docs/user-guide/feature-guides/git-data-source.md +0 -307
  676. nautobot/docs/user-guide/feature-guides/graphql.md +0 -342
  677. nautobot/docs/user-guide/feature-guides/images/custom-fields/custom_field_choices.png +0 -0
  678. nautobot/docs/user-guide/feature-guides/images/custom-fields/custom_field_detail_grouped.png +0 -0
  679. nautobot/docs/user-guide/feature-guides/images/custom-fields/custom_field_detail_label.png +0 -0
  680. nautobot/docs/user-guide/feature-guides/images/custom-fields/custom_field_edit.png +0 -0
  681. nautobot/docs/user-guide/feature-guides/images/custom-fields/custom_field_select.png +0 -0
  682. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/1-create-location-type.png +0 -0
  683. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/10-add-platform.png +0 -0
  684. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/11-platforms-page.png +0 -0
  685. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/12-add-tenant.png +0 -0
  686. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/13-assign-tenant-to-device.png +0 -0
  687. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/14-assign-tenant-to-device-2.png +0 -0
  688. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/15-create-device-type.png +0 -0
  689. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/16-interface-templates.png +0 -0
  690. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/17-templated-interfaces.png +0 -0
  691. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/18-assign-device-type.png +0 -0
  692. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/19-edit-ints-for-lag.png +0 -0
  693. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/2-create-manufacturer.png +0 -0
  694. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/20-ints-int-lag.png +0 -0
  695. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/21-device-type.png +0 -0
  696. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/22-create-vlans.png +0 -0
  697. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/23-create-vlans-2.png +0 -0
  698. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/24-vlan-main-page.png +0 -0
  699. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/25-add-vlan-to-interface.png +0 -0
  700. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/26-add-vlan-to-interface-2.png +0 -0
  701. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/27-add-rir.png +0 -0
  702. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/3-create-role.png +0 -0
  703. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/30-add-prefix.png +0 -0
  704. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/32-add-ip-addr.png +0 -0
  705. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/33-assign-address.png +0 -0
  706. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/34-assign-address-2.png +0 -0
  707. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/35-assign-address-3.png +0 -0
  708. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/36-verify-address.png +0 -0
  709. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/37-verify-prefix.png +0 -0
  710. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/38-verify-prefix2.png +0 -0
  711. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/39-address-search.png +0 -0
  712. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/4-create-device-type.png +0 -0
  713. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/40-addr-main-page.png +0 -0
  714. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/41-device-search-results.png +0 -0
  715. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/42-address-search-v2.png +0 -0
  716. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/43-get-to-device-main-page.png +0 -0
  717. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/44-add-platform.png +0 -0
  718. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/5-create-device.png +0 -0
  719. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/6-create-location.png +0 -0
  720. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/7-location-type-page.png +0 -0
  721. nautobot/docs/user-guide/feature-guides/images/getting-started-nautobot-ui/8-location-page.png +0 -0
  722. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/01-git-data-source.png +0 -0
  723. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/02-git-data-source.png +0 -0
  724. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/03-git-data-source.png +0 -0
  725. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/04-git-data-source.png +0 -0
  726. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/05-git-data-source.png +0 -0
  727. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/06-git-data-source.png +0 -0
  728. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/07-git-data-source.png +0 -0
  729. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/08-git-data-source.png +0 -0
  730. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/09-git-data-source.png +0 -0
  731. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/10-git-data-source.png +0 -0
  732. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/11-git-data-source.png +0 -0
  733. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/12-git-data-source.png +0 -0
  734. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/13-git-data-source.png +0 -0
  735. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/14-git-data-source.png +0 -0
  736. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/15-git-data-source.png +0 -0
  737. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/16-git-data-source.png +0 -0
  738. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/17-git-data-source.png +0 -0
  739. nautobot/docs/user-guide/feature-guides/images/git-as-data-source/18-git-data-source.png +0 -0
  740. nautobot/docs/user-guide/feature-guides/images/graphql/00-graphiql.png +0 -0
  741. nautobot/docs/user-guide/feature-guides/images/graphql/01-graphiql-explorer.png +0 -0
  742. nautobot/docs/user-guide/feature-guides/images/graphql/02-graphiql-explorer-device-query.png +0 -0
  743. nautobot/docs/user-guide/feature-guides/images/graphql/03-graphiql-explorer-device-attributes.png +0 -0
  744. nautobot/docs/user-guide/feature-guides/images/graphql/04-graphql-query-01.png +0 -0
  745. nautobot/docs/user-guide/feature-guides/images/graphql/05-graphiql-autocomplete.png +0 -0
  746. nautobot/docs/user-guide/feature-guides/images/graphql/06-graphql-query-02.png +0 -0
  747. nautobot/docs/user-guide/feature-guides/images/graphql/07-graphql-query-03.png +0 -0
  748. nautobot/docs/user-guide/feature-guides/images/graphql/08-graphql-query-04.png +0 -0
  749. nautobot/docs/user-guide/feature-guides/images/graphql/09-graphql-query-05.png +0 -0
  750. nautobot/docs/user-guide/feature-guides/images/graphql/10-graphql-swagger.png +0 -0
  751. nautobot/docs/user-guide/feature-guides/images/graphql/11-graphql-query-06.png +0 -0
  752. nautobot/docs/user-guide/feature-guides/images/ip-address-merge-tool/ip_merge_button.png +0 -0
  753. nautobot/docs/user-guide/feature-guides/images/ip-address-merge-tool/merge_button.png +0 -0
  754. nautobot/docs/user-guide/feature-guides/images/ip-address-merge-tool/merge_view.png +0 -0
  755. nautobot/docs/user-guide/feature-guides/images/ip-address-merge-tool/no_more_dup_ips.png +0 -0
  756. nautobot/docs/user-guide/feature-guides/images/ip-address-merge-tool/skip_button.png +0 -0
  757. nautobot/docs/user-guide/feature-guides/images/ip-address-merge-tool/unselect_ips.png +0 -0
  758. nautobot/docs/user-guide/feature-guides/images/relationships/01-relationships.png +0 -0
  759. nautobot/docs/user-guide/feature-guides/images/relationships/02-relationships.png +0 -0
  760. nautobot/docs/user-guide/feature-guides/images/relationships/03-relationships.png +0 -0
  761. nautobot/docs/user-guide/feature-guides/images/relationships/04-relationships.png +0 -0
  762. nautobot/docs/user-guide/feature-guides/images/relationships/05-relationships.png +0 -0
  763. nautobot/docs/user-guide/feature-guides/images/relationships/06-relationships.png +0 -0
  764. nautobot/docs/user-guide/feature-guides/images/relationships/07-relationships.png +0 -0
  765. nautobot/docs/user-guide/feature-guides/images/relationships/08-relationships.png +0 -0
  766. nautobot/docs/user-guide/feature-guides/images/relationships/09-relationships.png +0 -0
  767. nautobot/docs/user-guide/feature-guides/images/relationships/10-relationships.png +0 -0
  768. nautobot/docs/user-guide/feature-guides/images/relationships/11-relationships.png +0 -0
  769. nautobot/docs/user-guide/feature-guides/ip-address-merge-tool.md +0 -63
  770. nautobot/docs/user-guide/feature-guides/relationships.md +0 -125
  771. nautobot/docs/user-guide/index.md +0 -1
  772. nautobot/docs/user-guide/platform-functionality/change-logging.md +0 -21
  773. nautobot/docs/user-guide/platform-functionality/computedfield.md +0 -89
  774. nautobot/docs/user-guide/platform-functionality/customfield.md +0 -123
  775. nautobot/docs/user-guide/platform-functionality/customlink.md +0 -59
  776. nautobot/docs/user-guide/platform-functionality/dynamicgroup.md +0 -660
  777. nautobot/docs/user-guide/platform-functionality/exporttemplate.md +0 -55
  778. nautobot/docs/user-guide/platform-functionality/gitrepository.md +0 -353
  779. nautobot/docs/user-guide/platform-functionality/graphql.md +0 -259
  780. nautobot/docs/user-guide/platform-functionality/graphqlquery.md +0 -28
  781. nautobot/docs/user-guide/platform-functionality/imageattachment.md +0 -10
  782. nautobot/docs/user-guide/platform-functionality/jobs/index.md +0 -193
  783. nautobot/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.md +0 -78
  784. nautobot/docs/user-guide/platform-functionality/jobs/jobbutton.md +0 -79
  785. nautobot/docs/user-guide/platform-functionality/jobs/jobhook.md +0 -15
  786. nautobot/docs/user-guide/platform-functionality/jobs/models.md +0 -65
  787. nautobot/docs/user-guide/platform-functionality/napalm.md +0 -85
  788. nautobot/docs/user-guide/platform-functionality/note.md +0 -7
  789. nautobot/docs/user-guide/platform-functionality/relationship.md +0 -158
  790. nautobot/docs/user-guide/platform-functionality/rest-api/authentication.md +0 -67
  791. nautobot/docs/user-guide/platform-functionality/rest-api/filtering.md +0 -142
  792. nautobot/docs/user-guide/platform-functionality/rest-api/overview.md +0 -1045
  793. nautobot/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.md +0 -9
  794. nautobot/docs/user-guide/platform-functionality/role.md +0 -17
  795. nautobot/docs/user-guide/platform-functionality/secret.md +0 -136
  796. nautobot/docs/user-guide/platform-functionality/status.md +0 -92
  797. nautobot/docs/user-guide/platform-functionality/tag.md +0 -62
  798. nautobot/docs/user-guide/platform-functionality/template-filters.md +0 -306
  799. nautobot/docs/user-guide/platform-functionality/users/objectpermission.md +0 -56
  800. nautobot/docs/user-guide/platform-functionality/users/token.md +0 -21
  801. nautobot/docs/user-guide/platform-functionality/webhook.md +0 -137
  802. nautobot/project-static/docs/media/nautobot_application_stack_low_level.drawio +0 -1
  803. nautobot/project-static/docs/media/nautobot_chatops.gif +0 -0
  804. nautobot/project-static/docs/media/nautobot_config_context.gif +0 -0
  805. nautobot/project-static/docs/media/nautobot_golden_config.gif +0 -0
  806. nautobot/project-static/docs/media/nautobot_graphql.gif +0 -0
  807. nautobot/project-static/docs/media/nautobot_mainpage.gif +0 -0
  808. nautobot/project-static/docs/media/nautobot_prefix_hierarchy.gif +0 -0
  809. nautobot-2.0.4.dist-info/LICENSE.txt +0 -177
  810. /LICENSE.txt → /nautobot-2.1.0b1.dist-info/LICENSE.txt +0 -0
  811. {nautobot-2.0.4.dist-info → nautobot-2.1.0b1.dist-info}/WHEEL +0 -0
  812. {nautobot-2.0.4.dist-info → nautobot-2.1.0b1.dist-info}/entry_points.txt +0 -0
@@ -442,58 +442,61 @@ class LookupRelatedFunctionTest(TestCase):
442
442
  location_fields = ["comments", "name", "contact_email", "physical_address", "shipping_address"]
443
443
  for field_name in location_fields:
444
444
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Location, field_name)
445
- self.assertIsInstance(form_field, django_forms.CharField)
445
+ self.assertIs(type(form_field), forms.MultiValueCharField)
446
446
 
447
447
  device_fields = ["serial", "name"]
448
448
  for field_name in device_fields:
449
449
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Device, field_name)
450
- self.assertIsInstance(form_field, django_forms.CharField)
450
+ self.assertIs(type(form_field), forms.MultiValueCharField)
451
451
 
452
452
  with self.subTest("Test IntegerField"):
453
453
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Location, "asn")
454
- self.assertIsInstance(form_field, django_forms.IntegerField)
454
+ self.assertIs(type(form_field), django_forms.IntegerField)
455
455
 
456
456
  device_fields = ["vc_position", "vc_priority"]
457
457
  for field_name in device_fields:
458
458
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Device, field_name)
459
- self.assertIsInstance(form_field, django_forms.IntegerField)
459
+ self.assertIs(type(form_field), django_forms.IntegerField)
460
460
 
461
461
  with self.subTest("Test DynamicModelMultipleChoiceField"):
462
462
  location_fields = ["tenant", "status"]
463
463
  for field_name in location_fields:
464
464
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Location, field_name)
465
- self.assertIsInstance(form_field, forms.DynamicModelMultipleChoiceField)
465
+ self.assertIs(type(form_field), forms.DynamicModelMultipleChoiceField)
466
466
 
467
467
  device_fields = ["cluster", "device_type", "location"]
468
468
  for field_name in device_fields:
469
469
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Device, field_name)
470
- self.assertIsInstance(form_field, forms.DynamicModelMultipleChoiceField)
470
+ self.assertIs(type(form_field), forms.DynamicModelMultipleChoiceField)
471
471
 
472
- with self.subTest("Test NullBooleanField"):
473
472
  location_fields = ["has_circuit_terminations", "has_devices"]
474
473
  for field_name in location_fields:
475
- form_field = filtering.get_filterset_parameter_form_field(dcim_models.Location, field_name)
476
- self.assertIsInstance(form_field, django_forms.NullBooleanField)
474
+ with self.subTest("Test ChoiceField", model=dcim_models.Location, field_name=field_name):
475
+ form_field = filtering.get_filterset_parameter_form_field(dcim_models.Location, field_name)
476
+ self.assertIs(type(form_field), django_forms.ChoiceField)
477
+ self.assertIs(type(form_field.widget), forms.StaticSelect2)
477
478
 
478
- device_fields = ["has_console_ports", "has_interfaces"]
479
+ device_fields = ["has_console_ports", "has_interfaces", "local_config_context_data"]
479
480
  for field_name in device_fields:
480
- form_field = filtering.get_filterset_parameter_form_field(dcim_models.Device, field_name)
481
- self.assertIsInstance(form_field, django_forms.NullBooleanField)
481
+ with self.subTest("Test ChoiceField", model=dcim_models.Device, field_name=field_name):
482
+ form_field = filtering.get_filterset_parameter_form_field(dcim_models.Device, field_name)
483
+ self.assertIs(type(form_field), django_forms.ChoiceField)
484
+ self.assertIs(type(form_field.widget), forms.StaticSelect2)
482
485
 
483
- with self.subTest("Test ChoiceField"):
486
+ with self.subTest("Test MultipleChoiceField"):
484
487
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Device, "face")
485
- self.assertIsInstance(form_field, django_forms.ChoiceField)
488
+ self.assertIs(type(form_field), django_forms.MultipleChoiceField)
486
489
 
487
490
  with self.subTest("Test DateTimePicker"):
488
491
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Location, "last_updated")
489
- self.assertIsInstance(form_field.widget, forms.DateTimePicker)
492
+ self.assertIs(type(form_field.widget), forms.DateTimePicker)
490
493
 
491
494
  form_field = filtering.get_filterset_parameter_form_field(dcim_models.Device, "last_updated")
492
- self.assertIsInstance(form_field.widget, forms.DateTimePicker)
495
+ self.assertIs(type(form_field.widget), forms.DateTimePicker)
493
496
 
494
497
  with self.subTest("Test DatePicker"):
495
498
  form_field = filtering.get_filterset_parameter_form_field(circuits_models.Circuit, "install_date")
496
- self.assertIsInstance(form_field.widget, forms.DatePicker)
499
+ self.assertIs(type(form_field.widget), forms.DatePicker)
497
500
 
498
501
  with self.subTest("Test Invalid parameter"):
499
502
  with self.assertRaises(exceptions.FilterSetFieldNotFound) as err:
@@ -502,15 +505,15 @@ class LookupRelatedFunctionTest(TestCase):
502
505
 
503
506
  with self.subTest("Test Content types"):
504
507
  form_field = filtering.get_filterset_parameter_form_field(extras_models.Status, "content_types")
505
- self.assertIsInstance(form_field, forms.MultipleContentTypeField)
508
+ self.assertIs(type(form_field), forms.MultipleContentTypeField)
506
509
 
507
510
  # Assert total ContentTypes generated by form_field is == total `content_types` generated by TaggableClassesQuery
508
511
  form_field = filtering.get_filterset_parameter_form_field(extras_models.Tag, "content_types")
509
- self.assertIsInstance(form_field, forms.MultipleContentTypeField)
512
+ self.assertIs(type(form_field), forms.MultipleContentTypeField)
510
513
  self.assertEqual(form_field.queryset.count(), extras_utils.TaggableClassesQuery().as_queryset().count())
511
514
 
512
515
  form_field = filtering.get_filterset_parameter_form_field(extras_models.JobHook, "content_types")
513
- self.assertIsInstance(form_field, forms.MultipleContentTypeField)
516
+ self.assertIs(type(form_field), forms.MultipleContentTypeField)
514
517
  self.assertEqual(form_field.queryset.count(), extras_utils.ChangeLoggedModelsQuery().as_queryset().count())
515
518
 
516
519
  def test_convert_querydict_to_factory_formset_dict(self):
@@ -37,7 +37,7 @@ class HomeViewTestCase(TestCase):
37
37
 
38
38
  # Search bar in nav
39
39
  nav_search_bar_pattern = re.compile(
40
- '<nav.*<form action="/search/" method="get" class="navbar-form navbar-right" id="navbar_search" role="search">.*</form>.*</nav>'
40
+ '<nav.*<form action="/search/" method="get" class="navbar-form" id="navbar_search" role="search">.*</form>.*</nav>'
41
41
  )
42
42
  nav_search_bar_result = nav_search_bar_pattern.search(
43
43
  response.content.decode(response.charset).replace("\n", "")
@@ -53,8 +53,7 @@ class HomeViewTestCase(TestCase):
53
53
 
54
54
  return nav_search_bar_result, body_search_bar_result
55
55
 
56
- @override_settings(HIDE_RESTRICTED_UI=True)
57
- def test_search_bar_not_visible_if_user_not_authenticated_and_hide_restricted_ui_True(self):
56
+ def test_search_bar_not_visible_if_user_not_authenticated(self):
58
57
  self.client.logout()
59
58
 
60
59
  nav_search_bar_result, body_search_bar_result = self.make_request()
@@ -62,23 +61,7 @@ class HomeViewTestCase(TestCase):
62
61
  self.assertIsNone(nav_search_bar_result)
63
62
  self.assertIsNone(body_search_bar_result)
64
63
 
65
- @override_settings(HIDE_RESTRICTED_UI=False)
66
- def test_search_bar_visible_if_user_authenticated_and_hide_restricted_ui_True(self):
67
- nav_search_bar_result, body_search_bar_result = self.make_request()
68
-
69
- self.assertIsNotNone(nav_search_bar_result)
70
- self.assertIsNotNone(body_search_bar_result)
71
-
72
- @override_settings(HIDE_RESTRICTED_UI=False)
73
- def test_search_bar_visible_if_hide_restricted_ui_False(self):
74
- # Assert if user is authenticated
75
- nav_search_bar_result, body_search_bar_result = self.make_request()
76
-
77
- self.assertIsNotNone(nav_search_bar_result)
78
- self.assertIsNotNone(body_search_bar_result)
79
-
80
- # Assert if user is logout
81
- self.client.logout()
64
+ def test_search_bar_visible_if_user_authenticated(self):
82
65
  nav_search_bar_result, body_search_bar_result = self.make_request()
83
66
 
84
67
  self.assertIsNotNone(nav_search_bar_result)
@@ -229,27 +212,8 @@ class NavRestrictedUI(TestCase):
229
212
  response = self.client.get(reverse("home"))
230
213
  return response.content.decode(response.charset)
231
214
 
232
- @override_settings(HIDE_RESTRICTED_UI=True)
233
- def test_installed_apps_visible_to_staff_with_hide_restricted_ui_true(self):
234
- """The "Installed Apps" menu item should be available to is_staff user regardless of HIDE_RESTRICTED_UI."""
235
- # Make user admin
236
- self.user.is_staff = True
237
- self.user.save()
238
-
239
- response_content = self.make_request()
240
- self.assertInHTML(
241
- f"""
242
- <a href="{self.url}"
243
- data-item-weight="{self.item_weight}">
244
- Installed Plugins
245
- </a>
246
- """,
247
- response_content,
248
- )
249
-
250
- @override_settings(HIDE_RESTRICTED_UI=False)
251
- def test_installed_apps_visible_to_staff_with_hide_restricted_ui_false(self):
252
- """The "Installed Apps" menu item should be available to is_staff user regardless of HIDE_RESTRICTED_UI."""
215
+ def test_installed_apps_visible_to_staff(self):
216
+ """The "Installed Apps" menu item should be available to is_staff user."""
253
217
  # Make user admin
254
218
  self.user.is_staff = True
255
219
  self.user.save()
@@ -265,29 +229,11 @@ class NavRestrictedUI(TestCase):
265
229
  response_content,
266
230
  )
267
231
 
268
- @override_settings(HIDE_RESTRICTED_UI=True)
269
- def test_installed_apps_not_visible_to_non_staff_user_with_hide_restricted_ui_true(self):
270
- """The "Installed Apps" menu item should be hidden from a non-staff user when HIDE_RESTRICTED_UI=True."""
271
- response_content = self.make_request()
272
-
273
- self.assertNotRegex(response_content, r"Installed\s+Apps")
274
-
275
- @override_settings(HIDE_RESTRICTED_UI=False)
276
- def test_installed_apps_disabled_to_non_staff_user_with_hide_restricted_ui_false(self):
277
- """The "Installed Apps" menu item should be disabled for a non-staff user when HIDE_RESTRICTED_UI=False."""
232
+ def test_installed_apps_not_visible_to_non_staff_user_without_permission(self):
233
+ """The "Installed Apps" menu item should be hidden from a non-staff user without permission."""
278
234
  response_content = self.make_request()
279
235
 
280
- # print(response_content)
281
-
282
- self.assertInHTML(
283
- f"""
284
- <a href="{self.url}"
285
- data-item-weight="{self.item_weight}">
286
- Installed Plugins
287
- </a>
288
- """,
289
- response_content,
290
- )
236
+ self.assertNotRegex(response_content, r"Installed\s+Plugins")
291
237
 
292
238
 
293
239
  class LoginUI(TestCase):
@@ -326,9 +272,9 @@ class LoginUI(TestCase):
326
272
  sso_login_search_result = self.make_request()
327
273
  self.assertIsNotNone(sso_login_search_result)
328
274
 
329
- @override_settings(HIDE_RESTRICTED_UI=True, BANNER_TOP="Hello, Banner Top", BANNER_BOTTOM="Hello, Banner Bottom")
330
- def test_routes_redirect_back_to_login_if_hide_restricted_ui_true(self):
331
- """Assert that api docs and graphql redirects to login page if user is unauthenticated and HIDE_RESTRICTED_UI=True."""
275
+ @override_settings(BANNER_TOP="Hello, Banner Top", BANNER_BOTTOM="Hello, Banner Bottom")
276
+ def test_routes_redirect_back_to_login_unauthenticated(self):
277
+ """Assert that api docs and graphql redirects to login page if user is unauthenticated."""
332
278
  self.client.logout()
333
279
  headers = {"HTTP_ACCEPT": "text/html"}
334
280
  urls = [reverse("api_docs"), reverse("graphql")]
@@ -346,26 +292,6 @@ class LoginUI(TestCase):
346
292
  self.assertNotIn("Hello, Banner Top", response_content)
347
293
  self.assertNotIn("Hello, Banner Bottom", response_content)
348
294
 
349
- @override_settings(HIDE_RESTRICTED_UI=False, BANNER_TOP="Hello, Banner Top", BANNER_BOTTOM="Hello, Banner Bottom")
350
- def test_routes_no_redirect_back_to_login_if_hide_restricted_ui_false(self):
351
- """Assert that api docs and graphql do not redirects to login page if user is unauthenticated and HIDE_RESTRICTED_UI=False."""
352
- self.client.logout()
353
- headers = {"HTTP_ACCEPT": "text/html"}
354
- urls = [reverse("api_docs"), reverse("graphql")]
355
- for url in urls:
356
- response = self.client.get(url, **headers)
357
- self.assertHttpStatus(response, 200)
358
- self.assertEqual(response.request["PATH_INFO"], url)
359
- response_content = response.content.decode(response.charset).replace("\n", "")
360
- # Assert Footer items(`self.footer_elements`), Banner and Banner Top is not hidden
361
- for footer_text in self.footer_elements:
362
- self.assertInHTML(footer_text, response_content)
363
-
364
- # Only API Docs implements BANNERS
365
- if url == urls[0]:
366
- self.assertInHTML("Hello, Banner Top", response_content)
367
- self.assertInHTML("Hello, Banner Bottom", response_content)
368
-
369
295
 
370
296
  class MetricsViewTestCase(TestCase):
371
297
  def query_and_parse_metrics(self):
nautobot/core/urls.py CHANGED
@@ -1,6 +1,7 @@
1
1
  from django.conf import settings
2
2
  from django.conf.urls import include
3
3
  from django.urls import path
4
+ from django.views.generic import TemplateView
4
5
  from django.views.static import serve
5
6
 
6
7
  from nautobot.core.views import CustomGraphQLView, HomeView, StaticMediaFailureView, SearchView, nautobot_metrics_view
@@ -31,7 +32,7 @@ urlpatterns = [
31
32
  path("api/", include("nautobot.core.api.urls")),
32
33
  # GraphQL
33
34
  path("graphql/", CustomGraphQLView.as_view(graphiql=True), name="graphql"),
34
- # Serving static media in Django
35
+ # Serving static media in Django (TODO: should be DEBUG mode only - "This view is NOT hardened for production use")
35
36
  path("media/<path:path>", serve, {"document_root": settings.MEDIA_ROOT}),
36
37
  # Admin
37
38
  path("admin/", admin_site.urls),
@@ -46,6 +47,10 @@ urlpatterns = [
46
47
  path(r"health/", include("health_check.urls")),
47
48
  # FileProxy attachments download/get URLs used in admin views only
48
49
  path("files/", include("db_file_storage.urls")),
50
+ # Templated css file
51
+ path(
52
+ "template.css", TemplateView.as_view(template_name="template.css", content_type="text/css"), name="template_css"
53
+ ),
49
54
  ]
50
55
 
51
56
 
@@ -100,7 +100,11 @@ def render_jinja2(template_code, context):
100
100
  """
101
101
  rendering_engine = engines["jinja"]
102
102
  template = rendering_engine.from_string(template_code)
103
- return template.render(context=context)
103
+ # For reasons unknown to me, django-jinja2 `template.render()` implicitly calls `mark_safe()` on the rendered text.
104
+ # This is a security risk in general, especially so in our case because we're often using this function to render
105
+ # a user-provided template and don't want to open ourselves up to script injection or similar issues.
106
+ # There's no `mark_unsafe()` function, but concatenating a SafeString to an ordinary string (even "") suffices.
107
+ return "" + template.render(context=context)
104
108
 
105
109
 
106
110
  def shallow_compare_dict(source_dict, destination_dict, exclude=None):
@@ -2,6 +2,7 @@ import re
2
2
 
3
3
  from django import forms
4
4
  from django_filters import (
5
+ BooleanFilter,
5
6
  ChoiceFilter,
6
7
  ModelMultipleChoiceFilter,
7
8
  MultipleChoiceFilter,
@@ -93,8 +94,10 @@ def get_filterset_parameter_form_field(model, parameter, filterset=None):
93
94
  from nautobot.extras.utils import ChangeLoggedModelsQuery, RoleModelsQuery, TaggableClassesQuery
94
95
  from nautobot.core.filters import MultiValueDecimalFilter, MultiValueFloatFilter
95
96
  from nautobot.core.forms import (
97
+ BOOLEAN_CHOICES,
96
98
  DynamicModelMultipleChoiceField,
97
99
  MultipleContentTypeField,
100
+ StaticSelect2,
98
101
  StaticSelect2Multiple,
99
102
  )
100
103
  from nautobot.virtualization.models import VirtualMachine
@@ -150,11 +153,10 @@ def get_filterset_parameter_form_field(model, parameter, filterset=None):
150
153
  choices_as_strings=True, queryset=queryset_map[plural_name]().as_queryset()
151
154
  )
152
155
  elif isinstance(field, (MultipleChoiceFilter, ChoiceFilter)) and "choices" in field.extra:
153
- form_field_class = forms.ChoiceField
154
- form_field_class.widget = StaticSelect2Multiple()
155
- form_attr = {"choices": field.extra.get("choices")}
156
+ form_field = forms.MultipleChoiceField(choices=field.extra.get("choices"), widget=StaticSelect2Multiple)
156
157
 
157
- form_field = form_field_class(**form_attr)
158
+ elif isinstance(field, BooleanFilter):
159
+ form_field = forms.ChoiceField(choices=BOOLEAN_CHOICES, widget=StaticSelect2)
158
160
 
159
161
  form_field.required = False
160
162
  form_field.initial = None
@@ -192,3 +192,31 @@ def get_table_for_model(model):
192
192
  (Union[Table, None]): Either the `Table` class or `None`
193
193
  """
194
194
  return get_related_class_for_model(model, module_name="tables", object_suffix="Table")
195
+
196
+
197
+ def get_created_and_last_updated_usernames_for_model(instance):
198
+ """
199
+ Args:
200
+ instance: A model class instance
201
+
202
+ Returns:
203
+ created_by: Username of the user that created the instance
204
+ last_updated_by: Username of the user that last modified the instance
205
+ """
206
+ from nautobot.extras.choices import ObjectChangeActionChoices
207
+ from nautobot.extras.models import ObjectChange
208
+
209
+ object_change_records = get_changes_for_model(instance)
210
+ created_by = None
211
+ last_updated_by = None
212
+ try:
213
+ created_by_record = object_change_records.get(action=ObjectChangeActionChoices.ACTION_CREATE)
214
+ created_by = created_by_record.user_name
215
+ except ObjectChange.DoesNotExist:
216
+ pass
217
+
218
+ last_updated_by_record = object_change_records.first()
219
+ if last_updated_by_record:
220
+ last_updated_by = last_updated_by_record.user_name
221
+
222
+ return created_by, last_updated_by
@@ -114,13 +114,12 @@ def get_filterable_params_from_filter_params(filter_params, non_filter_params, f
114
114
  Returns:
115
115
  (QueryDict): Filter param querydict with only queryset filterable params
116
116
  """
117
- for non_filter_param in non_filter_params:
118
- filter_params.pop(non_filter_param, None)
119
-
120
117
  # Some FilterSet field only accept single choice not multiple choices
121
118
  # e.g datetime field, bool fields etc.
122
119
  final_filter_params = {}
123
120
  for field in filter_params.keys():
121
+ if field in non_filter_params:
122
+ continue
124
123
  if filter_params.get(field):
125
124
  # `is_single_choice_field` implements `get_filterset_field`, which throws an exception if a field is not found.
126
125
  # If an exception is thrown, instead of throwing an exception, set `_is_single_choice_field` to 'False'
@@ -25,7 +25,6 @@ from prometheus_client.registry import Collector
25
25
  from nautobot.core.constants import SEARCH_MAX_RESULTS
26
26
  from nautobot.core.forms import SearchForm
27
27
  from nautobot.core.releases import get_latest_release
28
- from nautobot.core.utils.config import get_settings_or_config
29
28
  from nautobot.core.utils.lookup import get_route_for_model
30
29
  from nautobot.extras.models import GraphQLQuery
31
30
  from nautobot.extras.registry import registry
@@ -58,8 +57,8 @@ class HomeView(AccessMixin, TemplateView):
58
57
  return template.render(additional_context)
59
58
 
60
59
  def get(self, request, *args, **kwargs):
61
- # Redirect user to login page if not authenticated and HIDE_RESTRICTED_UI is set to True
62
- if not request.user.is_authenticated and get_settings_or_config("HIDE_RESTRICTED_UI"):
60
+ # Redirect user to login page if not authenticated
61
+ if not request.user.is_authenticated:
63
62
  return self.handle_no_permission()
64
63
  # Check whether a new release is available. (Only for staff/superusers.)
65
64
  new_release = None
@@ -242,7 +241,7 @@ def csrf_failure(request, reason="", template_name="403_csrf_failure.html"):
242
241
 
243
242
  class CustomGraphQLView(GraphQLView):
244
243
  def render_graphiql(self, request, **data):
245
- if not request.user.is_authenticated and get_settings_or_config("HIDE_RESTRICTED_UI"):
244
+ if not request.user.is_authenticated:
246
245
  graphql_url = reverse("graphql")
247
246
  login_url = reverse(settings.LOGIN_URL)
248
247
  return redirect(f"{login_url}?next={graphql_url}")
@@ -16,9 +16,8 @@ from django.db.models import ManyToManyField, ProtectedError
16
16
  from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput
17
17
  from django.http import HttpResponse, JsonResponse
18
18
  from django.shortcuts import get_object_or_404, redirect, render
19
- from django.utils.html import escape
19
+ from django.utils.html import format_html
20
20
  from django.utils.http import is_safe_url
21
- from django.utils.safestring import mark_safe
22
21
  from django.views.generic import View
23
22
  from django_tables2 import RequestConfig
24
23
  from rest_framework.exceptions import ParseError
@@ -40,6 +39,7 @@ from nautobot.core.forms import (
40
39
  from nautobot.core.forms.forms import DynamicFilterFormSet
41
40
  from nautobot.core.templatetags.helpers import bettertitle, validated_viewname
42
41
  from nautobot.core.utils.config import get_settings_or_config
42
+ from nautobot.core.utils.lookup import get_created_and_last_updated_usernames_for_model
43
43
  from nautobot.core.utils.permissions import get_permission_for_model
44
44
  from nautobot.core.utils.requests import (
45
45
  convert_querydict_to_factory_formset_acceptable_querydict,
@@ -101,6 +101,8 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
101
101
  Generic GET handler for accessing an object.
102
102
  """
103
103
  instance = get_object_or_404(self.queryset, **kwargs)
104
+ # Get the ObjectChange records to populate the advanced tab information
105
+ created_by, last_updated_by = get_created_and_last_updated_usernames_for_model(instance)
104
106
 
105
107
  # TODO: this feels inelegant - should the tabs lookup be a dedicated endpoint rather than piggybacking
106
108
  # on the object-retrieve endpoint?
@@ -128,6 +130,8 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
128
130
  "object": instance,
129
131
  "verbose_name": self.queryset.model._meta.verbose_name,
130
132
  "verbose_name_plural": self.queryset.model._meta.verbose_name_plural,
133
+ "created_by": created_by,
134
+ "last_updated_by": last_updated_by,
131
135
  **self.get_extra_context(request, instance),
132
136
  },
133
137
  )
@@ -153,7 +157,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
153
157
  template_name = "generic/object_list.html"
154
158
  action_buttons = ("add", "import", "export")
155
159
  non_filter_params = (
156
- "export", # trigger for CSV/export-template/YAML export
160
+ "export", # trigger for CSV/export-template/YAML export # 3.0 TODO: remove, irrelevant after #4746
157
161
  "page", # used by django-tables2.RequestConfig
158
162
  "per_page", # used by get_paginate_count
159
163
  "sort", # table sorting
@@ -167,7 +171,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
167
171
  def get_required_permission(self):
168
172
  return get_permission_for_model(self.queryset.model, "view")
169
173
 
170
- # TODO: remove this as well?
174
+ # 3.0 TODO: remove, irrelevant after #4746
171
175
  def queryset_to_yaml(self):
172
176
  """
173
177
  Export the queryset of objects as concatenated YAML documents.
@@ -209,7 +213,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
209
213
  if not filterset.is_valid():
210
214
  messages.error(
211
215
  request,
212
- mark_safe(f"Invalid filters were specified: {filterset.errors}"),
216
+ format_html("Invalid filters were specified: {}", filterset.errors),
213
217
  )
214
218
  self.queryset = self.queryset.none()
215
219
 
@@ -230,7 +234,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
230
234
  filter_form = self.filterset_form(filter_params, label_suffix="")
231
235
 
232
236
  # Check for export template rendering
233
- if request.GET.get("export"):
237
+ if request.GET.get("export"): # 3.0 TODO: remove, irrelevant after #4746
234
238
  et = get_object_or_404(
235
239
  ExportTemplate,
236
240
  content_type=content_type,
@@ -245,7 +249,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
245
249
  )
246
250
 
247
251
  # Check for YAML export support
248
- elif "export" in request.GET and hasattr(model, "to_yaml"):
252
+ elif "export" in request.GET and hasattr(model, "to_yaml"): # 3.0 TODO: remove, irrelevant after #4746
249
253
  response = HttpResponse(self.queryset_to_yaml(), content_type="text/yaml")
250
254
  filename = f"{settings.BRANDING_PREPENDED_FILENAME}{self.queryset.model._meta.verbose_name_plural}.yaml"
251
255
  response["Content-Disposition"] = f'attachment; filename="{filename}"'
@@ -397,10 +401,10 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
397
401
  msg = f"{verb} {self.queryset.model._meta.verbose_name}"
398
402
  logger.info(f"{msg} {obj} (PK: {obj.pk})")
399
403
  if hasattr(obj, "get_absolute_url"):
400
- msg = f'{msg} <a href="{obj.get_absolute_url()}">{escape(obj)}</a>'
404
+ msg = format_html('{} <a href="{}">{}</a>', msg, obj.get_absolute_url(), obj)
401
405
  else:
402
- msg = f"{msg} {escape(obj)}"
403
- messages.success(request, mark_safe(msg))
406
+ msg = format_html("{} {}", msg, obj)
407
+ messages.success(request, msg)
404
408
 
405
409
  def post(self, request, *args, **kwargs):
406
410
  logger = logging.getLogger(__name__ + ".ObjectEditView")
@@ -752,7 +756,7 @@ class ObjectImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
752
756
  logger.info(f"Import object {obj} (PK: {obj.pk})")
753
757
  messages.success(
754
758
  request,
755
- mark_safe(f'Imported object: <a href="{obj.get_absolute_url()}">{obj}</a>'),
759
+ format_html('Imported object: <a href="{}">{}</a>', obj.get_absolute_url(), obj),
756
760
  )
757
761
 
758
762
  if "_addanother" in request.POST:
@@ -19,8 +19,7 @@ from django.template.loader import select_template, TemplateDoesNotExist
19
19
  from django.urls import reverse
20
20
  from django.urls.exceptions import NoReverseMatch
21
21
  from django.utils.http import is_safe_url
22
- from django.utils.html import escape
23
- from django.utils.safestring import mark_safe
22
+ from django.utils.html import format_html
24
23
  from django.views.generic.edit import FormView
25
24
 
26
25
  from rest_framework import mixins, exceptions
@@ -605,7 +604,7 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
605
604
  filterset_class = None
606
605
  filterset_form_class = None
607
606
  non_filter_params = (
608
- "export", # trigger for CSV/export-template/YAML export
607
+ "export", # trigger for CSV/export-template/YAML export # 3.0 TODO: remove, irrelevant after #4746
609
608
  "page", # used by django-tables2.RequestConfig
610
609
  "per_page", # used by get_paginate_count
611
610
  "sort", # table sorting
@@ -622,11 +621,12 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
622
621
  if not self.filterset.is_valid():
623
622
  messages.error(
624
623
  self.request,
625
- mark_safe(f"Invalid filters were specified: {self.filterset.errors}"),
624
+ format_html("Invalid filters were specified: {}", self.filterset.errors),
626
625
  )
627
626
  queryset = queryset.none()
628
627
  return queryset
629
628
 
629
+ # 3.0 TODO: remove, irrelevant after #4746
630
630
  def check_for_export(self, request, model, content_type):
631
631
  # Check for export template rendering
632
632
  queryset = self.filter_queryset(self.get_queryset())
@@ -653,6 +653,7 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
653
653
 
654
654
  return None
655
655
 
656
+ # 3.0 TODO: remove, irrelevant after #4746
656
657
  def queryset_to_yaml(self):
657
658
  """
658
659
  Export the queryset of objects as concatenated YAML documents.
@@ -667,7 +668,7 @@ class ObjectListViewMixin(NautobotViewSetMixin, mixins.ListModelMixin):
667
668
  List the model instances.
668
669
  """
669
670
  context = {"use_new_ui": True}
670
- if "export" in request.GET:
671
+ if "export" in request.GET: # 3.0 TODO: remove, irrelevant after #4746
671
672
  queryset = self.get_queryset()
672
673
  model = queryset.model
673
674
  content_type = ContentType.objects.get_for_model(model)
@@ -748,10 +749,10 @@ class ObjectEditViewMixin(NautobotViewSetMixin, mixins.CreateModelMixin, mixins.
748
749
  msg = f'{"Created" if object_created else "Modified"} {queryset.model._meta.verbose_name}'
749
750
  self.logger.info(f"{msg} {obj} (PK: {obj.pk})")
750
751
  if hasattr(obj, "get_absolute_url"):
751
- msg = f'{msg} <a href="{obj.get_absolute_url()}">{escape(obj)}</a>'
752
+ msg = format_html('{} <a href="{}">{}</a>', msg, obj.get_absolute_url(), obj)
752
753
  else:
753
- msg = f"{msg} { escape(obj)}"
754
- messages.success(request, mark_safe(msg))
754
+ msg = format_html("{} {}", msg, obj)
755
+ messages.success(request, msg)
755
756
  if "_addanother" in request.POST:
756
757
  # If the object has clone_fields, pre-populate a new instance of the form
757
758
  if hasattr(obj, "clone_fields"):
@@ -14,6 +14,7 @@ from nautobot.core.forms import (
14
14
  from nautobot.core.forms.forms import DynamicFilterFormSet
15
15
  from nautobot.core.templatetags.helpers import bettertitle, validated_viewname
16
16
  from nautobot.core.utils.config import get_settings_or_config
17
+ from nautobot.core.utils.lookup import get_created_and_last_updated_usernames_for_model
17
18
  from nautobot.core.utils.permissions import get_permission_for_model
18
19
  from nautobot.core.utils.requests import (
19
20
  convert_querydict_to_factory_formset_acceptable_querydict,
@@ -229,6 +230,10 @@ class NautobotHTMLRenderer(renderers.BrowsableAPIRenderer):
229
230
  "verbose_name_plural": queryset.model._meta.verbose_name_plural,
230
231
  }
231
232
  if view.action == "retrieve":
233
+ created_by, last_updated_by = get_created_and_last_updated_usernames_for_model(instance)
234
+
235
+ context["created_by"] = created_by
236
+ context["last_updated_by"] = last_updated_by
232
237
  context.update(view.get_extra_context(request, instance))
233
238
  else:
234
239
  if view.action == "list":