nautobot 2.2.3__py3-none-any.whl → 2.2.5__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.
- nautobot/circuits/forms.py +15 -0
- nautobot/circuits/navigation.py +9 -1
- nautobot/circuits/views.py +2 -0
- nautobot/core/filters.py +11 -0
- nautobot/core/settings.py +6 -4
- nautobot/core/settings.yaml +54 -19
- nautobot/core/templates/admin/base.html +2 -2
- nautobot/core/templates/base_django.html +2 -2
- nautobot/core/templates/buttons/export.html +47 -47
- nautobot/core/templates/inc/javascript.html +3 -0
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/login.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +2 -0
- nautobot/core/testing/filters.py +24 -1
- nautobot/core/testing/views.py +13 -1
- nautobot/core/tests/test_jobs.py +79 -2
- nautobot/core/tests/test_views.py +33 -0
- nautobot/core/views/mixins.py +4 -0
- nautobot/core/views/utils.py +18 -1
- nautobot/dcim/filters/__init__.py +1 -1
- nautobot/dcim/forms.py +23 -4
- nautobot/dcim/tables/devicetypes.py +15 -4
- nautobot/dcim/tests/test_views.py +323 -55
- nautobot/dcim/views.py +26 -20
- nautobot/extras/api/serializers.py +17 -6
- nautobot/extras/api/views.py +2 -2
- nautobot/extras/context_managers.py +3 -0
- nautobot/extras/filters/__init__.py +15 -1
- nautobot/extras/forms/forms.py +33 -0
- nautobot/extras/forms/mixins.py +0 -6
- nautobot/extras/signals.py +6 -1
- nautobot/extras/tests/test_api.py +24 -2
- nautobot/extras/tests/test_context_managers.py +51 -1
- nautobot/extras/tests/test_filters.py +69 -0
- nautobot/extras/tests/test_forms.py +0 -3
- nautobot/extras/tests/test_views.py +48 -4
- nautobot/extras/utils.py +2 -1
- nautobot/extras/views.py +47 -31
- nautobot/ipam/forms.py +18 -0
- nautobot/ipam/tests/test_views.py +9 -2
- nautobot/ipam/views.py +17 -6
- nautobot/project-static/docs/404.html +107 -51
- nautobot/project-static/docs/apps/index.html +107 -51
- nautobot/project-static/docs/apps/nautobot-apps.html +107 -51
- nautobot/project-static/docs/assets/_mkdocstrings.css +6 -1
- nautobot/project-static/docs/assets/extra.css +7 -0
- nautobot/project-static/docs/assets/javascripts/bundle.ebd0bdb7.min.js +29 -0
- nautobot/project-static/docs/assets/javascripts/bundle.ebd0bdb7.min.js.map +7 -0
- nautobot/project-static/docs/assets/stylesheets/main.6543a935.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.6543a935.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +107 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +107 -51
- nautobot/project-static/docs/development/apps/api/configuration-view.html +110 -54
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +107 -51
- nautobot/project-static/docs/development/apps/api/models/global-search.html +110 -54
- nautobot/project-static/docs/development/apps/api/models/graphql.html +113 -57
- nautobot/project-static/docs/development/apps/api/models/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +113 -57
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +111 -55
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +110 -54
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +107 -51
- nautobot/project-static/docs/development/apps/api/prometheus.html +110 -54
- nautobot/project-static/docs/development/apps/api/setup.html +107 -51
- nautobot/project-static/docs/development/apps/api/testing.html +113 -57
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +110 -54
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +107 -51
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/base-template.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/index.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +113 -57
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +122 -66
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/notes.html +110 -54
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +107 -51
- nautobot/project-static/docs/development/apps/api/views/urls.html +107 -51
- nautobot/project-static/docs/development/apps/index.html +128 -72
- nautobot/project-static/docs/development/apps/migration/code-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +107 -51
- nautobot/project-static/docs/development/apps/migration/from-v1.html +109 -53
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +107 -51
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +107 -51
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +110 -54
- nautobot/project-static/docs/development/core/application-registry.html +120 -64
- nautobot/project-static/docs/development/core/best-practices.html +122 -66
- nautobot/project-static/docs/development/core/bootstrap-ui.html +107 -51
- nautobot/project-static/docs/development/core/caching.html +107 -51
- nautobot/project-static/docs/development/core/controllers.html +107 -51
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +113 -57
- nautobot/project-static/docs/development/core/generic-views.html +110 -54
- nautobot/project-static/docs/development/core/getting-started.html +137 -81
- nautobot/project-static/docs/development/core/homepage.html +110 -54
- nautobot/project-static/docs/development/core/index.html +107 -51
- nautobot/project-static/docs/development/core/model-checklist.html +107 -51
- nautobot/project-static/docs/development/core/model-features.html +107 -51
- nautobot/project-static/docs/development/core/natural-keys.html +110 -54
- nautobot/project-static/docs/development/core/navigation-menu.html +107 -51
- nautobot/project-static/docs/development/core/release-checklist.html +107 -51
- nautobot/project-static/docs/development/core/role-internals.html +107 -51
- nautobot/project-static/docs/development/core/settings.html +107 -51
- nautobot/project-static/docs/development/core/style-guide.html +110 -54
- nautobot/project-static/docs/development/core/templates.html +113 -57
- nautobot/project-static/docs/development/core/testing.html +126 -70
- nautobot/project-static/docs/development/core/user-preferences.html +107 -51
- nautobot/project-static/docs/development/index.html +107 -51
- nautobot/project-static/docs/development/jobs/index.html +173 -117
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +110 -54
- nautobot/project-static/docs/docker/index.html +3 -3
- nautobot/project-static/docs/index.html +125 -69
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +3 -3
- nautobot/project-static/docs/release-notes/index.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.0.html +108 -52
- nautobot/project-static/docs/release-notes/version-1.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-1.2.html +109 -53
- nautobot/project-static/docs/release-notes/version-1.3.html +108 -52
- nautobot/project-static/docs/release-notes/version-1.4.html +109 -53
- nautobot/project-static/docs/release-notes/version-1.5.html +118 -62
- nautobot/project-static/docs/release-notes/version-1.6.html +721 -285
- nautobot/project-static/docs/release-notes/version-2.0.html +113 -57
- nautobot/project-static/docs/release-notes/version-2.1.html +107 -51
- nautobot/project-static/docs/release-notes/version-2.2.html +503 -120
- nautobot/project-static/docs/requirements.txt +4 -4
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +262 -262
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +107 -51
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +109 -53
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +108 -52
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +254 -167
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +113 -57
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +113 -57
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +108 -52
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +107 -51
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +107 -51
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +171 -112
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +13 -8626
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +117 -61
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +13 -8614
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +252 -165
- nautobot/project-static/docs/user-guide/administration/installation/index.html +165 -192
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +411 -691
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +249 -230
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +13 -8118
- nautobot/project-static/docs/user-guide/administration/installation/services.html +351 -241
- nautobot/project-static/docs/user-guide/administration/installation-extras/docker.html +8684 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/health-checks.html +8672 -0
- nautobot/project-static/docs/user-guide/administration/installation-extras/selinux-troubleshooting.html +8176 -0
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +110 -54
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +110 -54
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +155 -99
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +109 -53
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +108 -52
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +107 -51
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +107 -70
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +115 -59
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +115 -59
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +117 -61
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +119 -63
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +125 -69
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +128 -72
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +116 -60
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +110 -54
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +107 -51
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +113 -57
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +108 -52
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +108 -52
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +113 -57
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +107 -51
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +110 -54
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +107 -51
- nautobot/project-static/docs/user-guide/index.html +109 -53
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +128 -72
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +125 -69
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +128 -72
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +114 -58
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +113 -57
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +121 -65
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +109 -53
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +131 -75
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +149 -93
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +108 -84
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +116 -60
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +119 -63
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +137 -81
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +110 -54
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +107 -51
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +110 -54
- nautobot/project-static/js/forms.js +2 -1
- nautobot/tenancy/forms.py +9 -0
- nautobot/tenancy/views.py +3 -6
- nautobot/virtualization/forms.py +18 -6
- nautobot/virtualization/templates/virtualization/clustertype.html +2 -2
- nautobot/virtualization/views.py +7 -9
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/METADATA +2 -2
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/RECORD +323 -320
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js +0 -29
- nautobot/project-static/docs/assets/javascripts/bundle.bd41221c.min.js.map +0 -7
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +0 -1
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/NOTICE +0 -0
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/WHEEL +0 -0
- {nautobot-2.2.3.dist-info → nautobot-2.2.5.dist-info}/entry_points.txt +0 -0
|
@@ -17,6 +17,7 @@ from nautobot.core.choices import ColorChoices
|
|
|
17
17
|
from nautobot.core.models.fields import slugify_dashes_to_underscores
|
|
18
18
|
from nautobot.core.testing import extract_form_failures, extract_page_body, TestCase, ViewTestCases
|
|
19
19
|
from nautobot.core.testing.utils import disable_warnings, post_data
|
|
20
|
+
from nautobot.core.utils.permissions import get_permission_for_model
|
|
20
21
|
from nautobot.dcim.models import (
|
|
21
22
|
ConsolePort,
|
|
22
23
|
Controller,
|
|
@@ -777,9 +778,11 @@ class DynamicGroupTestCase(
|
|
|
777
778
|
content_type = ContentType.objects.get_for_model(Device)
|
|
778
779
|
|
|
779
780
|
# DynamicGroup objects to test.
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
781
|
+
cls.dynamic_groups = [
|
|
782
|
+
DynamicGroup.objects.create(name="DG 1", content_type=content_type),
|
|
783
|
+
DynamicGroup.objects.create(name="DG 2", content_type=content_type),
|
|
784
|
+
DynamicGroup.objects.create(name="DG 3", content_type=content_type),
|
|
785
|
+
]
|
|
783
786
|
|
|
784
787
|
cls.form_data = {
|
|
785
788
|
"name": "new_dynamic_group",
|
|
@@ -792,6 +795,38 @@ class DynamicGroupTestCase(
|
|
|
792
795
|
"dynamic_group_memberships-MAX_NUM_FORMS": "1000",
|
|
793
796
|
}
|
|
794
797
|
|
|
798
|
+
def test_get_object_with_permission(self):
|
|
799
|
+
instance = self._get_queryset().first()
|
|
800
|
+
# Add view permissions for the group's members:
|
|
801
|
+
self.add_permissions(get_permission_for_model(instance.content_type.model_class(), "view"))
|
|
802
|
+
|
|
803
|
+
response = super().test_get_object_with_permission()
|
|
804
|
+
|
|
805
|
+
response_body = extract_page_body(response.content.decode(response.charset))
|
|
806
|
+
# Check that the "members" table in the detail view includes all appropriate member objects
|
|
807
|
+
for member in instance.members:
|
|
808
|
+
self.assertIn(str(member.pk), response_body)
|
|
809
|
+
|
|
810
|
+
def test_get_object_with_constrained_permission(self):
|
|
811
|
+
instance = self._get_queryset().first()
|
|
812
|
+
# Add view permission for one of the group's members but not the others:
|
|
813
|
+
member1, member2 = instance.members[:2]
|
|
814
|
+
obj_perm = ObjectPermission(
|
|
815
|
+
name="Members permission",
|
|
816
|
+
constraints={"pk": member1.pk},
|
|
817
|
+
actions=["view"],
|
|
818
|
+
)
|
|
819
|
+
obj_perm.save()
|
|
820
|
+
obj_perm.users.add(self.user)
|
|
821
|
+
obj_perm.object_types.add(instance.content_type)
|
|
822
|
+
|
|
823
|
+
response = super().test_get_object_with_constrained_permission()
|
|
824
|
+
|
|
825
|
+
response_body = extract_page_body(response.content.decode(response.charset))
|
|
826
|
+
# Check that the "members" table in the detail view includes all permitted member objects
|
|
827
|
+
self.assertIn(str(member1.pk), response_body)
|
|
828
|
+
self.assertNotIn(str(member2.pk), response_body)
|
|
829
|
+
|
|
795
830
|
def test_get_object_dynamic_groups_anonymous(self):
|
|
796
831
|
url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
|
|
797
832
|
self.client.logout()
|
|
@@ -815,7 +850,6 @@ class DynamicGroupTestCase(
|
|
|
815
850
|
self.assertIn("DG 3", response_body, msg=response_body)
|
|
816
851
|
|
|
817
852
|
def test_get_object_dynamic_groups_with_constrained_permission(self):
|
|
818
|
-
self.add_permissions("extras.view_dynamicgroup")
|
|
819
853
|
obj_perm = ObjectPermission(
|
|
820
854
|
name="View a device",
|
|
821
855
|
constraints={"pk": Device.objects.first().pk},
|
|
@@ -824,12 +858,22 @@ class DynamicGroupTestCase(
|
|
|
824
858
|
obj_perm.save()
|
|
825
859
|
obj_perm.users.add(self.user)
|
|
826
860
|
obj_perm.object_types.add(ContentType.objects.get_for_model(Device))
|
|
861
|
+
obj_perm_2 = ObjectPermission(
|
|
862
|
+
name="View a Dynamic Group",
|
|
863
|
+
constraints={"pk": self.dynamic_groups[0].pk},
|
|
864
|
+
actions=["view"],
|
|
865
|
+
)
|
|
866
|
+
obj_perm_2.save()
|
|
867
|
+
obj_perm_2.users.add(self.user)
|
|
868
|
+
obj_perm_2.object_types.add(ContentType.objects.get_for_model(DynamicGroup))
|
|
827
869
|
|
|
828
870
|
url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.first().pk})
|
|
829
871
|
response = self.client.get(url)
|
|
830
872
|
self.assertHttpStatus(response, 200)
|
|
831
873
|
response_body = response.content.decode(response.charset)
|
|
832
874
|
self.assertIn("DG 1", response_body, msg=response_body)
|
|
875
|
+
self.assertNotIn("DG 2", response_body, msg=response_body)
|
|
876
|
+
self.assertNotIn("DG 3", response_body, msg=response_body)
|
|
833
877
|
|
|
834
878
|
url = reverse("dcim:device_dynamicgroups", kwargs={"pk": Device.objects.last().pk})
|
|
835
879
|
response = self.client.get(url)
|
nautobot/extras/utils.py
CHANGED
|
@@ -637,7 +637,8 @@ def bulk_delete_with_bulk_change_logging(qs, batch_size=1000):
|
|
|
637
637
|
ObjectChange.objects.bulk_create(queued_object_changes)
|
|
638
638
|
queued_object_changes = []
|
|
639
639
|
oc = obj.to_objectchange(ObjectChangeActionChoices.ACTION_DELETE)
|
|
640
|
-
oc.user = change_context.
|
|
640
|
+
oc.user = change_context.get_user()
|
|
641
|
+
oc.user_name = oc.user.username
|
|
641
642
|
oc.request_id = change_context.change_id
|
|
642
643
|
oc.change_context = change_context.context
|
|
643
644
|
oc.change_context_detail = change_context.context_detail[:CHANGELOG_MAX_CHANGE_CONTEXT_DETAIL]
|
nautobot/extras/views.py
CHANGED
|
@@ -56,8 +56,6 @@ from .datasources import (
|
|
|
56
56
|
enqueue_pull_git_repository_and_refresh_data,
|
|
57
57
|
get_datasource_contents,
|
|
58
58
|
)
|
|
59
|
-
from .filters import RoleFilterSet
|
|
60
|
-
from .forms import RoleBulkEditForm, RoleForm
|
|
61
59
|
from .jobs import get_job
|
|
62
60
|
from .models import (
|
|
63
61
|
ComputedField,
|
|
@@ -94,7 +92,6 @@ from .models import (
|
|
|
94
92
|
Webhook,
|
|
95
93
|
)
|
|
96
94
|
from .registry import registry
|
|
97
|
-
from .tables import AssociatedContactsTable, RoleTable
|
|
98
95
|
|
|
99
96
|
logger = logging.getLogger(__name__)
|
|
100
97
|
|
|
@@ -152,19 +149,18 @@ class ConfigContextView(generic.ObjectView):
|
|
|
152
149
|
queryset = ConfigContext.objects.all()
|
|
153
150
|
|
|
154
151
|
def get_extra_context(self, request, instance):
|
|
152
|
+
context = super().get_extra_context(request, instance)
|
|
155
153
|
# Determine user's preferred output format
|
|
156
154
|
if request.GET.get("format") in ["json", "yaml"]:
|
|
157
|
-
|
|
155
|
+
context["format"] = request.GET.get("format")
|
|
158
156
|
if request.user.is_authenticated:
|
|
159
|
-
request.user.set_config("extras.configcontext.format",
|
|
157
|
+
request.user.set_config("extras.configcontext.format", context["format"], commit=True)
|
|
160
158
|
elif request.user.is_authenticated:
|
|
161
|
-
|
|
159
|
+
context["format"] = request.user.get_config("extras.configcontext.format", "json")
|
|
162
160
|
else:
|
|
163
|
-
|
|
161
|
+
context["format"] = "json"
|
|
164
162
|
|
|
165
|
-
return
|
|
166
|
-
"format": format_,
|
|
167
|
-
}
|
|
163
|
+
return context
|
|
168
164
|
|
|
169
165
|
|
|
170
166
|
class ConfigContextEditView(generic.ObjectEditView):
|
|
@@ -236,19 +232,18 @@ class ConfigContextSchemaView(generic.ObjectView):
|
|
|
236
232
|
queryset = ConfigContextSchema.objects.all()
|
|
237
233
|
|
|
238
234
|
def get_extra_context(self, request, instance):
|
|
235
|
+
context = super().get_extra_context(request, instance)
|
|
239
236
|
# Determine user's preferred output format
|
|
240
237
|
if request.GET.get("format") in ["json", "yaml"]:
|
|
241
|
-
|
|
238
|
+
context["format"] = request.GET.get("format")
|
|
242
239
|
if request.user.is_authenticated:
|
|
243
|
-
request.user.set_config("extras.configcontextschema.format",
|
|
240
|
+
request.user.set_config("extras.configcontextschema.format", context["format"], commit=True)
|
|
244
241
|
elif request.user.is_authenticated:
|
|
245
|
-
|
|
242
|
+
context["format"] = request.user.get_config("extras.configcontextschema.format", "json")
|
|
246
243
|
else:
|
|
247
|
-
|
|
244
|
+
context["format"] = "json"
|
|
248
245
|
|
|
249
|
-
return
|
|
250
|
-
"format": format_,
|
|
251
|
-
}
|
|
246
|
+
return context
|
|
252
247
|
|
|
253
248
|
|
|
254
249
|
class ConfigContextSchemaObjectValidationView(generic.ObjectView):
|
|
@@ -400,7 +395,7 @@ class ContactAssociationUIViewSet(
|
|
|
400
395
|
filterset_class = filters.ContactAssociationFilterSet
|
|
401
396
|
queryset = ContactAssociation.objects.all()
|
|
402
397
|
serializer_class = serializers.ContactAssociationSerializer
|
|
403
|
-
table_class = AssociatedContactsTable
|
|
398
|
+
table_class = tables.AssociatedContactsTable
|
|
404
399
|
non_filter_params = ("export", "page", "per_page", "sort")
|
|
405
400
|
|
|
406
401
|
|
|
@@ -508,6 +503,7 @@ class CustomFieldListView(generic.ObjectListView):
|
|
|
508
503
|
queryset = CustomField.objects.all()
|
|
509
504
|
table = tables.CustomFieldTable
|
|
510
505
|
filterset = filters.CustomFieldFilterSet
|
|
506
|
+
filterset_form = forms.CustomFieldFilterForm
|
|
511
507
|
action_buttons = ("add",)
|
|
512
508
|
|
|
513
509
|
|
|
@@ -708,7 +704,7 @@ class DynamicGroupView(generic.ObjectView):
|
|
|
708
704
|
|
|
709
705
|
if table_class is not None:
|
|
710
706
|
# Members table (for display on Members nav tab)
|
|
711
|
-
members_table = table_class(instance.members, orderable=False)
|
|
707
|
+
members_table = table_class(instance.members.restrict(request.user, "view"), orderable=False)
|
|
712
708
|
paginate = {
|
|
713
709
|
"paginator_class": EnhancedPaginator,
|
|
714
710
|
"per_page": get_paginate_count(request),
|
|
@@ -888,7 +884,9 @@ class ObjectDynamicGroupsView(generic.GenericView):
|
|
|
888
884
|
obj = get_object_or_404(model, **kwargs)
|
|
889
885
|
|
|
890
886
|
# Gather all dynamic groups for this object (and its related objects)
|
|
891
|
-
dynamicsgroups_table = tables.DynamicGroupTable(
|
|
887
|
+
dynamicsgroups_table = tables.DynamicGroupTable(
|
|
888
|
+
data=obj.dynamic_groups_cached.restrict(request.user, "view"), orderable=False
|
|
889
|
+
)
|
|
892
890
|
|
|
893
891
|
# Apply the request context
|
|
894
892
|
paginate = {
|
|
@@ -952,6 +950,7 @@ class ExportTemplateBulkDeleteView(generic.BulkDeleteView):
|
|
|
952
950
|
class ExternalIntegrationUIViewSet(NautobotUIViewSet):
|
|
953
951
|
bulk_update_form_class = forms.ExternalIntegrationBulkEditForm
|
|
954
952
|
filterset_class = filters.ExternalIntegrationFilterSet
|
|
953
|
+
filterset_form_class = forms.ExternalIntegrationFilterForm
|
|
955
954
|
form_class = forms.ExternalIntegrationForm
|
|
956
955
|
queryset = ExternalIntegration.objects.select_related("secrets_group")
|
|
957
956
|
serializer_class = serializers.ExternalIntegrationSerializer
|
|
@@ -994,6 +993,7 @@ class GitRepositoryView(generic.ObjectView):
|
|
|
994
993
|
def get_extra_context(self, request, instance):
|
|
995
994
|
return {
|
|
996
995
|
"datasource_contents": get_datasource_contents("extras.gitrepository"),
|
|
996
|
+
**super().get_extra_context(request, instance),
|
|
997
997
|
}
|
|
998
998
|
|
|
999
999
|
|
|
@@ -1520,9 +1520,7 @@ class JobApprovalRequestView(generic.ObjectView):
|
|
|
1520
1520
|
else:
|
|
1521
1521
|
job_form = None
|
|
1522
1522
|
|
|
1523
|
-
return {
|
|
1524
|
-
"job_form": job_form,
|
|
1525
|
-
}
|
|
1523
|
+
return {"job_form": job_form, **super().get_extra_context(request, instance)}
|
|
1526
1524
|
|
|
1527
1525
|
def post(self, request, pk):
|
|
1528
1526
|
"""
|
|
@@ -1652,7 +1650,11 @@ class ScheduledJobView(generic.ObjectView):
|
|
|
1652
1650
|
labels[name] = field.label
|
|
1653
1651
|
else:
|
|
1654
1652
|
labels[name] = pretty_name(name)
|
|
1655
|
-
return {
|
|
1653
|
+
return {
|
|
1654
|
+
"labels": labels,
|
|
1655
|
+
"job_class_found": (job_class is not None),
|
|
1656
|
+
**super().get_extra_context(request, instance),
|
|
1657
|
+
}
|
|
1656
1658
|
|
|
1657
1659
|
|
|
1658
1660
|
class ScheduledJobDeleteView(generic.ObjectDeleteView):
|
|
@@ -1676,7 +1678,10 @@ class JobHookView(generic.ObjectView):
|
|
|
1676
1678
|
queryset = JobHook.objects.all()
|
|
1677
1679
|
|
|
1678
1680
|
def get_extra_context(self, request, instance):
|
|
1679
|
-
return {
|
|
1681
|
+
return {
|
|
1682
|
+
"content_types": instance.content_types.order_by("app_label", "model"),
|
|
1683
|
+
**super().get_extra_context(request, instance),
|
|
1684
|
+
}
|
|
1680
1685
|
|
|
1681
1686
|
|
|
1682
1687
|
class JobHookEditView(generic.ObjectEditView):
|
|
@@ -1761,6 +1766,7 @@ class JobResultView(generic.ObjectView):
|
|
|
1761
1766
|
"job": job_class,
|
|
1762
1767
|
"associated_record": associated_record,
|
|
1763
1768
|
"result": instance,
|
|
1769
|
+
**super().get_extra_context(request, instance),
|
|
1764
1770
|
}
|
|
1765
1771
|
|
|
1766
1772
|
|
|
@@ -1848,6 +1854,7 @@ class ObjectChangeView(generic.ObjectView):
|
|
|
1848
1854
|
"prev_change": instance.get_prev_change(request.user),
|
|
1849
1855
|
"related_changes_table": related_changes_table,
|
|
1850
1856
|
"related_changes_count": related_changes.count(),
|
|
1857
|
+
**super().get_extra_context(request, instance),
|
|
1851
1858
|
}
|
|
1852
1859
|
|
|
1853
1860
|
|
|
@@ -2042,11 +2049,12 @@ class RoleUIViewSet(viewsets.NautobotUIViewSet):
|
|
|
2042
2049
|
"""`Roles` UIViewSet."""
|
|
2043
2050
|
|
|
2044
2051
|
queryset = Role.objects.all()
|
|
2045
|
-
bulk_update_form_class = RoleBulkEditForm
|
|
2046
|
-
filterset_class = RoleFilterSet
|
|
2047
|
-
|
|
2052
|
+
bulk_update_form_class = forms.RoleBulkEditForm
|
|
2053
|
+
filterset_class = filters.RoleFilterSet
|
|
2054
|
+
filterset_form_class = forms.RoleFilterForm
|
|
2055
|
+
form_class = forms.RoleForm
|
|
2048
2056
|
serializer_class = serializers.RoleSerializer
|
|
2049
|
-
table_class = RoleTable
|
|
2057
|
+
table_class = tables.RoleTable
|
|
2050
2058
|
|
|
2051
2059
|
def get_extra_context(self, request, instance):
|
|
2052
2060
|
context = super().get_extra_context(request, instance)
|
|
@@ -2192,6 +2200,7 @@ class SecretView(generic.ObjectView):
|
|
|
2192
2200
|
"format": format_,
|
|
2193
2201
|
"provider_name": provider.name if provider else instance.provider,
|
|
2194
2202
|
"groups_table": groups_table,
|
|
2203
|
+
**super().get_extra_context(request, instance),
|
|
2195
2204
|
}
|
|
2196
2205
|
|
|
2197
2206
|
|
|
@@ -2407,7 +2416,10 @@ class StatusView(generic.ObjectView):
|
|
|
2407
2416
|
|
|
2408
2417
|
def get_extra_context(self, request, instance):
|
|
2409
2418
|
"""Return ordered content types."""
|
|
2410
|
-
return {
|
|
2419
|
+
return {
|
|
2420
|
+
"content_types": instance.content_types.order_by("app_label", "model"),
|
|
2421
|
+
**super().get_extra_context(request, instance),
|
|
2422
|
+
}
|
|
2411
2423
|
|
|
2412
2424
|
|
|
2413
2425
|
#
|
|
@@ -2442,6 +2454,7 @@ class TagView(generic.ObjectView):
|
|
|
2442
2454
|
"items_count": tagged_items.count(),
|
|
2443
2455
|
"items_table": items_table,
|
|
2444
2456
|
"content_types": instance.content_types.order_by("app_label", "model"),
|
|
2457
|
+
**super().get_extra_context(request, instance),
|
|
2445
2458
|
}
|
|
2446
2459
|
|
|
2447
2460
|
|
|
@@ -2522,7 +2535,10 @@ class WebhookView(generic.ObjectView):
|
|
|
2522
2535
|
queryset = Webhook.objects.all()
|
|
2523
2536
|
|
|
2524
2537
|
def get_extra_context(self, request, instance):
|
|
2525
|
-
return {
|
|
2538
|
+
return {
|
|
2539
|
+
"content_types": instance.content_types.order_by("app_label", "model"),
|
|
2540
|
+
**super().get_extra_context(request, instance),
|
|
2541
|
+
}
|
|
2526
2542
|
|
|
2527
2543
|
|
|
2528
2544
|
class WebhookEditView(generic.ObjectEditView):
|
nautobot/ipam/forms.py
CHANGED
|
@@ -94,6 +94,12 @@ class NamespaceBulkEditForm(
|
|
|
94
94
|
]
|
|
95
95
|
|
|
96
96
|
|
|
97
|
+
class NamespaceFilterForm(LocatableModelFilterFormMixin, NautobotFilterForm):
|
|
98
|
+
model = Namespace
|
|
99
|
+
q = forms.CharField(required=False, label="Search")
|
|
100
|
+
name = forms.CharField(required=False)
|
|
101
|
+
|
|
102
|
+
|
|
97
103
|
#
|
|
98
104
|
# VRFs
|
|
99
105
|
#
|
|
@@ -142,6 +148,12 @@ class VRFBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
|
142
148
|
namespace = DynamicModelChoiceField(queryset=Namespace.objects.all(), required=False)
|
|
143
149
|
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
144
150
|
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
151
|
+
add_prefixes = DynamicModelMultipleChoiceField(
|
|
152
|
+
queryset=Prefix.objects.all(), required=False, query_params={"namespace": "$namespace"}
|
|
153
|
+
)
|
|
154
|
+
remove_prefixes = DynamicModelMultipleChoiceField(
|
|
155
|
+
queryset=Prefix.objects.all(), required=False, query_params={"namespace": "$namespace"}
|
|
156
|
+
)
|
|
145
157
|
|
|
146
158
|
class Meta:
|
|
147
159
|
nullable_fields = [
|
|
@@ -358,6 +370,12 @@ class PrefixBulkEditForm(
|
|
|
358
370
|
remove_locations = DynamicModelMultipleChoiceField(
|
|
359
371
|
queryset=Location.objects.all(), required=False, query_params={"content_type": Prefix._meta.label_lower}
|
|
360
372
|
)
|
|
373
|
+
add_vrfs = DynamicModelMultipleChoiceField(
|
|
374
|
+
queryset=VRF.objects.all(), required=False, query_params={"namespace": "$namespace"}
|
|
375
|
+
)
|
|
376
|
+
remove_vrfs = DynamicModelMultipleChoiceField(
|
|
377
|
+
queryset=VRF.objects.all(), required=False, query_params={"namespace": "$namespace"}
|
|
378
|
+
)
|
|
361
379
|
tenant = DynamicModelChoiceField(queryset=Tenant.objects.all(), required=False)
|
|
362
380
|
rir = DynamicModelChoiceField(queryset=RIR.objects.all(), required=False, label="RIR")
|
|
363
381
|
date_allocated = forms.DateTimeField(required=False, widget=DateTimePicker)
|
|
@@ -71,7 +71,8 @@ class VRFTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
71
71
|
@classmethod
|
|
72
72
|
def setUpTestData(cls):
|
|
73
73
|
tenants = Tenant.objects.all()[:2]
|
|
74
|
-
namespace =
|
|
74
|
+
namespace = Prefix.objects.first().namespace
|
|
75
|
+
prefixes = Prefix.objects.filter(namespace=namespace)
|
|
75
76
|
|
|
76
77
|
cls.form_data = {
|
|
77
78
|
"name": "VRF X",
|
|
@@ -79,12 +80,16 @@ class VRFTestCase(ViewTestCases.PrimaryObjectViewTestCase):
|
|
|
79
80
|
"rd": "65000:999",
|
|
80
81
|
"tenant": tenants[0].pk,
|
|
81
82
|
"description": "A new VRF",
|
|
83
|
+
"prefixes": [prefixes[1].id],
|
|
82
84
|
"tags": [t.pk for t in Tag.objects.get_for_model(VRF)],
|
|
83
85
|
}
|
|
84
86
|
|
|
85
87
|
cls.bulk_edit_data = {
|
|
86
88
|
"tenant": tenants[1].pk,
|
|
87
89
|
"description": "New description",
|
|
90
|
+
"namespace": prefixes[0].namespace.id,
|
|
91
|
+
"add_prefixes": [prefixes[0].id],
|
|
92
|
+
"remove_prefixes": [prefixes[1].id],
|
|
88
93
|
}
|
|
89
94
|
|
|
90
95
|
|
|
@@ -158,7 +163,6 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
|
|
|
158
163
|
|
|
159
164
|
cls.bulk_edit_data = {
|
|
160
165
|
"tenant": None,
|
|
161
|
-
# TODO "vrf": vrfs[1].pk,
|
|
162
166
|
"status": cls.statuses[1].pk,
|
|
163
167
|
"role": cls.roles[1].pk,
|
|
164
168
|
"rir": RIR.objects.last().pk,
|
|
@@ -166,6 +170,9 @@ class PrefixTestCase(ViewTestCases.PrimaryObjectViewTestCase, ViewTestCases.List
|
|
|
166
170
|
"description": "New description",
|
|
167
171
|
"add_locations": [cls.locations[0].pk],
|
|
168
172
|
"remove_locations": [cls.locations[1].pk],
|
|
173
|
+
"namespace": vrfs[0].namespace.pk,
|
|
174
|
+
"add_vrfs": [vrfs[0].pk],
|
|
175
|
+
"remove_vrfs": [vrfs[1].pk],
|
|
169
176
|
}
|
|
170
177
|
|
|
171
178
|
@override_settings(EXEMPT_VIEW_PERMISSIONS=["*"])
|
nautobot/ipam/views.py
CHANGED
|
@@ -80,6 +80,7 @@ class NamespaceUIViewSet(
|
|
|
80
80
|
form_class = forms.NamespaceForm
|
|
81
81
|
bulk_update_form_class = forms.NamespaceBulkEditForm
|
|
82
82
|
filterset_class = filters.NamespaceFilterSet
|
|
83
|
+
filterset_form_class = forms.NamespaceFilterForm
|
|
83
84
|
queryset = Namespace.objects.all()
|
|
84
85
|
serializer_class = serializers.NamespaceSerializer
|
|
85
86
|
table_class = tables.NamespaceTable
|
|
@@ -303,6 +304,12 @@ class VRFBulkEditView(generic.BulkEditView):
|
|
|
303
304
|
table = tables.VRFTable
|
|
304
305
|
form = forms.VRFBulkEditForm
|
|
305
306
|
|
|
307
|
+
def extra_post_save_action(self, obj, form):
|
|
308
|
+
if form.cleaned_data.get("add_prefixes", None):
|
|
309
|
+
obj.prefixes.add(*form.cleaned_data["add_prefixes"])
|
|
310
|
+
if form.cleaned_data.get("remove_prefixes", None):
|
|
311
|
+
obj.prefixes.remove(*form.cleaned_data["remove_prefixes"])
|
|
312
|
+
|
|
306
313
|
|
|
307
314
|
class VRFBulkDeleteView(generic.BulkDeleteView):
|
|
308
315
|
queryset = VRF.objects.select_related("tenant")
|
|
@@ -332,6 +339,7 @@ class RouteTargetView(generic.ObjectView):
|
|
|
332
339
|
return {
|
|
333
340
|
"importing_vrfs_table": importing_vrfs_table,
|
|
334
341
|
"exporting_vrfs_table": exporting_vrfs_table,
|
|
342
|
+
**super().get_extra_context(request, instance),
|
|
335
343
|
}
|
|
336
344
|
|
|
337
345
|
|
|
@@ -389,9 +397,7 @@ class RIRView(generic.ObjectView):
|
|
|
389
397
|
}
|
|
390
398
|
RequestConfig(request, paginate).configure(assigned_prefix_table)
|
|
391
399
|
|
|
392
|
-
return {
|
|
393
|
-
"assigned_prefix_table": assigned_prefix_table,
|
|
394
|
-
}
|
|
400
|
+
return {"assigned_prefix_table": assigned_prefix_table, **super().get_extra_context(request, instance)}
|
|
395
401
|
|
|
396
402
|
|
|
397
403
|
class RIREditView(generic.ObjectEditView):
|
|
@@ -457,6 +463,7 @@ class PrefixView(generic.ObjectView):
|
|
|
457
463
|
return {
|
|
458
464
|
"vrf_table": vrf_table,
|
|
459
465
|
"parent_prefix_table": parent_prefix_table,
|
|
466
|
+
**super().get_extra_context(request, instance),
|
|
460
467
|
}
|
|
461
468
|
|
|
462
469
|
|
|
@@ -713,6 +720,10 @@ class PrefixBulkEditView(generic.BulkEditView):
|
|
|
713
720
|
obj.locations.add(*form.cleaned_data["add_locations"])
|
|
714
721
|
if form.cleaned_data.get("remove_locations", None):
|
|
715
722
|
obj.locations.remove(*form.cleaned_data["remove_locations"])
|
|
723
|
+
if form.cleaned_data.get("add_vrfs", None):
|
|
724
|
+
obj.vrfs.add(*form.cleaned_data["add_vrfs"])
|
|
725
|
+
if form.cleaned_data.get("remove_vrfs", None):
|
|
726
|
+
obj.vrfs.remove(*form.cleaned_data["remove_vrfs"])
|
|
716
727
|
|
|
717
728
|
|
|
718
729
|
class PrefixBulkDeleteView(generic.BulkDeleteView):
|
|
@@ -780,6 +791,7 @@ class IPAddressView(generic.ObjectView):
|
|
|
780
791
|
return {
|
|
781
792
|
"parent_prefixes_table": parent_prefixes_table,
|
|
782
793
|
"related_ips_table": related_ips_table,
|
|
794
|
+
**super().get_extra_context(request, instance),
|
|
783
795
|
}
|
|
784
796
|
|
|
785
797
|
|
|
@@ -1261,6 +1273,7 @@ class VLANGroupView(generic.ObjectView):
|
|
|
1261
1273
|
"vlan_table": vlan_table,
|
|
1262
1274
|
"permissions": permissions,
|
|
1263
1275
|
"vlans_count": vlans_count,
|
|
1276
|
+
**super().get_extra_context(request, instance),
|
|
1264
1277
|
}
|
|
1265
1278
|
|
|
1266
1279
|
|
|
@@ -1317,9 +1330,7 @@ class VLANView(generic.ObjectView):
|
|
|
1317
1330
|
prefix_table = tables.PrefixTable(list(prefixes))
|
|
1318
1331
|
prefix_table.exclude = ("vlan",)
|
|
1319
1332
|
|
|
1320
|
-
return {
|
|
1321
|
-
"prefix_table": prefix_table,
|
|
1322
|
-
}
|
|
1333
|
+
return {"prefix_table": prefix_table, **super().get_extra_context(request, instance)}
|
|
1323
1334
|
|
|
1324
1335
|
|
|
1325
1336
|
class VLANInterfacesView(generic.ObjectView):
|