nautobot 2.3.12__py3-none-any.whl → 2.3.13__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 (312) hide show
  1. nautobot/core/api/serializers.py +1 -0
  2. nautobot/core/celery/log.py +4 -4
  3. nautobot/core/models/tree_queries.py +5 -2
  4. nautobot/core/settings.py +1 -1
  5. nautobot/core/tables.py +60 -10
  6. nautobot/core/templatetags/helpers.py +7 -1
  7. nautobot/core/testing/api.py +5 -1
  8. nautobot/core/tests/test_api.py +20 -0
  9. nautobot/core/tests/test_csv.py +25 -3
  10. nautobot/core/tests/test_utils.py +8 -0
  11. nautobot/core/utils/lookup.py +11 -8
  12. nautobot/dcim/api/views.py +3 -0
  13. nautobot/dcim/filters/__init__.py +26 -1
  14. nautobot/dcim/forms.py +4 -0
  15. nautobot/dcim/tests/test_filters.py +33 -0
  16. nautobot/dcim/tests/test_views.py +6 -0
  17. nautobot/extras/api/serializers.py +1 -0
  18. nautobot/extras/api/views.py +2 -0
  19. nautobot/extras/forms/forms.py +2 -0
  20. nautobot/extras/group_sync.py +3 -3
  21. nautobot/extras/plugins/__init__.py +13 -2
  22. nautobot/extras/tests/test_views.py +2 -0
  23. nautobot/ipam/lookups.py +101 -62
  24. nautobot/ipam/tables.py +18 -4
  25. nautobot/ipam/tests/test_querysets.py +49 -1
  26. nautobot/ipam/utils/__init__.py +24 -0
  27. nautobot/ipam/views.py +61 -68
  28. nautobot/project-static/docs/404.html +1 -1
  29. nautobot/project-static/docs/apps/index.html +1 -1
  30. nautobot/project-static/docs/apps/nautobot-apps.html +1 -1
  31. nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1 -1
  32. nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1 -1
  33. nautobot/project-static/docs/code-reference/nautobot/apps/api.html +1 -1
  34. nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +1 -1
  35. nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1 -1
  36. nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1 -1
  37. nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +1 -1
  38. nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1 -1
  39. nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +1 -1
  40. nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +1 -1
  41. nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1 -1
  42. nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1 -1
  43. nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +1 -1
  44. nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +1 -1
  45. nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1 -1
  46. nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +1 -1
  47. nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1 -1
  48. nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +197 -5
  49. nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +1 -1
  50. nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +1 -1
  51. nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1 -1
  52. nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +16 -2
  53. nautobot/project-static/docs/code-reference/nautobot/apps/views.html +1 -1
  54. nautobot/project-static/docs/development/apps/api/configuration-view.html +1 -1
  55. nautobot/project-static/docs/development/apps/api/database-backend-config.html +1 -1
  56. nautobot/project-static/docs/development/apps/api/models/django-admin.html +1 -1
  57. nautobot/project-static/docs/development/apps/api/models/global-search.html +1 -1
  58. nautobot/project-static/docs/development/apps/api/models/graphql.html +1 -1
  59. nautobot/project-static/docs/development/apps/api/models/index.html +1 -1
  60. nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +1 -1
  61. nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +1 -1
  62. nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +1 -1
  63. nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +1 -1
  64. nautobot/project-static/docs/development/apps/api/platform-features/index.html +1 -1
  65. nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +1 -1
  66. nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +1 -1
  67. nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +1 -1
  68. nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +1 -1
  69. nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +23 -4
  70. nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +1 -1
  71. nautobot/project-static/docs/development/apps/api/prometheus.html +1 -1
  72. nautobot/project-static/docs/development/apps/api/setup.html +1 -1
  73. nautobot/project-static/docs/development/apps/api/testing.html +1 -1
  74. nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +1 -1
  75. nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +1 -1
  76. nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +1 -1
  77. nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +1 -1
  78. nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +1 -1
  79. nautobot/project-static/docs/development/apps/api/views/base-template.html +1 -1
  80. nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +1 -1
  81. nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +1 -1
  82. nautobot/project-static/docs/development/apps/api/views/help-documentation.html +1 -1
  83. nautobot/project-static/docs/development/apps/api/views/index.html +1 -1
  84. nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +1 -1
  85. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +1 -1
  86. nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +1 -1
  87. nautobot/project-static/docs/development/apps/api/views/notes.html +1 -1
  88. nautobot/project-static/docs/development/apps/api/views/rest-api.html +1 -1
  89. nautobot/project-static/docs/development/apps/api/views/urls.html +1 -1
  90. nautobot/project-static/docs/development/apps/index.html +1 -1
  91. nautobot/project-static/docs/development/apps/migration/code-updates.html +1 -1
  92. nautobot/project-static/docs/development/apps/migration/dependency-updates.html +1 -1
  93. nautobot/project-static/docs/development/apps/migration/from-v1.html +1 -1
  94. nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +1 -1
  95. nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +1 -1
  96. nautobot/project-static/docs/development/apps/migration/model-updates/global.html +1 -1
  97. nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +1 -1
  98. nautobot/project-static/docs/development/apps/porting-from-netbox.html +1 -1
  99. nautobot/project-static/docs/development/core/application-registry.html +1 -1
  100. nautobot/project-static/docs/development/core/best-practices.html +1 -1
  101. nautobot/project-static/docs/development/core/bootstrap-ui.html +1 -1
  102. nautobot/project-static/docs/development/core/caching.html +1 -1
  103. nautobot/project-static/docs/development/core/controllers.html +1 -1
  104. nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +1 -1
  105. nautobot/project-static/docs/development/core/generic-views.html +1 -1
  106. nautobot/project-static/docs/development/core/getting-started.html +1 -1
  107. nautobot/project-static/docs/development/core/homepage.html +1 -1
  108. nautobot/project-static/docs/development/core/index.html +1 -1
  109. nautobot/project-static/docs/development/core/model-checklist.html +1 -1
  110. nautobot/project-static/docs/development/core/model-features.html +1 -1
  111. nautobot/project-static/docs/development/core/natural-keys.html +1 -1
  112. nautobot/project-static/docs/development/core/navigation-menu.html +1 -1
  113. nautobot/project-static/docs/development/core/release-checklist.html +1 -1
  114. nautobot/project-static/docs/development/core/role-internals.html +1 -1
  115. nautobot/project-static/docs/development/core/settings.html +1 -1
  116. nautobot/project-static/docs/development/core/style-guide.html +1 -1
  117. nautobot/project-static/docs/development/core/templates.html +1 -1
  118. nautobot/project-static/docs/development/core/testing.html +1 -1
  119. nautobot/project-static/docs/development/core/user-preferences.html +1 -1
  120. nautobot/project-static/docs/development/index.html +1 -1
  121. nautobot/project-static/docs/development/jobs/index.html +1 -1
  122. nautobot/project-static/docs/development/jobs/migration/from-v1.html +1 -1
  123. nautobot/project-static/docs/index.html +1 -1
  124. nautobot/project-static/docs/objects.inv +0 -0
  125. nautobot/project-static/docs/overview/application_stack.html +1 -1
  126. nautobot/project-static/docs/overview/design_philosophy.html +1 -1
  127. nautobot/project-static/docs/release-notes/index.html +1 -1
  128. nautobot/project-static/docs/release-notes/version-1.0.html +1 -1
  129. nautobot/project-static/docs/release-notes/version-1.1.html +1 -1
  130. nautobot/project-static/docs/release-notes/version-1.2.html +1 -1
  131. nautobot/project-static/docs/release-notes/version-1.3.html +1 -1
  132. nautobot/project-static/docs/release-notes/version-1.4.html +1 -1
  133. nautobot/project-static/docs/release-notes/version-1.5.html +1 -1
  134. nautobot/project-static/docs/release-notes/version-1.6.html +614 -179
  135. nautobot/project-static/docs/release-notes/version-2.0.html +1 -1
  136. nautobot/project-static/docs/release-notes/version-2.1.html +1 -1
  137. nautobot/project-static/docs/release-notes/version-2.2.html +1 -1
  138. nautobot/project-static/docs/release-notes/version-2.3.html +401 -199
  139. nautobot/project-static/docs/requirements.txt +1 -1
  140. nautobot/project-static/docs/search/search_index.json +1 -1
  141. nautobot/project-static/docs/sitemap.xml +270 -270
  142. nautobot/project-static/docs/sitemap.xml.gz +0 -0
  143. nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +1 -1
  144. nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +1 -1
  145. nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +3 -3
  146. nautobot/project-static/docs/user-guide/administration/configuration/index.html +1 -1
  147. nautobot/project-static/docs/user-guide/administration/configuration/redis.html +1 -1
  148. nautobot/project-static/docs/user-guide/administration/configuration/settings.html +1 -1
  149. nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +1 -1
  150. nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +1 -1
  151. nautobot/project-static/docs/user-guide/administration/guides/docker.html +1 -1
  152. nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +1 -1
  153. nautobot/project-static/docs/user-guide/administration/guides/permissions.html +1 -1
  154. nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +1 -1
  155. nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +1 -1
  156. nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +1 -1
  157. nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +1 -1
  158. nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +1 -1
  159. nautobot/project-static/docs/user-guide/administration/installation/app-install.html +1 -1
  160. nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +1 -1
  161. nautobot/project-static/docs/user-guide/administration/installation/http-server.html +1 -1
  162. nautobot/project-static/docs/user-guide/administration/installation/index.html +1 -1
  163. nautobot/project-static/docs/user-guide/administration/installation/install_system.html +1 -1
  164. nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +1 -1
  165. nautobot/project-static/docs/user-guide/administration/installation/services.html +1 -1
  166. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +1 -1
  167. nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +1 -1
  168. nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +1 -1
  169. nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +1 -1
  170. nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +1 -1
  171. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +1 -1
  172. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +1 -1
  173. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +1 -1
  174. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +1 -1
  175. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +1 -1
  176. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +1 -1
  177. nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +1 -1
  178. nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +1 -1
  179. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +1 -1
  180. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +1 -1
  181. nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +1 -1
  182. nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +1 -1
  183. nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +1 -1
  184. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +1 -1
  185. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +1 -1
  186. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +1 -1
  187. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +1 -1
  188. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +1 -1
  189. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +1 -1
  190. nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +1 -1
  191. nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +1 -1
  192. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +1 -1
  193. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +1 -1
  194. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +1 -1
  195. nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +1 -1
  196. nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +1 -1
  197. nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +1 -1
  198. nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +1 -1
  199. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +1 -1
  200. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +1 -1
  201. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +1 -1
  202. nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +1 -1
  203. nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +1 -1
  204. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +1 -1
  205. nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +1 -1
  206. nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +1 -1
  207. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +1 -1
  208. nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +1 -1
  209. nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +1 -1
  210. nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +1 -1
  211. nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +1 -1
  212. nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +1 -1
  213. nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +1 -1
  214. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +1 -1
  215. nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +1 -1
  216. nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +1 -1
  217. nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +1 -1
  218. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +1 -1
  219. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +1 -1
  220. nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +1 -1
  221. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +1 -1
  222. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +1 -1
  223. nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +1 -1
  224. nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +1 -1
  225. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +1 -1
  226. nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +1 -1
  227. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +1 -1
  228. nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +1 -1
  229. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +1 -1
  230. nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +1 -1
  231. nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +1 -1
  232. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +1 -1
  233. nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +1 -1
  234. nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +1 -1
  235. nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +1 -1
  236. nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +1 -1
  237. nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +1 -1
  238. nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +1 -1
  239. nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +1 -1
  240. nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +1 -1
  241. nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +1 -1
  242. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +1 -1
  243. nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +1 -1
  244. nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +1 -1
  245. nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +1 -1
  246. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +1 -1
  247. nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +1 -1
  248. nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +1 -1
  249. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +1 -1
  250. nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +1 -1
  251. nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +1 -1
  252. nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +1 -1
  253. nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +1 -1
  254. nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +1 -1
  255. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +1 -1
  256. nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +1 -1
  257. nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +1 -1
  258. nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +1 -1
  259. nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +1 -1
  260. nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +1 -1
  261. nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +1 -1
  262. nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +1 -1
  263. nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +1 -1
  264. nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +1 -1
  265. nautobot/project-static/docs/user-guide/feature-guides/graphql.html +1 -1
  266. nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +1 -1
  267. nautobot/project-static/docs/user-guide/feature-guides/relationships.html +1 -1
  268. nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +1 -1
  269. nautobot/project-static/docs/user-guide/index.html +1 -1
  270. nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +1 -1
  271. nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +1 -1
  272. nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +1 -1
  273. nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +1 -1
  274. nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +1 -1
  275. nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +1 -1
  276. nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +1 -1
  277. nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +1 -1
  278. nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +1 -1
  279. nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +1 -1
  280. nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +1 -1
  281. nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +1 -1
  282. nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +1 -1
  283. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +1 -1
  284. nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +1 -1
  285. nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +1 -1
  286. nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +1 -1
  287. nautobot/project-static/docs/user-guide/platform-functionality/note.html +1 -1
  288. nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +1 -1
  289. nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +1 -1
  290. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +1 -1
  291. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +1 -1
  292. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +1 -1
  293. nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +1 -1
  294. nautobot/project-static/docs/user-guide/platform-functionality/role.html +1 -1
  295. nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +1 -1
  296. nautobot/project-static/docs/user-guide/platform-functionality/secret.html +1 -1
  297. nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +1 -1
  298. nautobot/project-static/docs/user-guide/platform-functionality/status.html +1 -1
  299. nautobot/project-static/docs/user-guide/platform-functionality/tag.html +1 -1
  300. nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +1 -1
  301. nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +1 -1
  302. nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +1 -1
  303. nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +1 -1
  304. nautobot/users/api/serializers.py +1 -0
  305. nautobot/virtualization/filters.py +19 -2
  306. nautobot/virtualization/tests/test_filters.py +9 -0
  307. {nautobot-2.3.12.dist-info → nautobot-2.3.13.dist-info}/METADATA +3 -3
  308. {nautobot-2.3.12.dist-info → nautobot-2.3.13.dist-info}/RECORD +312 -312
  309. {nautobot-2.3.12.dist-info → nautobot-2.3.13.dist-info}/LICENSE.txt +0 -0
  310. {nautobot-2.3.12.dist-info → nautobot-2.3.13.dist-info}/NOTICE +0 -0
  311. {nautobot-2.3.12.dist-info → nautobot-2.3.13.dist-info}/WHEEL +0 -0
  312. {nautobot-2.3.12.dist-info → nautobot-2.3.13.dist-info}/entry_points.txt +0 -0
