nautobot 2.2.0b1__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/apps/api.py +1 -2
- nautobot/apps/utils.py +4 -0
- nautobot/apps/views.py +2 -0
- nautobot/circuits/api/urls.py +1 -2
- nautobot/circuits/api/views.py +0 -12
- nautobot/circuits/apps.py +1 -1
- nautobot/circuits/tests/test_filters.py +1 -1
- nautobot/core/api/routers.py +50 -3
- nautobot/core/api/utils.py +4 -0
- nautobot/core/api/views.py +21 -15
- nautobot/core/cli/__init__.py +18 -11
- nautobot/core/constants.py +85 -0
- nautobot/core/filters.py +7 -1
- nautobot/core/forms/widgets.py +1 -2
- nautobot/core/graphql/schema.py +1 -0
- nautobot/core/management/commands/generate_test_data.py +4 -4
- nautobot/core/models/__init__.py +1 -0
- nautobot/core/settings.py +24 -3
- nautobot/core/settings.yaml +20 -0
- nautobot/core/signals.py +1 -0
- nautobot/core/tables.py +2 -1
- nautobot/core/templates/admin/base.html +23 -94
- nautobot/core/templates/generic/object_retrieve.html +2 -2
- nautobot/core/templates/graphene/graphiql.html +18 -47
- nautobot/core/templates/inc/footer.html +5 -5
- nautobot/core/templates/inc/javascript.html +4 -4
- nautobot/core/templates/inc/media.html +2 -2
- nautobot/core/templates/inc/nav_menu.html +0 -7
- nautobot/core/templates/nautobot_config.py.j2 +14 -1
- nautobot/core/templates/rest_framework/api.html +12 -5
- nautobot/core/templatetags/helpers.py +2 -2
- nautobot/core/testing/__init__.py +1 -1
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/testing/views.py +30 -0
- nautobot/core/tests/integration/test_view_authentication.py +68 -0
- nautobot/core/tests/test_api.py +13 -6
- nautobot/core/tests/test_csv.py +5 -4
- nautobot/core/tests/test_filters.py +2 -1
- nautobot/core/tests/test_graphql.py +4 -14
- nautobot/core/tests/test_navigations.py +3 -0
- nautobot/core/tests/test_views.py +44 -16
- nautobot/core/utils/data.py +1 -2
- nautobot/core/utils/lookup.py +126 -0
- nautobot/core/views/__init__.py +3 -7
- nautobot/core/views/generic.py +20 -6
- nautobot/core/views/mixins.py +7 -1
- nautobot/core/views/renderers.py +11 -6
- nautobot/dcim/api/serializers.py +4 -4
- nautobot/dcim/api/urls.py +2 -3
- nautobot/dcim/api/views.py +7 -18
- nautobot/dcim/apps.py +8 -4
- nautobot/dcim/elevations.py +5 -1
- nautobot/dcim/factory.py +7 -7
- nautobot/dcim/filters/__init__.py +16 -17
- nautobot/dcim/forms.py +61 -45
- nautobot/dcim/homepage.py +11 -3
- nautobot/dcim/management/commands/migrate_location_contacts.py +218 -0
- nautobot/dcim/migrations/0057_controller_models.py +11 -70
- nautobot/dcim/models/__init__.py +2 -2
- nautobot/dcim/models/devices.py +14 -16
- nautobot/dcim/models/racks.py +1 -3
- nautobot/dcim/navigation.py +23 -31
- nautobot/dcim/signals.py +6 -6
- nautobot/dcim/tables/__init__.py +2 -2
- nautobot/dcim/tables/devices.py +13 -16
- nautobot/dcim/tables/template_code.py +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +70 -0
- nautobot/dcim/templates/dcim/controller_retrieve.html +35 -18
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +88 -0
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +75 -43
- nautobot/dcim/templates/dcim/device.html +11 -3
- nautobot/dcim/templates/dcim/device_edit.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 +47 -6
- nautobot/dcim/tests/test_filters.py +92 -81
- nautobot/dcim/tests/test_graphql.py +11 -1
- nautobot/dcim/tests/test_models.py +15 -15
- nautobot/dcim/tests/test_signals.py +3 -1
- nautobot/dcim/tests/test_views.py +24 -12
- nautobot/dcim/urls.py +1 -1
- nautobot/dcim/views.py +25 -15
- nautobot/extras/api/serializers.py +20 -1
- nautobot/extras/api/urls.py +1 -2
- nautobot/extras/api/views.py +0 -10
- nautobot/extras/apps.py +7 -0
- nautobot/extras/context_managers.py +15 -4
- nautobot/extras/filters/__init__.py +53 -2
- nautobot/extras/filters/customfields.py +14 -9
- nautobot/extras/filters/mixins.py +6 -1
- nautobot/extras/forms/contacts.py +7 -0
- nautobot/extras/health_checks.py +1 -0
- nautobot/extras/jobs.py +1 -0
- nautobot/extras/managers.py +15 -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/navigation.py +71 -65
- nautobot/extras/plugins/__init__.py +2 -1
- nautobot/extras/plugins/views.py +7 -11
- 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 +2 -4
- nautobot/extras/tests/test_customfields.py +72 -9
- nautobot/extras/tests/test_dynamicgroups.py +2 -0
- nautobot/extras/tests/test_filters.py +89 -4
- nautobot/extras/tests/test_models.py +9 -0
- nautobot/extras/tests/test_relationships.py +10 -1
- nautobot/extras/tests/test_views.py +112 -1
- nautobot/extras/views.py +18 -17
- nautobot/ipam/api/serializers.py +10 -0
- nautobot/ipam/api/urls.py +1 -2
- nautobot/ipam/api/views.py +0 -11
- nautobot/ipam/apps.py +3 -2
- nautobot/ipam/tables.py +2 -22
- nautobot/ipam/tests/test_graphql.py +2 -3
- nautobot/ipam/tests/test_tables.py +42 -0
- nautobot/ipam/tests/test_views.py +1 -0
- nautobot/ipam/views.py +9 -9
- nautobot/project-static/css/base.css +1 -0
- nautobot/project-static/docs/404.html +126 -73
- nautobot/project-static/docs/apps/index.html +127 -71
- nautobot/project-static/docs/apps/nautobot-apps.html +127 -71
- 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 +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +167 -73
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +165 -72
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +128 -72
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +127 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +345 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +172 -73
- nautobot/project-static/docs/development/apps/api/configuration-view.html +127 -71
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/global-search.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/graphql.html +127 -71
- nautobot/project-static/docs/development/apps/api/models/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +127 -71
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +127 -71
- nautobot/project-static/docs/development/apps/api/prometheus.html +127 -71
- nautobot/project-static/docs/development/apps/api/setup.html +127 -71
- nautobot/project-static/docs/development/apps/api/testing.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +127 -71
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/base-template.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +141 -80
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +144 -83
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/index.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/notes.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +127 -71
- nautobot/project-static/docs/development/apps/api/views/urls.html +127 -71
- nautobot/project-static/docs/development/apps/index.html +127 -71
- nautobot/project-static/docs/development/apps/migration/code-updates.html +127 -71
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +127 -71
- nautobot/project-static/docs/development/apps/migration/from-v1.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +127 -71
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +127 -71
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +127 -71
- nautobot/project-static/docs/development/core/application-registry.html +127 -71
- nautobot/project-static/docs/development/core/best-practices.html +145 -79
- nautobot/project-static/docs/development/core/bootstrap-ui.html +127 -71
- nautobot/project-static/docs/development/core/caching.html +127 -71
- nautobot/project-static/docs/development/core/controllers.html +141 -275
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +127 -71
- nautobot/project-static/docs/development/core/extending-models.html +13 -8166
- nautobot/project-static/docs/development/core/generic-views.html +142 -86
- nautobot/project-static/docs/development/core/getting-started.html +146 -81
- nautobot/project-static/docs/development/core/homepage.html +145 -89
- nautobot/project-static/docs/development/core/index.html +127 -71
- nautobot/project-static/docs/development/core/model-checklist.html +8354 -0
- nautobot/project-static/docs/development/core/model-features.html +130 -74
- nautobot/project-static/docs/development/core/natural-keys.html +127 -71
- nautobot/project-static/docs/development/core/navigation-menu.html +127 -71
- nautobot/project-static/docs/development/core/release-checklist.html +127 -71
- nautobot/project-static/docs/development/core/role-internals.html +127 -71
- nautobot/project-static/docs/development/core/settings.html +127 -71
- nautobot/project-static/docs/development/core/style-guide.html +127 -71
- nautobot/project-static/docs/development/core/templates.html +127 -71
- nautobot/project-static/docs/development/core/testing.html +127 -71
- nautobot/project-static/docs/development/core/user-preferences.html +127 -71
- nautobot/project-static/docs/development/extending-models.html +3 -3
- nautobot/project-static/docs/development/index.html +127 -71
- nautobot/project-static/docs/development/jobs/index.html +128 -72
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +127 -71
- nautobot/project-static/docs/index.html +126 -73
- nautobot/project-static/docs/models/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +3 -3
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/release-notes/index.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.0.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.1.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.2.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.3.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.4.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.5.html +127 -71
- nautobot/project-static/docs/release-notes/version-1.6.html +127 -71
- nautobot/project-static/docs/release-notes/version-2.0.html +127 -71
- nautobot/project-static/docs/release-notes/version-2.1.html +538 -254
- nautobot/project-static/docs/release-notes/version-2.2.html +520 -101
- nautobot/project-static/docs/requirements.txt +3 -3
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +264 -259
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/optional-settings.html +192 -71
- nautobot/project-static/docs/user-guide/administration/configuration/required-settings.html +127 -71
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/caching.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/healthcheck.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -71
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +127 -71
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +130 -74
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/docker.html +134 -74
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/health-checks.html +8616 -0
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +127 -71
- nautobot/project-static/docs/user-guide/administration/installation/selinux-troubleshooting.html +130 -74
- nautobot/project-static/docs/user-guide/administration/installation/services.html +127 -71
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +127 -71
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +127 -71
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +127 -71
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +127 -71
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +362 -79
- nautobot/project-static/docs/user-guide/core-data-model/dcim/{controllerdevicegroup.html → controllermanageddevicegroup.html} +210 -85
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +130 -74
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +138 -71
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +138 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +127 -71
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/{contact-and-team.html → contacts-and-teams.html} +128 -72
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +129 -73
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +129 -73
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +127 -71
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +127 -71
- nautobot/project-static/docs/user-guide/index.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +127 -71
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +127 -71
- 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/tenancy/api/urls.py +1 -2
- nautobot/tenancy/api/views.py +0 -12
- nautobot/tenancy/tables.py +1 -1
- nautobot/tenancy/tests/test_views.py +1 -0
- nautobot/users/api/urls.py +1 -2
- nautobot/users/api/views.py +2 -65
- nautobot/users/views.py +8 -8
- nautobot/virtualization/api/urls.py +1 -2
- nautobot/virtualization/api/views.py +0 -12
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/METADATA +24 -24
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/RECORD +418 -412
- nautobot/dcim/templates/dcim/controllerdevicegroup_create.html +0 -43
- 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/dcim/templates/dcim/{controllerdevicegroup_retrieve.html → controllermanageddevicegroup_retrieve.html} +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/NOTICE +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/WHEEL +0 -0
- {nautobot-2.2.0b1.dist-info → nautobot-2.2.1.dist-info}/entry_points.txt +0 -0
nautobot/extras/navigation.py
CHANGED
|
@@ -14,8 +14,50 @@ menu_items = (
|
|
|
14
14
|
weight=100,
|
|
15
15
|
groups=(
|
|
16
16
|
NavMenuGroup(
|
|
17
|
-
name="
|
|
17
|
+
name="Contacts",
|
|
18
18
|
weight=400,
|
|
19
|
+
items=(
|
|
20
|
+
NavMenuItem(
|
|
21
|
+
link="extras:contact_list",
|
|
22
|
+
name="Contacts",
|
|
23
|
+
weight=100,
|
|
24
|
+
permissions=["extras.view_contact"],
|
|
25
|
+
buttons=[NavMenuAddButton(link="extras:contact_add", permissions=["extras.add_contact"])],
|
|
26
|
+
),
|
|
27
|
+
NavMenuItem(
|
|
28
|
+
link="extras:team_list",
|
|
29
|
+
name="Teams",
|
|
30
|
+
weight=200,
|
|
31
|
+
permissions=["extras.view_team"],
|
|
32
|
+
buttons=[NavMenuAddButton(link="extras:team_add", permissions=["extras.add_team"])],
|
|
33
|
+
),
|
|
34
|
+
),
|
|
35
|
+
),
|
|
36
|
+
NavMenuGroup(
|
|
37
|
+
name="Groups",
|
|
38
|
+
weight=500,
|
|
39
|
+
items=(
|
|
40
|
+
NavMenuItem(
|
|
41
|
+
link="extras:dynamicgroup_list",
|
|
42
|
+
name="Dynamic Groups",
|
|
43
|
+
weight=100,
|
|
44
|
+
permissions=[
|
|
45
|
+
"extras.view_dynamicgroup",
|
|
46
|
+
],
|
|
47
|
+
buttons=(
|
|
48
|
+
NavMenuAddButton(
|
|
49
|
+
link="extras:dynamicgroup_add",
|
|
50
|
+
permissions=[
|
|
51
|
+
"extras.add_dynamicgroup",
|
|
52
|
+
],
|
|
53
|
+
),
|
|
54
|
+
),
|
|
55
|
+
),
|
|
56
|
+
),
|
|
57
|
+
),
|
|
58
|
+
NavMenuGroup(
|
|
59
|
+
name="Metadata", # TODO: is there a better name for this grouping?
|
|
60
|
+
weight=600,
|
|
19
61
|
items=(
|
|
20
62
|
NavMenuItem(
|
|
21
63
|
link="extras:tag_list",
|
|
@@ -65,42 +107,6 @@ menu_items = (
|
|
|
65
107
|
),
|
|
66
108
|
),
|
|
67
109
|
),
|
|
68
|
-
NavMenuItem(
|
|
69
|
-
link="extras:contact_list",
|
|
70
|
-
name="Contacts",
|
|
71
|
-
weight=400,
|
|
72
|
-
permissions=["extras.view_contact"],
|
|
73
|
-
buttons=[NavMenuAddButton(link="extras:contact_add", permissions=["extras.add_contact"])],
|
|
74
|
-
),
|
|
75
|
-
NavMenuItem(
|
|
76
|
-
link="extras:team_list",
|
|
77
|
-
name="Teams",
|
|
78
|
-
weight=500,
|
|
79
|
-
permissions=["extras.view_team"],
|
|
80
|
-
buttons=[NavMenuAddButton(link="extras:team_add", permissions=["extras.add_team"])],
|
|
81
|
-
),
|
|
82
|
-
),
|
|
83
|
-
),
|
|
84
|
-
NavMenuGroup(
|
|
85
|
-
name="Dynamic Groups",
|
|
86
|
-
weight=500,
|
|
87
|
-
items=(
|
|
88
|
-
NavMenuItem(
|
|
89
|
-
link="extras:dynamicgroup_list",
|
|
90
|
-
name="Dynamic Groups",
|
|
91
|
-
weight=100,
|
|
92
|
-
permissions=[
|
|
93
|
-
"extras.view_dynamicgroup",
|
|
94
|
-
],
|
|
95
|
-
buttons=(
|
|
96
|
-
NavMenuAddButton(
|
|
97
|
-
link="extras:dynamicgroup_add",
|
|
98
|
-
permissions=[
|
|
99
|
-
"extras.add_dynamicgroup",
|
|
100
|
-
],
|
|
101
|
-
),
|
|
102
|
-
),
|
|
103
|
-
),
|
|
104
110
|
),
|
|
105
111
|
),
|
|
106
112
|
),
|
|
@@ -276,22 +282,6 @@ menu_items = (
|
|
|
276
282
|
),
|
|
277
283
|
),
|
|
278
284
|
),
|
|
279
|
-
NavMenuItem(
|
|
280
|
-
link="extras:relationship_list",
|
|
281
|
-
name="Relationships",
|
|
282
|
-
weight=200,
|
|
283
|
-
permissions=[
|
|
284
|
-
"extras.view_relationship",
|
|
285
|
-
],
|
|
286
|
-
buttons=(
|
|
287
|
-
NavMenuAddButton(
|
|
288
|
-
link="extras:relationship_add",
|
|
289
|
-
permissions=[
|
|
290
|
-
"extras.add_relationship",
|
|
291
|
-
],
|
|
292
|
-
),
|
|
293
|
-
),
|
|
294
|
-
),
|
|
295
285
|
NavMenuItem(
|
|
296
286
|
link="extras:note_list",
|
|
297
287
|
name="Notes",
|
|
@@ -389,37 +379,53 @@ menu_items = (
|
|
|
389
379
|
),
|
|
390
380
|
),
|
|
391
381
|
NavMenuGroup(
|
|
392
|
-
name="
|
|
382
|
+
name="Data Model",
|
|
393
383
|
weight=600,
|
|
394
384
|
items=(
|
|
395
385
|
NavMenuItem(
|
|
396
|
-
link="extras:
|
|
397
|
-
name="
|
|
386
|
+
link="extras:customfield_list",
|
|
387
|
+
name="Custom Fields",
|
|
398
388
|
weight=100,
|
|
399
389
|
permissions=[
|
|
400
|
-
"extras.
|
|
390
|
+
"extras.view_customfield",
|
|
401
391
|
],
|
|
402
392
|
buttons=(
|
|
403
393
|
NavMenuAddButton(
|
|
404
|
-
link="extras:
|
|
394
|
+
link="extras:customfield_add",
|
|
405
395
|
permissions=[
|
|
406
|
-
"extras.
|
|
396
|
+
"extras.add_customfield",
|
|
407
397
|
],
|
|
408
398
|
),
|
|
409
399
|
),
|
|
410
400
|
),
|
|
411
401
|
NavMenuItem(
|
|
412
|
-
link="extras:
|
|
413
|
-
name="
|
|
402
|
+
link="extras:relationship_list",
|
|
403
|
+
name="Relationships",
|
|
414
404
|
weight=200,
|
|
415
405
|
permissions=[
|
|
416
|
-
"extras.
|
|
406
|
+
"extras.view_relationship",
|
|
417
407
|
],
|
|
418
408
|
buttons=(
|
|
419
409
|
NavMenuAddButton(
|
|
420
|
-
link="extras:
|
|
410
|
+
link="extras:relationship_add",
|
|
421
411
|
permissions=[
|
|
422
|
-
"extras.
|
|
412
|
+
"extras.add_relationship",
|
|
413
|
+
],
|
|
414
|
+
),
|
|
415
|
+
),
|
|
416
|
+
),
|
|
417
|
+
NavMenuItem(
|
|
418
|
+
link="extras:computedfield_list",
|
|
419
|
+
name="Computed Fields",
|
|
420
|
+
weight=300,
|
|
421
|
+
permissions=[
|
|
422
|
+
"extras.view_computedfield",
|
|
423
|
+
],
|
|
424
|
+
buttons=(
|
|
425
|
+
NavMenuAddButton(
|
|
426
|
+
link="extras:computedfield_add",
|
|
427
|
+
permissions=[
|
|
428
|
+
"extras.add_computedfield",
|
|
423
429
|
],
|
|
424
430
|
),
|
|
425
431
|
),
|
|
@@ -427,7 +433,7 @@ menu_items = (
|
|
|
427
433
|
NavMenuItem(
|
|
428
434
|
link="extras:customlink_list",
|
|
429
435
|
name="Custom Links",
|
|
430
|
-
weight=
|
|
436
|
+
weight=400,
|
|
431
437
|
permissions=[
|
|
432
438
|
"extras.view_customlink",
|
|
433
439
|
],
|
|
@@ -4,6 +4,7 @@ from importlib import import_module
|
|
|
4
4
|
import inspect
|
|
5
5
|
from logging import getLogger
|
|
6
6
|
|
|
7
|
+
from django.conf import settings
|
|
7
8
|
from django.core.exceptions import ValidationError
|
|
8
9
|
from django.template.loader import get_template
|
|
9
10
|
from django.urls import get_resolver, URLPattern
|
|
@@ -147,7 +148,7 @@ class NautobotAppConfig(NautobotConfig):
|
|
|
147
148
|
|
|
148
149
|
# Import metrics (if present)
|
|
149
150
|
metrics = import_object(f"{self.__module__}.{self.metrics}")
|
|
150
|
-
if metrics is not None:
|
|
151
|
+
if metrics is not None and self.name not in settings.METRICS_DISABLED_APPS:
|
|
151
152
|
register_metrics(metrics)
|
|
152
153
|
self.features["metrics"] = [] # Initialize as empty, to be filled by the signal handler
|
|
153
154
|
# Inject the metrics to discover into the signal handler.
|
nautobot/extras/plugins/views.py
CHANGED
|
@@ -2,11 +2,9 @@ from collections import OrderedDict
|
|
|
2
2
|
|
|
3
3
|
from django.apps import apps
|
|
4
4
|
from django.conf import settings
|
|
5
|
-
from django.contrib.auth.mixins import LoginRequiredMixin
|
|
6
5
|
from django.http import Http404
|
|
7
6
|
from django.shortcuts import render
|
|
8
7
|
from django.urls.exceptions import NoReverseMatch
|
|
9
|
-
from django.views.generic import View
|
|
10
8
|
from django_tables2 import RequestConfig
|
|
11
9
|
from drf_spectacular.utils import extend_schema
|
|
12
10
|
from rest_framework import permissions
|
|
@@ -14,13 +12,14 @@ from rest_framework.response import Response
|
|
|
14
12
|
from rest_framework.reverse import reverse
|
|
15
13
|
from rest_framework.views import APIView
|
|
16
14
|
|
|
17
|
-
from nautobot.core.api.views import NautobotAPIVersionMixin
|
|
15
|
+
from nautobot.core.api.views import AuthenticatedAPIRootView, NautobotAPIVersionMixin
|
|
18
16
|
from nautobot.core.forms import TableConfigForm
|
|
17
|
+
from nautobot.core.views.generic import GenericView
|
|
19
18
|
from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
20
19
|
from nautobot.extras.plugins.tables import InstalledAppsTable
|
|
21
20
|
|
|
22
21
|
|
|
23
|
-
class InstalledAppsView(
|
|
22
|
+
class InstalledAppsView(GenericView):
|
|
24
23
|
"""
|
|
25
24
|
View for listing all installed Apps.
|
|
26
25
|
"""
|
|
@@ -66,7 +65,7 @@ class InstalledAppsView(LoginRequiredMixin, View):
|
|
|
66
65
|
)
|
|
67
66
|
|
|
68
67
|
|
|
69
|
-
class InstalledAppDetailView(
|
|
68
|
+
class InstalledAppDetailView(GenericView):
|
|
70
69
|
"""
|
|
71
70
|
View for showing details of an installed App.
|
|
72
71
|
"""
|
|
@@ -93,7 +92,6 @@ class InstalledAppsAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
93
92
|
"""
|
|
94
93
|
|
|
95
94
|
permission_classes = [permissions.IsAdminUser]
|
|
96
|
-
_ignore_model_permissions = True
|
|
97
95
|
|
|
98
96
|
def get_view_name(self):
|
|
99
97
|
return "Installed Apps"
|
|
@@ -129,11 +127,9 @@ class InstalledAppsAPIView(NautobotAPIVersionMixin, APIView):
|
|
|
129
127
|
return Response([self._get_app_data(apps.get_app_config(app)) for app in settings.PLUGINS])
|
|
130
128
|
|
|
131
129
|
|
|
132
|
-
class AppsAPIRootView(
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
def get_view_name(self):
|
|
136
|
-
return "Apps"
|
|
130
|
+
class AppsAPIRootView(AuthenticatedAPIRootView):
|
|
131
|
+
name = "Apps"
|
|
132
|
+
description = "API extension point for installed Nautobot Apps"
|
|
137
133
|
|
|
138
134
|
@staticmethod
|
|
139
135
|
def _get_app_entry(app_config, request, format_):
|
nautobot/extras/querysets.py
CHANGED
|
@@ -3,7 +3,6 @@ from django.contrib.contenttypes.models import ContentType
|
|
|
3
3
|
from django.core.cache import cache
|
|
4
4
|
from django.db.models import F, Model, OuterRef, Q, Subquery
|
|
5
5
|
from django.db.models.functions import JSONObject
|
|
6
|
-
from django_celery_beat.managers import ExtendedQuerySet
|
|
7
6
|
|
|
8
7
|
from nautobot.core.models.query_functions import EmptyGroupByJSONBAgg
|
|
9
8
|
from nautobot.core.models.querysets import RestrictedQuerySet
|
|
@@ -272,7 +271,7 @@ class JobQuerySet(RestrictedQuerySet):
|
|
|
272
271
|
)
|
|
273
272
|
|
|
274
273
|
|
|
275
|
-
class ScheduledJobExtendedQuerySet(RestrictedQuerySet
|
|
274
|
+
class ScheduledJobExtendedQuerySet(RestrictedQuerySet):
|
|
276
275
|
"""
|
|
277
276
|
Base queryset used for the ScheduledJob class
|
|
278
277
|
"""
|
nautobot/extras/signals.py
CHANGED
|
@@ -52,7 +52,7 @@ logger = logging.getLogger(__name__)
|
|
|
52
52
|
#
|
|
53
53
|
|
|
54
54
|
|
|
55
|
-
def
|
|
55
|
+
def get_user_if_authenticated(user, instance):
|
|
56
56
|
"""Return the user object associated with the request if the user is defined.
|
|
57
57
|
|
|
58
58
|
If the user is not defined, log a warning to indicate that the user couldn't be retrived from the request
|
|
@@ -119,7 +119,7 @@ def _handle_changed_object(sender, instance, raw=False, **kwargs):
|
|
|
119
119
|
|
|
120
120
|
# Record an ObjectChange if applicable
|
|
121
121
|
if hasattr(instance, "to_objectchange"):
|
|
122
|
-
user =
|
|
122
|
+
user = change_context_state.get().get_user(instance)
|
|
123
123
|
# save a copy of this instance's field cache so it can be restored after serialization
|
|
124
124
|
# to prevent unexpected behavior when chaining multiple signal handlers
|
|
125
125
|
original_cache = instance._state.fields_cache.copy()
|
|
@@ -186,7 +186,7 @@ def _handle_deleted_object(sender, instance, **kwargs):
|
|
|
186
186
|
|
|
187
187
|
# Record an ObjectChange if applicable
|
|
188
188
|
if hasattr(instance, "to_objectchange"):
|
|
189
|
-
user =
|
|
189
|
+
user = change_context_state.get().get_user(instance)
|
|
190
190
|
|
|
191
191
|
# save a copy of this instance's field cache so it can be restored after serialization
|
|
192
192
|
# to prevent unexpected behavior when chaining multiple signal handlers
|
|
@@ -238,13 +238,23 @@ def handle_cf_removed_obj_types(instance, action, pk_set, **kwargs):
|
|
|
238
238
|
"""
|
|
239
239
|
Handle the cleanup of old custom field data when a CustomField is removed from one or more ContentTypes.
|
|
240
240
|
"""
|
|
241
|
+
|
|
242
|
+
change_context = change_context_state.get()
|
|
243
|
+
if change_context is None:
|
|
244
|
+
context = None
|
|
245
|
+
else:
|
|
246
|
+
context = change_context.as_dict(instance=instance)
|
|
241
247
|
if action == "post_remove":
|
|
242
248
|
# Existing content types have been removed from the custom field, delete their data
|
|
243
|
-
|
|
249
|
+
if context:
|
|
250
|
+
context["context_detail"] = "delete custom field data from existing content types"
|
|
251
|
+
transaction.on_commit(lambda: delete_custom_field_data.delay(instance.key, pk_set, context))
|
|
244
252
|
|
|
245
253
|
elif action == "post_add":
|
|
246
254
|
# New content types have been added to the custom field, provision them
|
|
247
|
-
|
|
255
|
+
if context:
|
|
256
|
+
context["context_detail"] = "provision custom field data for new content types"
|
|
257
|
+
transaction.on_commit(lambda: provision_field.delay(instance.pk, pk_set, context))
|
|
248
258
|
|
|
249
259
|
|
|
250
260
|
m2m_changed.connect(handle_cf_removed_obj_types, sender=CustomField.content_types.through)
|
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
|
|
|
@@ -18,6 +18,7 @@ from nautobot.core.testing import APITestCase, APIViewTestCases
|
|
|
18
18
|
from nautobot.core.testing.utils import disable_warnings
|
|
19
19
|
from nautobot.core.utils.lookup import get_route_for_model
|
|
20
20
|
from nautobot.dcim.models import (
|
|
21
|
+
Controller,
|
|
21
22
|
Device,
|
|
22
23
|
DeviceType,
|
|
23
24
|
Location,
|
|
@@ -408,11 +409,9 @@ class ContactTest(APIViewTestCases.APIViewTestCase):
|
|
|
408
409
|
{
|
|
409
410
|
"name": "Contact 3",
|
|
410
411
|
"phone": "555-0123",
|
|
411
|
-
"email": "",
|
|
412
412
|
},
|
|
413
413
|
{
|
|
414
414
|
"name": "Contact 4",
|
|
415
|
-
"phone": "",
|
|
416
415
|
"email": "contact4@example.com",
|
|
417
416
|
},
|
|
418
417
|
]
|
|
@@ -2851,6 +2850,7 @@ class RelationshipTest(APIViewTestCases.APIViewTestCase, RequiredRelationshipTes
|
|
|
2851
2850
|
vlan_groups = VLANGroup.objects.all()[:2]
|
|
2852
2851
|
|
|
2853
2852
|
# Try deleting all devices and then creating 2 VLANs (fails):
|
|
2853
|
+
Controller.objects.filter(controller_device__isnull=False).delete()
|
|
2854
2854
|
Device.objects.all().delete()
|
|
2855
2855
|
response = send_bulk_data(
|
|
2856
2856
|
"post",
|
|
@@ -3611,11 +3611,9 @@ class TeamTest(APIViewTestCases.APIViewTestCase):
|
|
|
3611
3611
|
{
|
|
3612
3612
|
"name": "Team 3",
|
|
3613
3613
|
"phone": "555-0123",
|
|
3614
|
-
"email": "",
|
|
3615
3614
|
},
|
|
3616
3615
|
{
|
|
3617
3616
|
"name": "Team 4",
|
|
3618
|
-
"phone": "",
|
|
3619
3617
|
"email": "team4@example.com",
|
|
3620
3618
|
"address": "Rainbow Bridge, Central NJ",
|
|
3621
3619
|
},
|