nautobot 2.2.0__py3-none-any.whl → 2.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/__init__.py +31 -0
- nautobot/circuits/apps.py +1 -1
- nautobot/core/api/routers.py +25 -0
- nautobot/core/cli/__init__.py +18 -11
- nautobot/core/constants.py +85 -0
- nautobot/core/forms/widgets.py +1 -2
- nautobot/core/graphql/schema.py +1 -0
- nautobot/core/models/__init__.py +1 -0
- nautobot/core/settings.py +23 -3
- nautobot/core/settings.yaml +20 -0
- nautobot/core/signals.py +1 -0
- nautobot/core/templates/generic/object_retrieve.html +2 -2
- nautobot/core/templates/inc/javascript.html +4 -4
- nautobot/core/templates/inc/media.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +14 -1
- nautobot/core/testing/__init__.py +1 -1
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/tests/integration/test_view_authentication.py +1 -0
- nautobot/core/tests/test_views.py +22 -0
- nautobot/core/utils/data.py +1 -2
- nautobot/core/utils/lookup.py +2 -0
- nautobot/core/views/generic.py +1 -3
- nautobot/core/views/mixins.py +0 -1
- nautobot/core/views/renderers.py +7 -5
- nautobot/dcim/apps.py +8 -4
- nautobot/dcim/elevations.py +5 -1
- nautobot/dcim/tables/devices.py +1 -1
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +12 -4
- nautobot/dcim/templates/dcim/device.html +1 -1
- nautobot/dcim/templates/dcim/devicefamily_retrieve.html +4 -0
- nautobot/dcim/templates/dcim/softwareimagefile_retrieve.html +1 -1
- nautobot/dcim/tests/test_api.py +36 -0
- nautobot/dcim/tests/test_signals.py +1 -1
- nautobot/dcim/views.py +6 -0
- nautobot/extras/api/serializers.py +20 -1
- nautobot/extras/apps.py +7 -0
- nautobot/extras/context_managers.py +15 -4
- nautobot/extras/filters/customfields.py +14 -9
- nautobot/extras/filters/mixins.py +6 -1
- nautobot/extras/health_checks.py +1 -0
- nautobot/extras/jobs.py +1 -0
- nautobot/extras/managers.py +1 -2
- nautobot/extras/models/contacts.py +1 -0
- nautobot/extras/models/customfields.py +25 -2
- nautobot/extras/models/datasources.py +1 -0
- nautobot/extras/models/mixins.py +1 -0
- nautobot/extras/plugins/__init__.py +2 -1
- nautobot/extras/querysets.py +1 -2
- nautobot/extras/secrets/providers.py +1 -0
- nautobot/extras/signals.py +15 -5
- nautobot/extras/tasks.py +70 -17
- nautobot/extras/tests/test_api.py +0 -4
- nautobot/extras/tests/test_customfields.py +72 -9
- nautobot/extras/views.py +8 -7
- nautobot/ipam/api/serializers.py +10 -0
- nautobot/ipam/apps.py +3 -2
- nautobot/project-static/docs/404.html +102 -70
- nautobot/project-static/docs/apps/index.html +103 -68
- nautobot/project-static/docs/apps/nautobot-apps.html +103 -68
- nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js → bundle.bd41221c.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.8fd75fb4.min.js.map → bundle.bd41221c.min.js.map} +3 -3
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.bcfcd587.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +141 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +141 -69
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +104 -69
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +103 -68
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +103 -68
- nautobot/project-static/docs/development/apps/api/configuration-view.html +103 -68
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +103 -68
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +103 -68
- nautobot/project-static/docs/development/apps/api/models/global-search.html +103 -68
- nautobot/project-static/docs/development/apps/api/models/graphql.html +103 -68
- nautobot/project-static/docs/development/apps/api/models/index.html +103 -68
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +103 -68
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +103 -68
- nautobot/project-static/docs/development/apps/api/prometheus.html +103 -68
- nautobot/project-static/docs/development/apps/api/setup.html +103 -68
- nautobot/project-static/docs/development/apps/api/testing.html +103 -68
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +103 -68
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +103 -68
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +103 -68
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +103 -68
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/base-template.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/index.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/notes.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +103 -68
- nautobot/project-static/docs/development/apps/api/views/urls.html +103 -68
- nautobot/project-static/docs/development/apps/index.html +103 -68
- nautobot/project-static/docs/development/apps/migration/code-updates.html +103 -68
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +103 -68
- nautobot/project-static/docs/development/apps/migration/from-v1.html +103 -68
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +103 -68
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +103 -68
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +103 -68
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +103 -68
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +103 -68
- nautobot/project-static/docs/development/core/application-registry.html +103 -68
- nautobot/project-static/docs/development/core/best-practices.html +121 -76
- nautobot/project-static/docs/development/core/bootstrap-ui.html +103 -68
- nautobot/project-static/docs/development/core/caching.html +103 -68
- nautobot/project-static/docs/development/core/controllers.html +106 -71
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +103 -68
- nautobot/project-static/docs/development/core/extending-models.html +13 -8187
- nautobot/project-static/docs/development/core/generic-views.html +118 -83
- nautobot/project-static/docs/development/core/getting-started.html +103 -68
- nautobot/project-static/docs/development/core/homepage.html +121 -86
- nautobot/project-static/docs/development/core/index.html +103 -68
- nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
- nautobot/project-static/docs/development/core/model-features.html +106 -71
- nautobot/project-static/docs/development/core/natural-keys.html +103 -68
- nautobot/project-static/docs/development/core/navigation-menu.html +103 -68
- nautobot/project-static/docs/development/core/release-checklist.html +103 -68
- nautobot/project-static/docs/development/core/role-internals.html +103 -68
- nautobot/project-static/docs/development/core/settings.html +103 -68
- nautobot/project-static/docs/development/core/style-guide.html +103 -68
- nautobot/project-static/docs/development/core/templates.html +103 -68
- nautobot/project-static/docs/development/core/testing.html +103 -68
- nautobot/project-static/docs/development/core/user-preferences.html +103 -68
- nautobot/project-static/docs/development/extending-models.html +3 -3
- nautobot/project-static/docs/development/index.html +103 -68
- nautobot/project-static/docs/development/jobs/index.html +104 -69
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +103 -68
- nautobot/project-static/docs/index.html +102 -70
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +103 -68
- nautobot/project-static/docs/release-notes/version-1.0.html +103 -68
- nautobot/project-static/docs/release-notes/version-1.1.html +103 -68
- nautobot/project-static/docs/release-notes/version-1.2.html +103 -68
- nautobot/project-static/docs/release-notes/version-1.3.html +103 -68
- nautobot/project-static/docs/release-notes/version-1.4.html +103 -68
- nautobot/project-static/docs/release-notes/version-1.5.html +103 -68
- nautobot/project-static/docs/release-notes/version-1.6.html +103 -68
- nautobot/project-static/docs/release-notes/version-2.0.html +103 -68
- nautobot/project-static/docs/release-notes/version-2.1.html +103 -68
- nautobot/project-static/docs/release-notes/version-2.2.html +334 -97
- nautobot/project-static/docs/requirements.txt +3 -3
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +258 -258
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +103 -68
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +103 -68
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +103 -68
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +103 -68
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +168 -68
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +103 -68
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +103 -68
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +103 -68
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +103 -68
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +103 -68
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +103 -68
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +107 -68
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +103 -68
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +103 -68
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +106 -71
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/index.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +103 -68
- nautobot/project-static/docs/user-guide/administration/installation/services.html +103 -68
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +103 -68
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +103 -68
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +103 -68
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +103 -68
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +114 -68
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +114 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +103 -68
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +103 -68
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +103 -68
- nautobot/project-static/docs/user-guide/index.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +103 -68
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +103 -68
- nautobot/project-static/jquery/jquery-3.7.1.min.js +2 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_444444_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_555555_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777620_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_777777_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_cc0000_256x240.png +0 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/images/ui-icons_ffffff_256x240.png +0 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.css +7 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.min.js +6 -0
- nautobot/project-static/jquery-ui-1.13.2/jquery-ui.structure.min.css +5 -0
- nautobot/project-static/{jquery-ui-1.13.1 → jquery-ui-1.13.2}/jquery-ui.theme.min.css +1 -1
- {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/METADATA +22 -22
- {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/RECORD +339 -338
- nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.f2e4d321.min.css.map +0 -1
- nautobot/project-static/jquery/jquery-3.6.0.min.js +0 -2
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.css +0 -7
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.min.js +0 -6
- nautobot/project-static/jquery-ui-1.13.1/jquery-ui.structure.min.css +0 -5
- {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/NOTICE +0 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/WHEEL +0 -0
- {nautobot-2.2.0.dist-info → nautobot-2.2.1.dist-info}/entry_points.txt +0 -0
nautobot/extras/tasks.py
CHANGED
|
@@ -14,7 +14,7 @@ logger = getLogger("nautobot.extras.tasks")
|
|
|
14
14
|
|
|
15
15
|
|
|
16
16
|
@nautobot_task
|
|
17
|
-
def update_custom_field_choice_data(field_id, old_value, new_value):
|
|
17
|
+
def update_custom_field_choice_data(field_id, old_value, new_value, change_context=None):
|
|
18
18
|
"""
|
|
19
19
|
Update the values for a custom field choice used in objects' _custom_field_data for the given field.
|
|
20
20
|
|
|
@@ -23,6 +23,8 @@ def update_custom_field_choice_data(field_id, old_value, new_value):
|
|
|
23
23
|
old_value (str): The existing value of the choice
|
|
24
24
|
new_value (str): The value which will be used as replacement
|
|
25
25
|
"""
|
|
26
|
+
# Circular Import
|
|
27
|
+
from nautobot.extras.context_managers import web_request_context
|
|
26
28
|
from nautobot.extras.models import CustomField
|
|
27
29
|
|
|
28
30
|
try:
|
|
@@ -35,19 +37,43 @@ def update_custom_field_choice_data(field_id, old_value, new_value):
|
|
|
35
37
|
# Loop through all field content types and search for values to update
|
|
36
38
|
for ct in field.content_types.all():
|
|
37
39
|
model = ct.model_class()
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
if change_context is not None:
|
|
41
|
+
with web_request_context(
|
|
42
|
+
user=change_context.get("user"),
|
|
43
|
+
change_id=change_context.get("change_id"),
|
|
44
|
+
context_detail=change_context.get("context_detail"),
|
|
45
|
+
context=change_context.get("context"),
|
|
46
|
+
):
|
|
47
|
+
for obj in model.objects.filter(**{f"_custom_field_data__{field.key}": old_value}):
|
|
48
|
+
obj._custom_field_data[field.key] = new_value
|
|
49
|
+
obj.save()
|
|
50
|
+
else:
|
|
51
|
+
for obj in model.objects.filter(**{f"_custom_field_data__{field.key}": old_value}):
|
|
52
|
+
obj._custom_field_data[field.key] = new_value
|
|
53
|
+
obj.save()
|
|
41
54
|
|
|
42
55
|
elif field.type == CustomFieldTypeChoices.TYPE_MULTISELECT:
|
|
43
56
|
# Loop through all field content types and search for values to update
|
|
44
57
|
for ct in field.content_types.all():
|
|
45
58
|
model = ct.model_class()
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
59
|
+
if change_context is not None:
|
|
60
|
+
with web_request_context(
|
|
61
|
+
user=change_context.get("user"),
|
|
62
|
+
change_id=change_context.get("change_id"),
|
|
63
|
+
context_detail=change_context.get("context_detail"),
|
|
64
|
+
context=change_context.get("context"),
|
|
65
|
+
):
|
|
66
|
+
for obj in model.objects.filter(**{f"_custom_field_data__{field.key}__contains": old_value}):
|
|
67
|
+
old_list = obj._custom_field_data[field.key]
|
|
68
|
+
new_list = [new_value if e == old_value else e for e in old_list]
|
|
69
|
+
obj._custom_field_data[field.key] = new_list
|
|
70
|
+
obj.save()
|
|
71
|
+
else:
|
|
72
|
+
for obj in model.objects.filter(**{f"_custom_field_data__{field.key}__contains": old_value}):
|
|
73
|
+
old_list = obj._custom_field_data[field.key]
|
|
74
|
+
new_list = [new_value if e == old_value else e for e in old_list]
|
|
75
|
+
obj._custom_field_data[field.key] = new_list
|
|
76
|
+
obj.save()
|
|
51
77
|
|
|
52
78
|
else:
|
|
53
79
|
logger.error(f"Unknown field type, failing to act on choice data for this field {field.key}.")
|
|
@@ -57,7 +83,7 @@ def update_custom_field_choice_data(field_id, old_value, new_value):
|
|
|
57
83
|
|
|
58
84
|
|
|
59
85
|
@nautobot_task
|
|
60
|
-
def delete_custom_field_data(field_key, content_type_pk_set):
|
|
86
|
+
def delete_custom_field_data(field_key, content_type_pk_set, change_context=None):
|
|
61
87
|
"""
|
|
62
88
|
Delete the values for a custom field
|
|
63
89
|
|
|
@@ -65,16 +91,30 @@ def delete_custom_field_data(field_key, content_type_pk_set):
|
|
|
65
91
|
field_key (str): The key of the custom field which is being deleted
|
|
66
92
|
content_type_pk_set (list): List of PKs for content types to act upon
|
|
67
93
|
"""
|
|
94
|
+
# Circular Import
|
|
95
|
+
from nautobot.extras.context_managers import web_request_context
|
|
96
|
+
|
|
68
97
|
with transaction.atomic():
|
|
69
98
|
for ct in ContentType.objects.filter(pk__in=content_type_pk_set):
|
|
70
99
|
model = ct.model_class()
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
100
|
+
if change_context is not None:
|
|
101
|
+
with web_request_context(
|
|
102
|
+
user=change_context.get("user"),
|
|
103
|
+
change_id=change_context.get("change_id"),
|
|
104
|
+
context_detail=change_context.get("context_detail"),
|
|
105
|
+
context=change_context.get("context"),
|
|
106
|
+
):
|
|
107
|
+
for obj in model.objects.filter(**{f"_custom_field_data__{field_key}__isnull": False}):
|
|
108
|
+
del obj._custom_field_data[field_key]
|
|
109
|
+
obj.save()
|
|
110
|
+
else:
|
|
111
|
+
for obj in model.objects.filter(**{f"_custom_field_data__{field_key}__isnull": False}):
|
|
112
|
+
del obj._custom_field_data[field_key]
|
|
113
|
+
obj.save()
|
|
74
114
|
|
|
75
115
|
|
|
76
116
|
@nautobot_task
|
|
77
|
-
def provision_field(field_id, content_type_pk_set):
|
|
117
|
+
def provision_field(field_id, content_type_pk_set, change_context=None):
|
|
78
118
|
"""
|
|
79
119
|
Provision a new custom field on all relevant content type object instances.
|
|
80
120
|
|
|
@@ -82,6 +122,8 @@ def provision_field(field_id, content_type_pk_set):
|
|
|
82
122
|
field_id (uuid4): The PK of the custom field being provisioned
|
|
83
123
|
content_type_pk_set (list): List of PKs for content types to act upon
|
|
84
124
|
"""
|
|
125
|
+
# Circular Import
|
|
126
|
+
from nautobot.extras.context_managers import web_request_context
|
|
85
127
|
from nautobot.extras.models import CustomField
|
|
86
128
|
|
|
87
129
|
try:
|
|
@@ -93,9 +135,20 @@ def provision_field(field_id, content_type_pk_set):
|
|
|
93
135
|
with transaction.atomic():
|
|
94
136
|
for ct in ContentType.objects.filter(pk__in=content_type_pk_set):
|
|
95
137
|
model = ct.model_class()
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
138
|
+
if change_context is not None:
|
|
139
|
+
with web_request_context(
|
|
140
|
+
user=change_context.get("user"),
|
|
141
|
+
change_id=change_context.get("change_id"),
|
|
142
|
+
context_detail=change_context.get("context_detail"),
|
|
143
|
+
context=change_context.get("context"),
|
|
144
|
+
):
|
|
145
|
+
for obj in model.objects.all():
|
|
146
|
+
obj._custom_field_data.setdefault(field.key, field.default)
|
|
147
|
+
obj.save()
|
|
148
|
+
else:
|
|
149
|
+
for obj in model.objects.all():
|
|
150
|
+
obj._custom_field_data.setdefault(field.key, field.default)
|
|
151
|
+
obj.save()
|
|
99
152
|
|
|
100
153
|
return True
|
|
101
154
|
|
|
@@ -409,11 +409,9 @@ class ContactTest(APIViewTestCases.APIViewTestCase):
|
|
|
409
409
|
{
|
|
410
410
|
"name": "Contact 3",
|
|
411
411
|
"phone": "555-0123",
|
|
412
|
-
"email": "",
|
|
413
412
|
},
|
|
414
413
|
{
|
|
415
414
|
"name": "Contact 4",
|
|
416
|
-
"phone": "",
|
|
417
415
|
"email": "contact4@example.com",
|
|
418
416
|
},
|
|
419
417
|
]
|
|
@@ -3613,11 +3611,9 @@ class TeamTest(APIViewTestCases.APIViewTestCase):
|
|
|
3613
3611
|
{
|
|
3614
3612
|
"name": "Team 3",
|
|
3615
3613
|
"phone": "555-0123",
|
|
3616
|
-
"email": "",
|
|
3617
3614
|
},
|
|
3618
3615
|
{
|
|
3619
3616
|
"name": "Team 4",
|
|
3620
|
-
"phone": "",
|
|
3621
3617
|
"email": "team4@example.com",
|
|
3622
3618
|
"address": "Rainbow Bridge, Central NJ",
|
|
3623
3619
|
},
|
|
@@ -16,11 +16,13 @@ from nautobot.core.tables import CustomFieldColumn
|
|
|
16
16
|
from nautobot.core.testing import APITestCase, TestCase, TransactionTestCase
|
|
17
17
|
from nautobot.core.testing.models import ModelTestCases
|
|
18
18
|
from nautobot.core.testing.utils import post_data
|
|
19
|
+
from nautobot.core.utils.lookup import get_changes_for_model
|
|
19
20
|
from nautobot.dcim.filters import LocationFilterSet
|
|
20
21
|
from nautobot.dcim.forms import RackFilterForm
|
|
21
22
|
from nautobot.dcim.models import Device, Location, LocationType, Rack
|
|
22
23
|
from nautobot.dcim.tables import LocationTable
|
|
23
24
|
from nautobot.extras.choices import CustomFieldFilterLogicChoices, CustomFieldTypeChoices
|
|
25
|
+
from nautobot.extras.context_managers import web_request_context
|
|
24
26
|
from nautobot.extras.models import ComputedField, CustomField, CustomFieldChoice, Status
|
|
25
27
|
from nautobot.users.models import ObjectPermission
|
|
26
28
|
from nautobot.virtualization.models import VirtualMachine
|
|
@@ -1537,8 +1539,10 @@ class CustomFieldFilterTest(TestCase):
|
|
|
1537
1539
|
cf.save()
|
|
1538
1540
|
cf.content_types.set([obj_type])
|
|
1539
1541
|
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
+
cls.select_choices = (
|
|
1543
|
+
CustomFieldChoice.objects.create(custom_field=cf, value="Foo"),
|
|
1544
|
+
CustomFieldChoice.objects.create(custom_field=cf, value="Bar"),
|
|
1545
|
+
)
|
|
1542
1546
|
|
|
1543
1547
|
# Multi-select filtering
|
|
1544
1548
|
cf = CustomField(
|
|
@@ -1548,8 +1552,11 @@ class CustomFieldFilterTest(TestCase):
|
|
|
1548
1552
|
cf.save()
|
|
1549
1553
|
cf.content_types.set([obj_type])
|
|
1550
1554
|
|
|
1551
|
-
|
|
1552
|
-
|
|
1555
|
+
cls.multiselect_choices = (
|
|
1556
|
+
CustomFieldChoice.objects.create(custom_field=cf, value="Foo"),
|
|
1557
|
+
CustomFieldChoice.objects.create(custom_field=cf, value="Bar"),
|
|
1558
|
+
)
|
|
1559
|
+
|
|
1553
1560
|
cls.location_type = LocationType.objects.get(name="Campus")
|
|
1554
1561
|
location_status = Status.objects.get_for_model(Location).first()
|
|
1555
1562
|
Location.objects.create(
|
|
@@ -1844,6 +1851,10 @@ class CustomFieldFilterTest(TestCase):
|
|
|
1844
1851
|
self.filterset({"cf_cf8": ["Foo", "AR"]}, self.queryset).qs,
|
|
1845
1852
|
self.queryset.filter(_custom_field_data__cf8__in=["Foo", "AR"]),
|
|
1846
1853
|
)
|
|
1854
|
+
self.assertQuerysetEqualAndNotEmpty( # https://github.com/nautobot/nautobot/issues/5009
|
|
1855
|
+
self.filterset({"cf_cf8": [str(choice.pk) for choice in self.select_choices]}, self.queryset).qs,
|
|
1856
|
+
self.queryset.filter(_custom_field_data__cf8__in=[choice.value for choice in self.select_choices]),
|
|
1857
|
+
)
|
|
1847
1858
|
self.assertQuerysetEqual(
|
|
1848
1859
|
self.filterset({"cf_cf8__n": ["Foo"]}, self.queryset).qs,
|
|
1849
1860
|
self.queryset.exclude(_custom_field_data__cf8="Foo")
|
|
@@ -1913,6 +1924,10 @@ class CustomFieldFilterTest(TestCase):
|
|
|
1913
1924
|
self.filterset({"cf_cf9": "Bar"}, self.queryset).qs,
|
|
1914
1925
|
self.queryset.filter(_custom_field_data__cf9__contains="Bar"),
|
|
1915
1926
|
)
|
|
1927
|
+
self.assertQuerysetEqualAndNotEmpty( # https://github.com/nautobot/nautobot/issues/5009
|
|
1928
|
+
self.filterset({"cf_cf9": str(self.multiselect_choices[0].pk)}, self.queryset).qs,
|
|
1929
|
+
self.queryset.filter(_custom_field_data__cf9__contains=self.multiselect_choices[0].value),
|
|
1930
|
+
)
|
|
1916
1931
|
|
|
1917
1932
|
|
|
1918
1933
|
class CustomFieldChoiceTest(ModelTestCases.BaseModelTestCase):
|
|
@@ -2016,30 +2031,64 @@ class CustomFieldBackgroundTasks(TransactionTestCase):
|
|
|
2016
2031
|
|
|
2017
2032
|
self.assertEqual(location.cf["cf1"], "Foo")
|
|
2018
2033
|
|
|
2034
|
+
with web_request_context(self.user):
|
|
2035
|
+
cf = CustomField(label="CF2", type=CustomFieldTypeChoices.TYPE_TEXT, default="Bar")
|
|
2036
|
+
cf.save()
|
|
2037
|
+
cf.content_types.set([obj_type])
|
|
2038
|
+
|
|
2039
|
+
location.refresh_from_db()
|
|
2040
|
+
|
|
2041
|
+
self.assertEqual(location.cf["cf2"], "Bar")
|
|
2042
|
+
|
|
2043
|
+
oc_list = get_changes_for_model(location).order_by("pk")
|
|
2044
|
+
self.assertEqual(len(oc_list), 1)
|
|
2045
|
+
self.assertEqual(oc_list[0].changed_object, location)
|
|
2046
|
+
self.assertEqual(oc_list[0].change_context_detail, "provision custom field data for new content types")
|
|
2047
|
+
self.assertEqual(oc_list[0].user, self.user)
|
|
2048
|
+
|
|
2019
2049
|
def test_delete_custom_field_data_task(self):
|
|
2020
2050
|
obj_type = ContentType.objects.get_for_model(Location)
|
|
2021
|
-
|
|
2051
|
+
cf_1 = CustomField(
|
|
2022
2052
|
label="CF1",
|
|
2023
2053
|
type=CustomFieldTypeChoices.TYPE_TEXT,
|
|
2024
2054
|
)
|
|
2025
|
-
|
|
2026
|
-
|
|
2055
|
+
cf_1.save()
|
|
2056
|
+
cf_1.content_types.set([obj_type])
|
|
2057
|
+
cf_2 = CustomField(
|
|
2058
|
+
label="CF2",
|
|
2059
|
+
type=CustomFieldTypeChoices.TYPE_TEXT,
|
|
2060
|
+
)
|
|
2061
|
+
cf_2.save()
|
|
2062
|
+
cf_2.content_types.set([obj_type])
|
|
2027
2063
|
location_type = LocationType.objects.create(name="Root Type 2")
|
|
2028
2064
|
location_status = Status.objects.get_for_model(Location).first()
|
|
2029
2065
|
location = Location(
|
|
2030
2066
|
name="Location 1",
|
|
2031
2067
|
location_type=location_type,
|
|
2032
2068
|
status=location_status,
|
|
2033
|
-
_custom_field_data={"cf1": "foo"},
|
|
2069
|
+
_custom_field_data={"cf1": "foo", "cf2": "bar"},
|
|
2034
2070
|
)
|
|
2035
2071
|
location.save()
|
|
2036
2072
|
|
|
2037
|
-
|
|
2073
|
+
cf_1.delete()
|
|
2038
2074
|
|
|
2039
2075
|
location.refresh_from_db()
|
|
2040
2076
|
|
|
2041
2077
|
self.assertTrue("cf1" not in location.cf)
|
|
2042
2078
|
|
|
2079
|
+
with web_request_context(self.user):
|
|
2080
|
+
cf_2.delete()
|
|
2081
|
+
|
|
2082
|
+
location.refresh_from_db()
|
|
2083
|
+
|
|
2084
|
+
self.assertTrue("cf2" not in location.cf)
|
|
2085
|
+
|
|
2086
|
+
oc_list = get_changes_for_model(location).order_by("pk")
|
|
2087
|
+
self.assertEqual(len(oc_list), 1)
|
|
2088
|
+
self.assertEqual(oc_list[0].changed_object, location)
|
|
2089
|
+
self.assertEqual(oc_list[0].change_context_detail, "delete custom field data")
|
|
2090
|
+
self.assertEqual(oc_list[0].user, self.user)
|
|
2091
|
+
|
|
2043
2092
|
def test_update_custom_field_choice_data_task(self):
|
|
2044
2093
|
obj_type = ContentType.objects.get_for_model(Location)
|
|
2045
2094
|
cf = CustomField(
|
|
@@ -2068,6 +2117,20 @@ class CustomFieldBackgroundTasks(TransactionTestCase):
|
|
|
2068
2117
|
|
|
2069
2118
|
self.assertEqual(location.cf["cf1"], "Bar")
|
|
2070
2119
|
|
|
2120
|
+
with web_request_context(self.user):
|
|
2121
|
+
choice.value = "FizzBuzz"
|
|
2122
|
+
choice.save()
|
|
2123
|
+
|
|
2124
|
+
location.refresh_from_db()
|
|
2125
|
+
|
|
2126
|
+
self.assertEqual(location.cf["cf1"], "FizzBuzz")
|
|
2127
|
+
|
|
2128
|
+
oc_list = get_changes_for_model(location).order_by("pk")
|
|
2129
|
+
self.assertEqual(len(oc_list), 1)
|
|
2130
|
+
self.assertEqual(oc_list[0].changed_object, location)
|
|
2131
|
+
self.assertEqual(oc_list[0].change_context_detail, "update custom field choice data")
|
|
2132
|
+
self.assertEqual(oc_list[0].user, self.user)
|
|
2133
|
+
|
|
2071
2134
|
|
|
2072
2135
|
class CustomFieldTableTest(TestCase):
|
|
2073
2136
|
"""
|
nautobot/extras/views.py
CHANGED
|
@@ -40,6 +40,7 @@ from nautobot.core.views.viewsets import NautobotUIViewSet
|
|
|
40
40
|
from nautobot.dcim.models import Controller, Device, Interface, Location, Rack
|
|
41
41
|
from nautobot.dcim.tables import ControllerTable, DeviceTable, RackTable
|
|
42
42
|
from nautobot.extras.constants import JOB_OVERRIDABLE_FIELDS
|
|
43
|
+
from nautobot.extras.signals import change_context_state
|
|
43
44
|
from nautobot.extras.tasks import delete_custom_field_data
|
|
44
45
|
from nautobot.extras.utils import get_base_template, get_worker_count
|
|
45
46
|
from nautobot.ipam.models import IPAddress, Prefix, VLAN
|
|
@@ -369,7 +370,6 @@ class ContactUIViewSet(NautobotUIViewSet):
|
|
|
369
370
|
queryset = Contact.objects.all()
|
|
370
371
|
serializer_class = serializers.ContactSerializer
|
|
371
372
|
table_class = tables.ContactTable
|
|
372
|
-
is_contact_associatable_model = False
|
|
373
373
|
|
|
374
374
|
def get_extra_context(self, request, instance):
|
|
375
375
|
context = super().get_extra_context(request, instance)
|
|
@@ -677,8 +677,14 @@ class CustomFieldBulkDeleteView(generic.BulkDeleteView):
|
|
|
677
677
|
"""
|
|
678
678
|
Helper method to construct a list of celery tasks to execute when bulk deleting custom fields.
|
|
679
679
|
"""
|
|
680
|
+
change_context = change_context_state.get()
|
|
681
|
+
if change_context is None:
|
|
682
|
+
context = None
|
|
683
|
+
else:
|
|
684
|
+
context = change_context.as_dict(queryset)
|
|
685
|
+
context["context_detail"] = "bulk delete custom field data"
|
|
680
686
|
tasks = [
|
|
681
|
-
delete_custom_field_data.si(obj.key, set(obj.content_types.values_list("pk", flat=True)))
|
|
687
|
+
delete_custom_field_data.si(obj.key, set(obj.content_types.values_list("pk", flat=True)), context)
|
|
682
688
|
for obj in queryset
|
|
683
689
|
]
|
|
684
690
|
return tasks
|
|
@@ -1939,8 +1945,6 @@ class ObjectChangeLogView(generic.GenericView):
|
|
|
1939
1945
|
"table": objectchanges_table,
|
|
1940
1946
|
"base_template": self.base_template,
|
|
1941
1947
|
"active_tab": "changelog",
|
|
1942
|
-
# Currently only Contact and Team models are not contact_associatable.
|
|
1943
|
-
"is_contact_associatable_model": type(obj) not in [Contact, Team],
|
|
1944
1948
|
},
|
|
1945
1949
|
)
|
|
1946
1950
|
|
|
@@ -2022,8 +2026,6 @@ class ObjectNotesView(generic.GenericView):
|
|
|
2022
2026
|
"base_template": self.base_template,
|
|
2023
2027
|
"active_tab": "notes",
|
|
2024
2028
|
"form": notes_form,
|
|
2025
|
-
# Currently only Contact and Team models are not contact_associatable.
|
|
2026
|
-
"is_contact_associatable_model": type(obj) not in [Contact, Team],
|
|
2027
2029
|
},
|
|
2028
2030
|
)
|
|
2029
2031
|
|
|
@@ -2532,7 +2534,6 @@ class TeamUIViewSet(NautobotUIViewSet):
|
|
|
2532
2534
|
queryset = Team.objects.all()
|
|
2533
2535
|
serializer_class = serializers.TeamSerializer
|
|
2534
2536
|
table_class = tables.TeamTable
|
|
2535
|
-
is_contact_associatable_model = False
|
|
2536
2537
|
|
|
2537
2538
|
def get_extra_context(self, request, instance):
|
|
2538
2539
|
context = super().get_extra_context(request, instance)
|
nautobot/ipam/api/serializers.py
CHANGED
|
@@ -495,6 +495,7 @@ class ServiceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
|
495
495
|
class Meta:
|
|
496
496
|
model = Service
|
|
497
497
|
fields = "__all__"
|
|
498
|
+
validators = []
|
|
498
499
|
extra_kwargs = {
|
|
499
500
|
"device": {"help_text": "Required if no virtual_machine is specified"},
|
|
500
501
|
"virtual_machine": {"help_text": "Required if no device is specified"},
|
|
@@ -504,3 +505,12 @@ class ServiceSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
|
504
505
|
# `device`.
|
|
505
506
|
# list_display_fields = ["name", "parent", "protocol", "ports", "description"]
|
|
506
507
|
list_display_fields = ["name", "device", "protocol", "ports", "description"]
|
|
508
|
+
|
|
509
|
+
def validate(self, data):
|
|
510
|
+
if data.get("device"):
|
|
511
|
+
validator = UniqueTogetherValidator(queryset=Service.objects.all(), fields=("name", "device"))
|
|
512
|
+
validator(data, self)
|
|
513
|
+
if data.get("virtual_machine"):
|
|
514
|
+
validator = UniqueTogetherValidator(queryset=Service.objects.all(), fields=("name", "virtual_machine"))
|
|
515
|
+
validator(data, self)
|
|
516
|
+
return super().validate(data)
|