@@ -519,6 +519,7 @@ class TableExtension:
519
519
  """
520
520
 
521
521
  model = None
522
+ suffix = None
522
523
  table_columns = {}
523
524
  add_to_default_columns = ()
524
525
  remove_from_default_columns = ()
@@ -594,7 +595,7 @@ def _add_columns_into_model_table(table_extension, app_name):
594
595
  logger.error(error)
595
596
  return
596
597
 
597
- table = get_table_for_model(table_extension.model)
598
+ table = get_table_for_model(table_extension.model, suffix=table_extension.suffix)
598
599
  for name, column in table_extension.table_columns.items():
599
600
  _validate_table_column_name_is_prefixed_with_app_name(name, app_name)
600
601
  _add_column_to_table_base_columns(table, name, column, app_name)
@@ -629,18 +630,28 @@ def _modify_default_table_columns(table_extension, app_name):
629
630
  """Add or remove columns from the table default columns."""
630
631
  from nautobot.core.utils.lookup import get_table_for_model
631
632
 
632
- table = get_table_for_model(table_extension.model)
633
+ table = get_table_for_model(table_extension.model, suffix=table_extension.suffix)
633
634
  message = (
634
635
  f"{app_name}: Cannot {{action}} column `{{column_name}}` {{preposition}} the default columns for `{table}`."
635
636
  )
636
637
 
637
638
  for column_name in table_extension.add_to_default_columns:
639
+ if not getattr(table.Meta, "default_columns", None):
640
+ logger.warning(
641
+ f"{app_name}: Table `{table}` does not have a `default_columns` attribute. Cannot add column: {column_name}."
642
+ )
643
+ continue
638
644
  if column_name in table.base_columns:
639
645
  table.Meta.default_columns = (*table.Meta.default_columns, column_name)
640
646
  else:
641
647
  logger.debug(message.format(action="add", column_name=column_name, preposition="to"))
642
648
 
643
649
  for column_name in table_extension.remove_from_default_columns:
650
+ if not getattr(table.Meta, "default_columns", None):
651
+ logger.warning(
652
+ f"{app_name}: Table `{table}` does not have a `default_columns` attribute. Cannot remove column: {column_name}."
653
+ )
654
+ continue
644
655
  if column_name in table.Meta.default_columns:
645
656
  table.Meta.default_columns = tuple(name for name in table.Meta.default_columns if name != column_name)
646
657
  else:
@@ -3607,6 +3607,8 @@ class RoleTestCase(ViewTestCases.OrganizationalObjectViewTestCase):
3607
3607
 
3608
3608
  cls.bulk_edit_data = {
3609
3609
  "color": "000000",
3610
+ "description": "I used to be a new role object.",
3611
+ "weight": 255,
3610
3612
  }
3611
3613
 
3612
3614
  @override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
nautobot/ipam/lookups.py CHANGED
@@ -3,7 +3,9 @@ from django.db.models import Lookup, lookups
3
3
  import netaddr
4
4
 
5
5
 
6
- def _mysql_varbin_to_broadcast():
6
+ def _mysql_varbin_to_broadcast(alias=None):
7
+ if alias:
8
+ return f"HEX({alias}.broadcast)"
7
9
  return "HEX(broadcast)"
8
10
 
9
11
 
@@ -13,11 +15,15 @@ def _mysql_varbin_to_hex(lhs, alias=None):
13
15
  return f"HEX({lhs})"
14
16
 
15
17
 
16
- def _mysql_varbin_to_network():
18
+ def _mysql_varbin_to_network(alias=None):
19
+ if alias:
20
+ return f"HEX({alias}.network)"
17
21
  return "HEX(network)"
18
22
 
19
23
 
20
- def _postgresql_varbin_to_broadcast(length):
24
+ def _postgresql_varbin_to_broadcast(length, alias=None):
25
+ if alias:
26
+ return f"right({alias}.broadcast::text, -1)::varbit::bit({length})"
21
27
  return f"right(broadcast::text, -1)::varbit::bit({length})"
22
28
 
23
29
 
@@ -27,8 +33,10 @@ def _postgresql_varbin_to_integer(lhs, length, alias=None):
27
33
  return f"right({lhs}::text, -1)::varbit::bit({length})"
28
34
 
29
35
 
30
- def _postgresql_varbin_to_network(lhs, length):
36
+ def _postgresql_varbin_to_network(lhs, length, alias=None):
31
37
  # convert to bitstring, 0 out everything larger than prefix_length
38
+ if alias:
39
+ return f"lpad(right({alias}.{lhs}::text, -1)::varbit::text, {alias}.prefix_length, '0')::bit({length})"
32
40
  return f"lpad(right({lhs}::text, -1)::varbit::text, prefix_length, '0')::bit({length})"
33
41
 
34
42
 
@@ -52,8 +60,8 @@ def get_ip_info(field_name, ip_str, alias=None):
52
60
  ip_details.rhs = py_to_hex(ip.ip, ip_details.length)
53
61
  ip_details.net_addr = f"'{py_to_hex(ip.network, ip_details.length)}'"
54
62
  ip_details.bcast_addr = f"'{py_to_hex(ip[-1], ip_details.length)}'"
55
- ip_details.q_net = _mysql_varbin_to_network()
56
- ip_details.q_bcast = _mysql_varbin_to_broadcast()
63
+ ip_details.q_net = _mysql_varbin_to_network(alias=alias)
64
+ ip_details.q_bcast = _mysql_varbin_to_broadcast(alias=alias)
57
65
  ip_details.q_ip = _mysql_varbin_to_hex(field_name, alias=alias)
58
66
 
59
67
  elif _connection.vendor == "postgresql":
@@ -61,8 +69,8 @@ def get_ip_info(field_name, ip_str, alias=None):
61
69
  ip_details.addr_str = f"B'{bin(int(ip_details.addr))[2:].zfill(ip_details.length)}'"
62
70
  ip_details.net_addr = f"B'{bin(int(ip.network))[2:].zfill(ip_details.length)}'"
63
71
  ip_details.bcast_addr = f"B'{bin(int(ip[-1]))[2:].zfill(ip_details.length)}'"
64
- ip_details.q_net = _postgresql_varbin_to_network(field_name, ip_details.length)
65
- ip_details.q_bcast = _postgresql_varbin_to_broadcast(ip_details.length)
72
+ ip_details.q_net = _postgresql_varbin_to_network(field_name, ip_details.length, alias=alias)
73
+ ip_details.q_bcast = _postgresql_varbin_to_broadcast(ip_details.length, alias=alias)
66
74
  ip_details.q_ip = _postgresql_varbin_to_integer(field_name, ip_details.length, alias=alias)
67
75
 
68
76
  return ip_details
@@ -71,25 +79,38 @@ def get_ip_info(field_name, ip_str, alias=None):
71
79
  class IPDetails:
72
80
  """Class for setting up all details about an IP they may be needed"""
73
81
 
74
- net = None
75
- addr = None
76
- ip = None
77
- prefix = None
78
- length = None
79
- addr_str = None
80
- rhs = None
81
- net_addr = None
82
- bcast_addr = None
83
- q_net = None
84
- q_bcast = None
85
- q_ip = None
82
+ addr = None # 10.0.0.0
83
+ ip = None # 10.0.0.0/8
84
+ prefix = None # 8
85
+ length = None # 32
86
+ addr_str = None # B'00001010000000000000000000000000'
87
+ rhs = None # 00001010000000000000000000000000
88
+ net_addr = None # B'00001010000000000000000000000000'
89
+ bcast_addr = None # B'00001010111111111111111111111111'
90
+ q_net = None # mysql or postgres specific
91
+ q_bcast = None # mysql or postgres specific
92
+ q_ip = None # mysql or postgres specific
86
93
  to_len = {4: 32, 6: 128}
87
94
 
95
+ def __str__(self):
96
+ return f"""\
97
+ addr: {self.addr}
98
+ ip: {self.ip}
99
+ prefix: {self.prefix}
100
+ length: {self.length}
101
+ addr_str: {self.addr_str}
102
+ rhs: {self.rhs}
103
+ net_addr: {self.net_addr}
104
+ bcast_addr: {self.bcast_addr}
105
+ q_net: {self.q_net}
106
+ q_bcast: {self.q_bcast}
107
+ q_ip: {self.q_ip}"""
108
+
88
109
 
89
110
  class StringMatchMixin:
90
- def process_lhs(self, qn, connection, lhs=None):
111
+ def process_lhs(self, compiler, connection, lhs=None):
91
112
  lhs = lhs or self.lhs
92
- lhs_string, lhs_params = qn.compile(lhs)
113
+ lhs_string, lhs_params = compiler.compile(lhs)
93
114
  if connection.vendor == "postgresql":
94
115
  raise NotSupportedError("Lookup not supported on postgresql.")
95
116
  return f"INET6_NTOA({lhs_string})", lhs_params
@@ -129,6 +150,7 @@ class IRegex(StringMatchMixin, lookups.IRegex):
129
150
 
130
151
  class NetworkFieldMixin:
131
152
  def get_prep_lookup(self):
153
+ self.alias = self.lhs.alias
132
154
  field_name = self.lhs.field.name
133
155
  if field_name not in ["host", "network"]:
134
156
  raise NotSupportedError(f"Lookup only provided on the host and network fields, not {field_name}.")
@@ -139,8 +161,8 @@ class NetworkFieldMixin:
139
161
  self.ip = get_ip_info(field_name, self.rhs, alias=self.lhs.alias)
140
162
  return str(self.ip.ip)
141
163
 
142
- def process_rhs(self, qn, connection):
143
- sql, params = super().process_rhs(qn, connection)
164
+ def process_rhs(self, compiler, connection):
165
+ sql, params = super().process_rhs(compiler, connection)
144
166
  params[0] = self.ip.rhs
145
167
  return sql, params
146
168
 
@@ -148,50 +170,67 @@ class NetworkFieldMixin:
148
170
  class NetEquals(NetworkFieldMixin, Lookup):
149
171
  lookup_name = "net_equals"
150
172
 
151
- def as_sql(self, qn, connection):
152
- _, lhs_params = self.process_lhs(qn, connection)
153
- rhs, rhs_params = self.process_rhs(qn, connection)
154
- query = f"prefix_length = {self.ip.prefix} AND {rhs} = {self.ip.q_ip}"
173
+ def as_sql(self, compiler, connection):
174
+ _, lhs_params = self.process_lhs(compiler, connection)
175
+ rhs, rhs_params = self.process_rhs(compiler, connection)
176
+ if self.alias:
177
+ query = f"{self.alias}.prefix_length = {self.ip.prefix} AND {rhs} = {self.ip.q_ip}"
178
+ else:
179
+ query = f"prefix_length = {self.ip.prefix} AND {rhs} = {self.ip.q_ip}"
155
180
  return query, lhs_params + rhs_params
156
181
 
157
182
 
158
183
  class NetContainsOrEquals(NetworkFieldMixin, Lookup):
159
184
  lookup_name = "net_contains_or_equals"
160
185
 
161
- def as_sql(self, qn, connection):
162
- _, lhs_params = self.process_lhs(qn, connection)
163
- rhs, rhs_params = self.process_rhs(qn, connection)
164
- query = f"prefix_length <= {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
186
+ def as_sql(self, compiler, connection):
187
+ _, lhs_params = self.process_lhs(compiler, connection)
188
+ rhs, rhs_params = self.process_rhs(compiler, connection)
189
+ if self.alias:
190
+ query = f"{self.alias}.prefix_length <= {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
191
+ else:
192
+ query = f"prefix_length <= {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
165
193
  return query, lhs_params + rhs_params
166
194
 
167
195
 
168
196
  class NetContains(NetworkFieldMixin, Lookup):
169
197
  lookup_name = "net_contains"
170
198
 
171
- def as_sql(self, qn, connection):
172
- _, lhs_params = self.process_lhs(qn, connection)
173
- rhs, rhs_params = self.process_rhs(qn, connection)
174
- query = f"prefix_length < {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
199
+ def as_sql(self, compiler, connection):
200
+ _, lhs_params = self.process_lhs(compiler, connection)
201
+ rhs, rhs_params = self.process_rhs(compiler, connection)
202
+ if self.alias:
203
+ query = (
204
+ f"{self.alias}.prefix_length < {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
205
+ )
206
+ else:
207
+ query = f"prefix_length < {self.ip.prefix} AND {rhs} BETWEEN {self.ip.q_net} AND {self.ip.q_bcast}"
175
208
  return query, lhs_params + rhs_params
176
209
 
177
210
 
178
211
  class NetContainedOrEqual(NetworkFieldMixin, Lookup):
179
212
  lookup_name = "net_contained_or_equal"
180
213
 
181
- def as_sql(self, qn, connection):
182
- _, lhs_params = self.process_lhs(qn, connection)
183
- rhs, rhs_params = self.process_rhs(qn, connection)
184
- query = f"prefix_length >= {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
214
+ def as_sql(self, compiler, connection):
215
+ _, lhs_params = self.process_lhs(compiler, connection)
216
+ rhs, rhs_params = self.process_rhs(compiler, connection)
217
+ if self.alias:
218
+ query = f"{self.alias}.prefix_length >= {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
219
+ else:
220
+ query = f"prefix_length >= {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
185
221
  return query, lhs_params + rhs_params
186
222
 
187
223
 
188
224
  class NetContained(NetworkFieldMixin, Lookup):
189
225
  lookup_name = "net_contained"
190
226
 
191
- def as_sql(self, qn, connection):
192
- _, lhs_params = self.process_lhs(qn, connection)
193
- rhs, rhs_params = self.process_rhs(qn, connection)
194
- query = f"prefix_length > {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
227
+ def as_sql(self, compiler, connection):
228
+ _, lhs_params = self.process_lhs(compiler, connection)
229
+ rhs, rhs_params = self.process_rhs(compiler, connection)
230
+ if self.alias:
231
+ query = f"{self.alias}.prefix_length > {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
232
+ else:
233
+ query = f"prefix_length > {self.ip.prefix} AND {self.ip.q_net} BETWEEN {rhs} AND {self.ip.bcast_addr}"
195
234
  return query, lhs_params + rhs_params
196
235
 
197
236
 
@@ -205,19 +244,19 @@ class NetHost(Lookup):
205
244
  self.ip = get_ip_info(field_name, self.rhs, alias=self.lhs.alias)
206
245
  return str(self.ip.ip)
207
246
 
208
- def process_rhs(self, qn, connection):
209
- sql, params = super().process_rhs(qn, connection)
247
+ def process_rhs(self, compiler, connection):
248
+ sql, params = super().process_rhs(compiler, connection)
210
249
  params[0] = self.ip.rhs
211
250
  return sql, params
212
251
 
213
- def process_lhs(self, qn, connection, lhs=None):
252
+ def process_lhs(self, compiler, connection, lhs=None):
214
253
  lhs = lhs or self.lhs
215
- _, lhs_params = qn.compile(lhs)
254
+ _, lhs_params = compiler.compile(lhs)
216
255
  return self.ip.q_ip, lhs_params
217
256
 
218
- def as_sql(self, qn, connection):
219
- lhs, lhs_params = self.process_lhs(qn, connection)
220
- rhs, rhs_params = self.process_rhs(qn, connection)
257
+ def as_sql(self, compiler, connection):
258
+ lhs, lhs_params = self.process_lhs(compiler, connection)
259
+ rhs, rhs_params = self.process_rhs(compiler, connection)
221
260
  return f"{lhs} = {rhs}", lhs_params + rhs_params
222
261
 
223
262
 
@@ -242,9 +281,9 @@ class NetIn(Lookup):
242
281
  self.query_starter = "'1' != ANY(%s) AND "
243
282
  return self.rhs
244
283
 
245
- def as_sql(self, qn, connection):
246
- _, lhs_params = self.process_lhs(qn, connection)
247
- _, rhs_params = self.process_rhs(qn, connection)
284
+ def as_sql(self, compiler, connection):
285
+ _, lhs_params = self.process_lhs(compiler, connection)
286
+ _, rhs_params = self.process_rhs(compiler, connection)
248
287
  query = self.query_starter
249
288
  query += "OR ".join(f"{ip.q_ip} BETWEEN {ip.net_addr} AND {ip.bcast_addr} " for ip in self.ips)
250
289
  return query, lhs_params + rhs_params
@@ -253,9 +292,9 @@ class NetIn(Lookup):
253
292
  class NetHostContained(NetworkFieldMixin, Lookup):
254
293
  lookup_name = "net_host_contained"
255
294
 
256
- def as_sql(self, qn, connection):
257
- _, lhs_params = self.process_lhs(qn, connection)
258
- rhs, rhs_params = self.process_rhs(qn, connection)
295
+ def as_sql(self, compiler, connection):
296
+ _, lhs_params = self.process_lhs(compiler, connection)
297
+ rhs, rhs_params = self.process_rhs(compiler, connection)
259
298
  query = f"{self.ip.q_ip} BETWEEN {rhs} AND {self.ip.bcast_addr}"
260
299
  return query, lhs_params + rhs_params
261
300
 
@@ -270,12 +309,12 @@ class NetFamily(Lookup):
270
309
  self.rhs = 16
271
310
  return self.rhs
272
311
 
273
- def process_lhs(self, qn, connection, lhs=None):
312
+ def process_lhs(self, compiler, connection, lhs=None):
274
313
  lhs = lhs or self.lhs
275
- lhs_string, lhs_params = qn.compile(lhs)
314
+ lhs_string, lhs_params = compiler.compile(lhs)
276
315
  return f"LENGTH({lhs_string})", lhs_params
277
316
 
278
- def as_sql(self, qn, connection):
279
- lhs, lhs_params = self.process_lhs(qn, connection)
280
- rhs, rhs_params = self.process_rhs(qn, connection)
317
+ def as_sql(self, compiler, connection):
318
+ lhs, lhs_params = self.process_lhs(compiler, connection)
319
+ rhs, rhs_params = self.process_rhs(compiler, connection)
281
320
  return f"{lhs} = {rhs}", lhs_params + rhs_params
nautobot/ipam/tables.py CHANGED
@@ -442,13 +442,27 @@ class IPAddressTable(StatusTableMixin, RoleTableMixin, BaseTable):
442
442
  )
443
443
  tenant = TenantColumn()
444
444
  parent__namespace = tables.Column(linkify=True)
445
- # Interface, Device, and VirtualMachine tables aren't currently filterable by IP address (?) so no LinkedCountColumn
446
- interface_count = tables.Column(verbose_name="Interfaces")
447
- interface_parent_count = tables.Column(verbose_name="Devices")
445
+ interface_count = LinkedCountColumn(
446
+ viewname="dcim:interface_list", url_params={"ip_addresses": "pk"}, verbose_name="Interfaces"
447
+ )
448
+ # TODO: what about interfaces assigned to modules?
449
+ interface_parent_count = LinkedCountColumn(
450
+ viewname="dcim:device_list",
451
+ url_params={"ip_addresses": "pk"},
452
+ reverse_lookup="interfaces__ip_addresses",
453
+ distinct=True,
454
+ verbose_name="Devices",
455
+ )
448
456
  vm_interface_count = LinkedCountColumn(
449
457
  viewname="virtualization:vminterface_list", url_params={"ip_addresses": "pk"}, verbose_name="VM Interfaces"
450
458
  )
451
- vm_interface_parent_count = tables.Column(verbose_name="Virtual Machines")
459
+ vm_interface_parent_count = LinkedCountColumn(
460
+ viewname="virtualization:virtualmachine_list",
461
+ url_params={"ip_addresses": "pk"},
462
+ reverse_lookup="interfaces__ip_addresses",
463
+ distinct=True,
464
+ verbose_name="Virtual Machines",
465
+ )
452
466
 
453
467
  class Meta(BaseTable.Meta):
454
468
  model = IPAddress
@@ -1,13 +1,15 @@
1
1
  import re
2
2
  from unittest import skipIf
3
3
 
4
- from django.db import connection
4
+ from django.contrib.contenttypes.models import ContentType
5
+ from django.db import connection, transaction
5
6
  import netaddr
6
7
 
7
8
  from nautobot.core.testing import TestCase
8
9
  from nautobot.extras.models import Status
9
10
  from nautobot.ipam import choices
10
11
  from nautobot.ipam.models import IPAddress, Namespace, Prefix
12
+ from nautobot.users.models import ObjectPermission
11
13
 
12
14
 
13
15
  class IPAddressQuerySet(TestCase):
@@ -266,6 +268,28 @@ class IPAddressQuerySet(TestCase):
266
268
  [instance for ip, instance in self.ips.items() if "10.0.0" in ip],
267
269
  )
268
270
 
271
+ def test_lookup_not_ambiguous(self):
272
+ """Check for issues like https://github.com/nautobot/nautobot/issues/5166."""
273
+ obj_perm = ObjectPermission.objects.create(name="Test Permission", constraints={}, actions=["view"])
274
+ obj_perm.object_types.add(ContentType.objects.get_for_model(IPAddress))
275
+ obj_perm.users.add(self.user)
276
+ queryset = IPAddress.objects.select_related("parent", "nat_inside", "status")
277
+
278
+ for permission_constraint in (
279
+ {"host__family": 4},
280
+ {"host__net_host": "10.0.0.1"},
281
+ {"host__net_host_contained": "10.0.0.0/24"},
282
+ {"host__net_in": ["10.0.0.0/24"]},
283
+ ):
284
+ with self.subTest(permission_type=next(iter(permission_constraint.keys()))):
285
+ try:
286
+ with transaction.atomic():
287
+ obj_perm.constraints = permission_constraint
288
+ obj_perm.save()
289
+ list(queryset.restrict(self.user, "view"))
290
+ finally:
291
+ delattr(self.user, "_object_perm_cache")
292
+
269
293
  @skipIf(
270
294
  connection.vendor == "postgresql",
271
295
  "Not currently supported on postgresql",
@@ -648,6 +672,30 @@ class PrefixQuerysetTestCase(TestCase):
648
672
  prefix = Prefix.objects.filter(network__net_equals="192.168.0.0/16")[0]
649
673
  self.assertEqual(Prefix.objects.filter(prefix="192.168.0.0/16")[0], prefix)
650
674
 
675
+ def test_lookup_not_ambiguous(self):
676
+ """Check for issues like https://github.com/nautobot/nautobot/issues/5166."""
677
+ obj_perm = ObjectPermission.objects.create(name="Test Permission", constraints={}, actions=["view"])
678
+ obj_perm.object_types.add(ContentType.objects.get_for_model(Prefix))
679
+ obj_perm.users.add(self.user)
680
+ queryset = Prefix.objects.select_related("parent", "rir", "role", "status", "namespace")
681
+
682
+ for permission_constraint in (
683
+ {"network__family": 4},
684
+ {"network__net_equals": "192.168.0.0/16"},
685
+ {"network__net_contained": "192.0.0.0/8"},
686
+ {"network__net_contained_or_equal": "192.0.0.0/8"},
687
+ {"network__net_contains": "192.168.3.192/32"},
688
+ {"network__net_contains_or_equals": "192.168.3.192/32"},
689
+ ):
690
+ with self.subTest(permission_type=next(iter(permission_constraint.keys()))):
691
+ try:
692
+ with transaction.atomic():
693
+ obj_perm.constraints = permission_constraint
694
+ obj_perm.save()
695
+ list(queryset.restrict(self.user, "view"))
696
+ finally:
697
+ delattr(self.user, "_object_perm_cache")
698
+
651
699
  @skipIf(
652
700
  connection.vendor == "postgresql",
653
701
  "Not currently supported on postgresql",
@@ -4,6 +4,7 @@ import netaddr
4
4
  from nautobot.core.forms.utils import compress_range
5
5
  from nautobot.dcim.models import Interface
6
6
  from nautobot.extras.models import RelationshipAssociation
7
+ from nautobot.ipam.choices import PrefixTypeChoices
7
8
  from nautobot.ipam.models import Prefix, VLAN
8
9
  from nautobot.ipam.querysets import IPAddressQuerySet
9
10
  from nautobot.virtualization.models import VMInterface
@@ -25,6 +26,13 @@ def add_available_prefixes(parent, prefix_list):
25
26
  return prefix_list
26
27
 
27
28
 
29
+ def get_add_available_prefixes_callback(show_available, parent):
30
+ """Conditionally provide a callback for add_available_prefixes()."""
31
+ if show_available:
32
+ return lambda prefixes: add_available_prefixes(parent.prefix, prefixes)
33
+ return lambda prefixes: prefixes
34
+
35
+
28
36
  def add_available_ipaddresses(prefix, ipaddress_list, is_pool=False):
29
37
  """
30
38
  Annotate ranges of available IP addresses within a given prefix. If is_pool is True, the first and last IP will be
@@ -81,6 +89,15 @@ def add_available_ipaddresses(prefix, ipaddress_list, is_pool=False):
81
89
  return output
82
90
 
83
91
 
92
+ def get_add_available_ipaddresses_callback(show_available, parent):
93
+ """Conditionally provide a callback for add_available_ipaddresses()."""
94
+ if show_available:
95
+ return lambda ip_addresses: add_available_ipaddresses(
96
+ parent.prefix, ip_addresses, is_pool=(parent.type == PrefixTypeChoices.TYPE_POOL)
97
+ )
98
+ return lambda ip_addresses: ip_addresses
99
+
100
+
84
101
  def add_available_vlans(vlan_group, vlans):
85
102
  """
86
103
  Create fake records for all gaps between used VLANs
@@ -99,6 +116,13 @@ def add_available_vlans(vlan_group, vlans):
99
116
  return vlans
100
117
 
101
118
 
119
+ def get_add_available_vlans_callback(show_available, vlan_group):
120
+ """Conditionally provide a callback for add_available_vlans()."""
121
+ if show_available:
122
+ return lambda vlans: add_available_vlans(vlan_group=vlan_group, vlans=vlans)
123
+ return lambda vlans: vlans
124
+
125
+
102
126
  def handle_relationship_changes_when_merging_ips(merged_ip, merged_attributes, collapsed_ips):
103
127
  """
104
128
  Update/Delete RelationshipAssociation instances after we collapsed the IPs.