nautobot 2.4.12__py3-none-any.whl → 2.4.14__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.
- nautobot/core/graphql/generators.py +8 -0
- nautobot/core/graphql/schema.py +30 -30
- nautobot/core/management/commands/migrate.py +90 -1
- nautobot/core/settings.yaml +3 -3
- nautobot/core/tables.py +4 -4
- nautobot/core/templates/inc/footer.html +4 -4
- nautobot/core/testing/api.py +7 -0
- nautobot/core/views/utils.py +1 -1
- nautobot/dcim/choices.py +2 -0
- nautobot/dcim/constants.py +0 -16
- nautobot/dcim/factory.py +1 -1
- nautobot/dcim/migrations/0071_alter_consoleport_options_and_more.py +42 -0
- nautobot/dcim/models/device_components.py +10 -2
- nautobot/dcim/models/devices.py +18 -0
- nautobot/dcim/templates/dcim/device.html +1 -34
- nautobot/dcim/templates/dcim/rack.html +2 -318
- nautobot/dcim/templates/dcim/rack_edit.html +2 -47
- nautobot/dcim/templates/dcim/rack_elevation_list.html +4 -1
- nautobot/dcim/templates/dcim/rack_retrieve.html +318 -0
- nautobot/dcim/templates/dcim/rack_update.html +47 -0
- nautobot/dcim/tests/test_models.py +1 -0
- nautobot/dcim/urls.py +3 -28
- nautobot/dcim/utils.py +4 -30
- nautobot/dcim/views.py +73 -71
- nautobot/extras/choices.py +12 -4
- nautobot/extras/filters/mixins.py +8 -6
- nautobot/extras/forms/forms.py +9 -0
- nautobot/extras/forms/mixins.py +4 -2
- nautobot/extras/migrations/0062_collect_roles_from_related_apps_roles.py +30 -7
- nautobot/extras/migrations/0124_add_joblogentry_index.py +16 -0
- nautobot/extras/models/customfields.py +52 -3
- nautobot/extras/models/jobs.py +6 -0
- nautobot/extras/models/relationships.py +55 -6
- nautobot/extras/templates/extras/graphqlquery.html +2 -97
- nautobot/extras/templates/extras/graphqlquery_list.html +1 -0
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +97 -0
- nautobot/extras/templates/extras/secretsgroup.html +2 -29
- nautobot/extras/templates/extras/secretsgroup_edit.html +2 -82
- nautobot/extras/templates/extras/secretsgroup_retrieve.html +29 -0
- nautobot/extras/templates/extras/secretsgroup_update.html +82 -0
- nautobot/extras/tests/test_customfields.py +115 -7
- nautobot/extras/tests/test_relationships.py +7 -1
- nautobot/extras/tests/test_views.py +113 -1
- nautobot/extras/urls.py +2 -51
- nautobot/extras/utils.py +4 -1
- nautobot/extras/views.py +42 -135
- nautobot/ipam/api/views.py +69 -6
- nautobot/ipam/migrations/0052_alter_ipaddress_index_together_and_more.py +28 -0
- nautobot/ipam/models.py +13 -1
- nautobot/ipam/tests/test_api.py +351 -3
- nautobot/ipam/utils/testing.py +76 -29
- nautobot/project-static/docs/404.html +11 -34
- nautobot/project-static/docs/apps/index.html +11 -34
- nautobot/project-static/docs/apps/nautobot-apps.html +11 -34
- nautobot/project-static/docs/assets/javascripts/{bundle.56ea9cef.min.js → bundle.50899def.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.56ea9cef.min.js.map → bundle.50899def.min.js.map} +2 -2
- nautobot/project-static/docs/assets/stylesheets/{main.342714a4.min.css → main.7e37652d.min.css} +1 -1
- nautobot/project-static/docs/assets/stylesheets/{main.342714a4.min.css.map → main.7e37652d.min.css.map} +1 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +11 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +13 -34
- nautobot/project-static/docs/development/apps/api/configuration-view.html +11 -34
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +11 -34
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +11 -34
- nautobot/project-static/docs/development/apps/api/models/global-search.html +11 -34
- nautobot/project-static/docs/development/apps/api/models/graphql.html +11 -34
- nautobot/project-static/docs/development/apps/api/models/index.html +11 -34
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +11 -34
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +11 -34
- nautobot/project-static/docs/development/apps/api/prometheus.html +11 -34
- nautobot/project-static/docs/development/apps/api/setup.html +11 -34
- nautobot/project-static/docs/development/apps/api/testing.html +11 -34
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +11 -34
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +11 -34
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +11 -34
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +11 -34
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/base-template.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/index.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/notes.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +11 -34
- nautobot/project-static/docs/development/apps/api/views/urls.html +11 -34
- nautobot/project-static/docs/development/apps/index.html +11 -34
- nautobot/project-static/docs/development/apps/migration/code-updates.html +11 -34
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +11 -34
- nautobot/project-static/docs/development/apps/migration/from-v1.html +11 -34
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +11 -34
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +11 -34
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +11 -34
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +11 -34
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +11 -34
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +11 -34
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +11 -34
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +11 -34
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +11 -34
- nautobot/project-static/docs/development/core/application-registry.html +139 -133
- nautobot/project-static/docs/development/core/best-practices.html +11 -34
- nautobot/project-static/docs/development/core/bootstrap-ui.html +11 -34
- nautobot/project-static/docs/development/core/caching.html +11 -34
- nautobot/project-static/docs/development/core/controllers.html +11 -34
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +11 -34
- nautobot/project-static/docs/development/core/generic-views.html +11 -34
- nautobot/project-static/docs/development/core/getting-started.html +11 -34
- nautobot/project-static/docs/development/core/homepage.html +11 -34
- nautobot/project-static/docs/development/core/index.html +11 -34
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +11 -34
- nautobot/project-static/docs/development/core/model-checklist.html +11 -34
- nautobot/project-static/docs/development/core/model-features.html +11 -34
- nautobot/project-static/docs/development/core/natural-keys.html +11 -34
- nautobot/project-static/docs/development/core/navigation-menu.html +11 -34
- nautobot/project-static/docs/development/core/release-checklist.html +11 -34
- nautobot/project-static/docs/development/core/role-internals.html +11 -34
- nautobot/project-static/docs/development/core/settings.html +11 -34
- nautobot/project-static/docs/development/core/style-guide.html +11 -34
- nautobot/project-static/docs/development/core/templates.html +11 -34
- nautobot/project-static/docs/development/core/testing.html +11 -34
- nautobot/project-static/docs/development/core/ui-component-framework.html +11 -34
- nautobot/project-static/docs/development/core/user-preferences.html +11 -34
- nautobot/project-static/docs/development/index.html +11 -34
- nautobot/project-static/docs/development/jobs/getting-started.html +11 -34
- nautobot/project-static/docs/development/jobs/index.html +11 -34
- nautobot/project-static/docs/development/jobs/installation.html +11 -34
- nautobot/project-static/docs/development/jobs/job-extensions.html +11 -34
- nautobot/project-static/docs/development/jobs/job-logging.html +11 -34
- nautobot/project-static/docs/development/jobs/job-patterns.html +11 -34
- nautobot/project-static/docs/development/jobs/job-structure.html +11 -34
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +11 -34
- nautobot/project-static/docs/development/jobs/testing.html +11 -34
- nautobot/project-static/docs/index.html +11 -34
- nautobot/project-static/docs/overview/application_stack.html +11 -34
- nautobot/project-static/docs/overview/design_philosophy.html +11 -34
- nautobot/project-static/docs/release-notes/index.html +11 -34
- nautobot/project-static/docs/release-notes/version-1.0.html +11 -34
- nautobot/project-static/docs/release-notes/version-1.1.html +11 -34
- nautobot/project-static/docs/release-notes/version-1.2.html +11 -34
- nautobot/project-static/docs/release-notes/version-1.3.html +11 -34
- nautobot/project-static/docs/release-notes/version-1.4.html +11 -34
- nautobot/project-static/docs/release-notes/version-1.5.html +11 -34
- nautobot/project-static/docs/release-notes/version-1.6.html +11 -34
- nautobot/project-static/docs/release-notes/version-2.0.html +11 -34
- nautobot/project-static/docs/release-notes/version-2.1.html +11 -34
- nautobot/project-static/docs/release-notes/version-2.2.html +11 -34
- nautobot/project-static/docs/release-notes/version-2.3.html +11 -34
- nautobot/project-static/docs/release-notes/version-2.4.html +271 -34
- nautobot/project-static/docs/requirements.txt +1 -1
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +299 -299
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +11 -34
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +11 -34
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +11 -34
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +11 -34
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +11 -34
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +14 -37
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +11 -34
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +11 -34
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +11 -34
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +11 -34
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +11 -34
- nautobot/project-static/docs/user-guide/administration/installation/index.html +11 -34
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +11 -34
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +11 -34
- nautobot/project-static/docs/user-guide/administration/installation/services.html +11 -34
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +11 -34
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +11 -34
- nautobot/project-static/docs/user-guide/administration/security/index.html +11 -34
- nautobot/project-static/docs/user-guide/administration/security/notices.html +11 -34
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +19 -39
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +11 -34
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +14 -37
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +19 -52
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +14 -37
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulefamily.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +11 -34
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +11 -34
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +11 -34
- nautobot/project-static/docs/user-guide/index.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/managing-jobs.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +11 -34
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +11 -34
- nautobot/tenancy/api/views.py +2 -1
- {nautobot-2.4.12.dist-info → nautobot-2.4.14.dist-info}/METADATA +5 -5
- {nautobot-2.4.12.dist-info → nautobot-2.4.14.dist-info}/RECORD +366 -357
- {nautobot-2.4.12.dist-info → nautobot-2.4.14.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.12.dist-info → nautobot-2.4.14.dist-info}/NOTICE +0 -0
- {nautobot-2.4.12.dist-info → nautobot-2.4.14.dist-info}/WHEEL +0 -0
- {nautobot-2.4.12.dist-info → nautobot-2.4.14.dist-info}/entry_points.txt +0 -0
|
@@ -16,6 +16,9 @@ logger = logging.getLogger(__name__)
|
|
|
16
16
|
RESOLVER_PREFIX = "resolve_"
|
|
17
17
|
|
|
18
18
|
|
|
19
|
+
LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE = {}
|
|
20
|
+
|
|
21
|
+
|
|
19
22
|
def generate_restricted_queryset():
|
|
20
23
|
"""
|
|
21
24
|
Generate a function to return a restricted queryset compatible with the internal permissions system.
|
|
@@ -248,6 +251,9 @@ def generate_schema_type(app_name: str, model: object) -> OptimizedNautobotObjec
|
|
|
248
251
|
def generate_list_search_parameters(schema_type):
|
|
249
252
|
"""Generate list of query parameters for the list resolver based on a filterset."""
|
|
250
253
|
|
|
254
|
+
if schema_type in LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE:
|
|
255
|
+
return LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE[schema_type]
|
|
256
|
+
|
|
251
257
|
search_params = {
|
|
252
258
|
"limit": graphene.Int(),
|
|
253
259
|
"offset": graphene.Int(),
|
|
@@ -259,6 +265,8 @@ def generate_list_search_parameters(schema_type):
|
|
|
259
265
|
)
|
|
260
266
|
)
|
|
261
267
|
|
|
268
|
+
LIST_SEARCH_PARAMS_BY_SCHEMA_TYPE[schema_type] = search_params
|
|
269
|
+
|
|
262
270
|
return search_params
|
|
263
271
|
|
|
264
272
|
|
nautobot/core/graphql/schema.py
CHANGED
|
@@ -243,12 +243,12 @@ def extend_schema_type_custom_field(schema_type, model):
|
|
|
243
243
|
(DjangoObjectType): The extended schema_type object
|
|
244
244
|
"""
|
|
245
245
|
|
|
246
|
-
|
|
246
|
+
custom_fields = CustomField.objects.get_for_model(model, get_queryset=False)
|
|
247
247
|
prefix = ""
|
|
248
248
|
if settings.GRAPHQL_CUSTOM_FIELD_PREFIX and isinstance(settings.GRAPHQL_CUSTOM_FIELD_PREFIX, str):
|
|
249
249
|
prefix = f"{settings.GRAPHQL_CUSTOM_FIELD_PREFIX}_"
|
|
250
250
|
|
|
251
|
-
for field in
|
|
251
|
+
for field in custom_fields:
|
|
252
252
|
# Since we guaranteed cf.key's uniqueness in CustomField data migration
|
|
253
253
|
# We can safely field_key this in our GraphQL without duplication
|
|
254
254
|
# For new CustomField instances, we also make sure that duplicate key does not exist.
|
|
@@ -281,6 +281,7 @@ def extend_schema_type_custom_field(schema_type, model):
|
|
|
281
281
|
|
|
282
282
|
def extend_schema_type_computed_field(schema_type, model):
|
|
283
283
|
"""Extend schema_type object to had attribute and resolver around computed_fields.
|
|
284
|
+
|
|
284
285
|
Each computed field will be defined as a first level attribute.
|
|
285
286
|
|
|
286
287
|
Args:
|
|
@@ -291,12 +292,12 @@ def extend_schema_type_computed_field(schema_type, model):
|
|
|
291
292
|
(DjangoObjectType): The extended schema_type object
|
|
292
293
|
"""
|
|
293
294
|
|
|
294
|
-
|
|
295
|
+
computed_fields = ComputedField.objects.get_for_model(model, get_queryset=False)
|
|
295
296
|
prefix = ""
|
|
296
297
|
if settings.GRAPHQL_COMPUTED_FIELD_PREFIX and isinstance(settings.GRAPHQL_COMPUTED_FIELD_PREFIX, str):
|
|
297
298
|
prefix = f"{settings.GRAPHQL_COMPUTED_FIELD_PREFIX}_"
|
|
298
299
|
|
|
299
|
-
for field in
|
|
300
|
+
for field in computed_fields:
|
|
300
301
|
field_name = f"{prefix}{field.key}"
|
|
301
302
|
try:
|
|
302
303
|
check_if_key_is_graphql_safe("Computed Field", field.key)
|
|
@@ -396,12 +397,16 @@ def extend_schema_type_global_features(schema_type, model):
|
|
|
396
397
|
|
|
397
398
|
|
|
398
399
|
def extend_schema_type_relationships(schema_type, model):
|
|
399
|
-
"""
|
|
400
|
-
|
|
400
|
+
"""
|
|
401
|
+
Extend the schema type with attributes and resolvers for the relationships associated with this model.
|
|
401
402
|
|
|
403
|
+
Args:
|
|
404
|
+
schema_type (DjangoObjectType): GraphQL Object type for a given model
|
|
405
|
+
model (Model): Django model
|
|
406
|
+
"""
|
|
402
407
|
relationships_by_side = {
|
|
403
|
-
"source": Relationship.objects.get_for_model_source(model),
|
|
404
|
-
"destination": Relationship.objects.get_for_model_destination(model),
|
|
408
|
+
"source": Relationship.objects.get_for_model_source(model, get_queryset=False),
|
|
409
|
+
"destination": Relationship.objects.get_for_model_destination(model, get_queryset=False),
|
|
405
410
|
}
|
|
406
411
|
|
|
407
412
|
prefix = ""
|
|
@@ -499,30 +504,16 @@ def generate_query_mixin():
|
|
|
499
504
|
|
|
500
505
|
logger.debug("Generating dynamic schemas for all models in the models_features graphql registry")
|
|
501
506
|
# - Ensure an attribute/schematype with the same name doesn't already exist
|
|
502
|
-
registered_models = registry.get("
|
|
503
|
-
for
|
|
504
|
-
|
|
505
|
-
try:
|
|
506
|
-
# Find the model class based on the content type
|
|
507
|
-
ct = ContentType.objects.get(app_label=app_name, model=model_name)
|
|
508
|
-
model = ct.model_class()
|
|
509
|
-
except ContentType.DoesNotExist:
|
|
510
|
-
logger.warning(
|
|
511
|
-
'Unable to generate a schema type for the model "%s.%s" in GraphQL, '
|
|
512
|
-
"as this model doesn't have an associated ContentType. Please create the Object manually.",
|
|
513
|
-
app_name,
|
|
514
|
-
model_name,
|
|
515
|
-
)
|
|
516
|
-
continue
|
|
507
|
+
registered_models = registry.get("feature_models", {}).get("graphql", [])
|
|
508
|
+
for model in registered_models:
|
|
509
|
+
type_identifier = model._meta.label_lower
|
|
517
510
|
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
# Skip models that have been added statically
|
|
522
|
-
continue
|
|
511
|
+
if type_identifier in registry["graphql_types"].keys():
|
|
512
|
+
# Skip models that have been added statically
|
|
513
|
+
continue
|
|
523
514
|
|
|
524
|
-
|
|
525
|
-
|
|
515
|
+
schema_type = generate_schema_type(app_name=model._meta.app_label, model=model)
|
|
516
|
+
registry["graphql_types"][type_identifier] = schema_type
|
|
526
517
|
|
|
527
518
|
logger.debug("Adding plugins' statically defined graphql schema types")
|
|
528
519
|
# After checking for conflict
|
|
@@ -542,6 +533,15 @@ def generate_query_mixin():
|
|
|
542
533
|
registry["graphql_types"][type_identifier] = schema_type
|
|
543
534
|
|
|
544
535
|
logger.debug("Extending all registered schema types with dynamic attributes")
|
|
536
|
+
|
|
537
|
+
# Precache all content-types as we'll need them for filtering and the like
|
|
538
|
+
for content_type in ContentType.objects.all():
|
|
539
|
+
ContentType.objects._add_to_cache(ContentType.objects.db, content_type)
|
|
540
|
+
|
|
541
|
+
CustomField.objects.populate_list_caches()
|
|
542
|
+
ComputedField.objects.populate_list_caches()
|
|
543
|
+
Relationship.objects.populate_list_caches()
|
|
544
|
+
|
|
545
545
|
for schema_type in registry["graphql_types"].values():
|
|
546
546
|
if already_present(schema_type._meta.model):
|
|
547
547
|
continue
|
|
@@ -1,8 +1,97 @@
|
|
|
1
1
|
# noinspection PyUnresolvedReferences
|
|
2
|
-
|
|
2
|
+
import contextlib
|
|
3
|
+
import time
|
|
4
|
+
|
|
5
|
+
from django.apps import apps
|
|
6
|
+
from django.core.management.commands.migrate import Command as _Command
|
|
3
7
|
from django.db import models
|
|
8
|
+
from django.db.migrations.operations.fields import FieldOperation
|
|
9
|
+
from django.db.migrations.operations.models import ModelOperation
|
|
4
10
|
|
|
5
11
|
from nautobot.core.management import commands
|
|
6
12
|
|
|
7
13
|
# Overload deconstruct with our own.
|
|
8
14
|
models.Field.deconstruct = commands.custom_deconstruct
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class Command(_Command):
|
|
18
|
+
def migration_progress_callback(self, action, migration=None, fake=False):
|
|
19
|
+
"""
|
|
20
|
+
Enhanced version of Django's built-in callback.
|
|
21
|
+
|
|
22
|
+
Differences in behavior:
|
|
23
|
+
- Measures and reports elapsed time whenever verbosity >= 1 (default value)
|
|
24
|
+
- Measures and reports affected record counts and elapsed time per record where applicable at verbosity >= 2.
|
|
25
|
+
- Aligns output to 80-character terminal width in most cases
|
|
26
|
+
|
|
27
|
+
Examples:
|
|
28
|
+
# nautobot-server migrate
|
|
29
|
+
Running migrations:
|
|
30
|
+
Applying dcim.0065_controller_capabilities_and_more... OK 0.10s
|
|
31
|
+
Applying wireless.0001_initial... OK 0.31s
|
|
32
|
+
Applying dcim.0066_controllermanageddevicegroup_radio_profi... OK 0.12s
|
|
33
|
+
|
|
34
|
+
# nautobot-server migrate -v=2 extras 0100
|
|
35
|
+
Operations to perform:
|
|
36
|
+
Target specific migration: 0100_fileproxy_job_result, from extras
|
|
37
|
+
Running migrations:
|
|
38
|
+
Rendering model states... DONE 19.10s
|
|
39
|
+
Unapplying ipam.0052_alter_ipaddress_index_together_and_mor... OK 0.10s
|
|
40
|
+
Affected ipam.ipaddress 75 rows 0.001s/record
|
|
41
|
+
Affected ipam.prefix 184 rows 0.000s/record
|
|
42
|
+
Affected ipam.vrf 20 rows 0.004s/record
|
|
43
|
+
Unapplying ipam.0051_added_optional_vrf_relationship_to_vdc... OK 0.10s
|
|
44
|
+
Affected ipam.vrf 20 rows 0.006s/record
|
|
45
|
+
Affected ipam.vrfdeviceassignment 140 rows 0.001s/record
|
|
46
|
+
Unapplying virtualization.0030_alter_virtualmachine_local_c... OK 0.30s
|
|
47
|
+
Affected virtualization.virtualmachine 0 rows
|
|
48
|
+
Affected virtualization.vminterface 0 rows
|
|
49
|
+
Unapplying virtualization.0029_add_role_field_to_interface_... OK 0.10s
|
|
50
|
+
Affected virtualization.vminterface 0 rows
|
|
51
|
+
"""
|
|
52
|
+
if self.verbosity < 1:
|
|
53
|
+
return
|
|
54
|
+
|
|
55
|
+
if action in ["apply_start", "render_start", "unapply_start"]:
|
|
56
|
+
self.start = time.monotonic()
|
|
57
|
+
self.affected_models = set()
|
|
58
|
+
self.affected_models_count = {}
|
|
59
|
+
self.migration = migration
|
|
60
|
+
if self.verbosity >= 2 and self.migration is not None:
|
|
61
|
+
for operation in self.migration.operations:
|
|
62
|
+
if isinstance(operation, FieldOperation):
|
|
63
|
+
self.affected_models.add((self.migration.app_label, operation.model_name.lower()))
|
|
64
|
+
elif isinstance(operation, ModelOperation):
|
|
65
|
+
self.affected_models.add((self.migration.app_label, operation.name.lower()))
|
|
66
|
+
|
|
67
|
+
for app_label, model_name in sorted(self.affected_models):
|
|
68
|
+
self.affected_models_count[f"{app_label}.{model_name}"] = 0
|
|
69
|
+
with contextlib.suppress(Exception):
|
|
70
|
+
model = apps.get_model(app_label, model_name)
|
|
71
|
+
self.affected_models_count[model._meta.label_lower] = model.objects.count()
|
|
72
|
+
|
|
73
|
+
if action == "apply_start":
|
|
74
|
+
msg = f" Applying {str(migration)[:50]}..."
|
|
75
|
+
elif action == "render_start":
|
|
76
|
+
msg = " Rendering model states..."
|
|
77
|
+
else:
|
|
78
|
+
msg = f" Unapplying {str(migration)[:48]}..."
|
|
79
|
+
self.stdout.write(f"{msg:<64}", ending="")
|
|
80
|
+
self.stdout.flush()
|
|
81
|
+
|
|
82
|
+
elif action in ["apply_success", "render_success", "unapply_success"]:
|
|
83
|
+
elapsed = time.monotonic() - self.start
|
|
84
|
+
outcome = "DONE" if action == "render_success" else "FAKED" if fake else "OK"
|
|
85
|
+
self.stdout.write(self.style.SUCCESS(f" {outcome:<5} {elapsed: 8.2f}s"))
|
|
86
|
+
if self.verbosity >= 2 and self.migration is not None:
|
|
87
|
+
for app_label, model_name in sorted(self.affected_models):
|
|
88
|
+
if self.affected_models_count[f"{app_label}.{model_name}"] == 0:
|
|
89
|
+
with contextlib.suppress(Exception):
|
|
90
|
+
model = apps.get_model(app_label, model_name)
|
|
91
|
+
self.affected_models_count[model._meta.label_lower] = model.objects.count()
|
|
92
|
+
|
|
93
|
+
for key, value in self.affected_models_count.items():
|
|
94
|
+
if value:
|
|
95
|
+
self.stdout.write(f" Affected {key:<38} {value: 8} rows {elapsed/value:6.3f}s/record")
|
|
96
|
+
else:
|
|
97
|
+
self.stdout.write(f" Affected {key:<38} {value: 8} rows")
|
nautobot/core/settings.yaml
CHANGED
|
@@ -1487,9 +1487,9 @@ properties:
|
|
|
1487
1487
|
}
|
|
1488
1488
|
```
|
|
1489
1489
|
|
|
1490
|
-
The default top-level keys
|
|
1491
|
-
|
|
1492
|
-
|
|
1490
|
+
The default top-level keys consists of `ansible`, `hier_config`, `napalm`, etc, and comes from netutils, but
|
|
1491
|
+
you can also add additional keys if you have an alternative network driver that you want your Nautobot instance
|
|
1492
|
+
to include.
|
|
1493
1493
|
is_constance_config: true
|
|
1494
1494
|
type: "object"
|
|
1495
1495
|
version_added: "1.6.0"
|
nautobot/core/tables.py
CHANGED
|
@@ -80,14 +80,14 @@ class BaseTable(django_tables2.Table):
|
|
|
80
80
|
reverse_lookup="static_group_associations__associated_object_id",
|
|
81
81
|
)
|
|
82
82
|
|
|
83
|
-
for cf in models.CustomField.objects.get_for_model(model):
|
|
83
|
+
for cf in models.CustomField.objects.get_for_model(model, get_queryset=False):
|
|
84
84
|
name = cf.add_prefix_to_cf_key()
|
|
85
85
|
self.base_columns[name] = CustomFieldColumn(cf)
|
|
86
86
|
|
|
87
|
-
for cpf in models.ComputedField.objects.get_for_model(model):
|
|
87
|
+
for cpf in models.ComputedField.objects.get_for_model(model, get_queryset=False):
|
|
88
88
|
self.base_columns[f"cpf_{cpf.key}"] = ComputedFieldColumn(cpf)
|
|
89
89
|
|
|
90
|
-
for relationship in models.Relationship.objects.get_for_model_source(model):
|
|
90
|
+
for relationship in models.Relationship.objects.get_for_model_source(model, get_queryset=False):
|
|
91
91
|
if not relationship.symmetric:
|
|
92
92
|
self.base_columns[f"cr_{relationship.key}_src"] = RelationshipColumn(
|
|
93
93
|
relationship, side=choices.RelationshipSideChoices.SIDE_SOURCE
|
|
@@ -97,7 +97,7 @@ class BaseTable(django_tables2.Table):
|
|
|
97
97
|
relationship, side=choices.RelationshipSideChoices.SIDE_PEER
|
|
98
98
|
)
|
|
99
99
|
|
|
100
|
-
for relationship in models.Relationship.objects.get_for_model_destination(model):
|
|
100
|
+
for relationship in models.Relationship.objects.get_for_model_destination(model, get_queryset=False):
|
|
101
101
|
if not relationship.symmetric:
|
|
102
102
|
self.base_columns[f"cr_{relationship.key}_dst"] = RelationshipColumn(
|
|
103
103
|
relationship, side=choices.RelationshipSideChoices.SIDE_DESTINATION
|
|
@@ -36,16 +36,16 @@
|
|
|
36
36
|
<a href="#theme_modal" data-toggle="modal" data-target="#theme_modal" id="btn-theme-modal"><i class="mdi mdi-theme-light-dark text-primary"></i>Theme</a> ·
|
|
37
37
|
<i class="mdi mdi-book-open-page-variant text-primary"></i>
|
|
38
38
|
{% if settings.BRANDING_URLS.docs %}
|
|
39
|
-
<a href="{{ settings.BRANDING_URLS.docs }}">Docs</a>
|
|
39
|
+
<a href="{{ settings.BRANDING_URLS.docs }}" target="_blank">Docs</a>
|
|
40
40
|
{% else %}
|
|
41
|
-
<a href="{% static 'docs/index.html' %}">Docs</a>
|
|
41
|
+
<a href="{% static 'docs/index.html' %}" target="_blank">Docs</a>
|
|
42
42
|
{% endif %}
|
|
43
43
|
·
|
|
44
44
|
<img src="{% static 'img/jinja_logo.svg' %}" style="height:20px"> <a href="{% url 'render_jinja_template' %}">Jinja Renderer</a> ·
|
|
45
45
|
<i class="mdi mdi-cloud-braces text-primary"></i> <a href="{% url 'api_docs' %}">API</a> ·
|
|
46
46
|
<i class="mdi mdi-graphql text-primary"></i> <a href="{% url 'graphql' %}">GraphQL</a> ·
|
|
47
|
-
<i class="mdi mdi-xml text-primary"></i> <a href="{{ settings.BRANDING_URLS.code }}">Code</a> ·
|
|
48
|
-
<i class="mdi mdi-lifebuoy text-primary"></i> <a href="{{ settings.BRANDING_URLS.help }}">Help</a>
|
|
47
|
+
<i class="mdi mdi-xml text-primary"></i> <a href="{{ settings.BRANDING_URLS.code }}" target="_blank">Code</a> ·
|
|
48
|
+
<i class="mdi mdi-lifebuoy text-primary"></i> <a href="{{ settings.BRANDING_URLS.help }}" target="_blank">Help</a>
|
|
49
49
|
</p>
|
|
50
50
|
{% endif %}
|
|
51
51
|
</div>
|
nautobot/core/testing/api.py
CHANGED
|
@@ -7,6 +7,7 @@ from django.contrib.contenttypes.fields import GenericForeignKey
|
|
|
7
7
|
from django.contrib.contenttypes.models import ContentType
|
|
8
8
|
from django.db import connections, DEFAULT_DB_ALIAS
|
|
9
9
|
from django.db.models import ForeignKey, ManyToManyField, QuerySet
|
|
10
|
+
from django.http import QueryDict
|
|
10
11
|
from django.test import override_settings, tag
|
|
11
12
|
from django.test.utils import CaptureQueriesContext
|
|
12
13
|
from django.urls import reverse
|
|
@@ -105,6 +106,12 @@ class APITestCase(views.ModelTestCase):
|
|
|
105
106
|
m2m_fields.append(field_name)
|
|
106
107
|
return m2m_fields
|
|
107
108
|
|
|
109
|
+
@staticmethod
|
|
110
|
+
def add_query_params_to_url(url: str, query_dict: dict) -> str:
|
|
111
|
+
query = QueryDict(mutable=True)
|
|
112
|
+
query.update(query_dict)
|
|
113
|
+
return f"{url}?{query.urlencode()}"
|
|
114
|
+
|
|
108
115
|
|
|
109
116
|
@tag("unit")
|
|
110
117
|
class APIViewTestCases:
|
nautobot/core/views/utils.py
CHANGED
|
@@ -123,7 +123,7 @@ def get_csv_form_fields_from_serializer_class(serializer_class):
|
|
|
123
123
|
from nautobot.extras.choices import CustomFieldTypeChoices
|
|
124
124
|
from nautobot.extras.models import CustomField
|
|
125
125
|
|
|
126
|
-
cfs = CustomField.objects.get_for_model(serializer_class.Meta.model)
|
|
126
|
+
cfs = CustomField.objects.get_for_model(serializer_class.Meta.model, get_queryset=False)
|
|
127
127
|
for cf in cfs:
|
|
128
128
|
cf_form_field = cf.to_form_field(set_initial=False)
|
|
129
129
|
field_info = {
|
nautobot/dcim/choices.py
CHANGED
|
@@ -589,6 +589,7 @@ class PowerOutletTypeChoices(ChoiceSet):
|
|
|
589
589
|
TYPE_NEUTRIK_POWERCON_TRUE1 = "neutrik-powercon-true1"
|
|
590
590
|
TYPE_NEUTRIK_POWERCON_TRUE1_TOP = "neutrik-powercon-true1-top"
|
|
591
591
|
TYPE_UBIQUITI_SMARTPOWER = "ubiquiti-smartpower"
|
|
592
|
+
TYPE_EATON_C39 = "eaton-c39"
|
|
592
593
|
# Other
|
|
593
594
|
TYPE_HARDWIRED = "hardwired"
|
|
594
595
|
TYPE_OTHER = "other"
|
|
@@ -728,6 +729,7 @@ class PowerOutletTypeChoices(ChoiceSet):
|
|
|
728
729
|
(TYPE_NEUTRIK_POWERCON_TRUE1, "Neutrik powerCON TRUE1"),
|
|
729
730
|
(TYPE_NEUTRIK_POWERCON_TRUE1_TOP, "Neutrik powerCON TRUE1 TOP"),
|
|
730
731
|
(TYPE_UBIQUITI_SMARTPOWER, "Ubiquiti SmartPower"),
|
|
732
|
+
(TYPE_EATON_C39, "Eaton C39"),
|
|
731
733
|
),
|
|
732
734
|
),
|
|
733
735
|
(
|
nautobot/dcim/constants.py
CHANGED
|
@@ -96,22 +96,6 @@ COMPATIBLE_TERMINATION_TYPES = {
|
|
|
96
96
|
],
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
-
#
|
|
100
|
-
# Platforms
|
|
101
|
-
#
|
|
102
|
-
|
|
103
|
-
NETUTILS_NETWORK_DRIVER_MAPPING_NAMES = {
|
|
104
|
-
"ansible",
|
|
105
|
-
"hier_config",
|
|
106
|
-
"napalm",
|
|
107
|
-
"netmiko",
|
|
108
|
-
"netutils_parser",
|
|
109
|
-
"ntc_templates",
|
|
110
|
-
"pyats",
|
|
111
|
-
"pyntc",
|
|
112
|
-
"scrapli",
|
|
113
|
-
}
|
|
114
|
-
|
|
115
99
|
#
|
|
116
100
|
# Modules
|
|
117
101
|
#
|
nautobot/dcim/factory.py
CHANGED
|
@@ -616,7 +616,7 @@ class RackFactory(PrimaryModelFactory):
|
|
|
616
616
|
has_role = NautobotBoolIterator()
|
|
617
617
|
role = factory.Maybe("has_role", random_instance(lambda: Role.objects.get_for_model(Rack)), None)
|
|
618
618
|
|
|
619
|
-
location = random_instance(lambda: Location.objects.get_for_model(
|
|
619
|
+
location = random_instance(lambda: Location.objects.get_for_model(Rack), allow_null=False)
|
|
620
620
|
|
|
621
621
|
has_rack_group = NautobotBoolIterator() # TODO there's no RackGroupFactory yet...
|
|
622
622
|
rack_group = factory.Maybe("has_rack_group", random_instance(RackGroup), None)
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Generated by Django 4.2.20 on 2025-07-17 20:24
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
import nautobot.core.models.query_functions
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class Migration(migrations.Migration):
|
|
9
|
+
dependencies = [
|
|
10
|
+
("dcim", "0070_modulefamily_models"),
|
|
11
|
+
]
|
|
12
|
+
|
|
13
|
+
operations = [
|
|
14
|
+
migrations.AlterModelOptions(
|
|
15
|
+
name="consoleport",
|
|
16
|
+
options={"ordering": ("device", "module__id", "_name")},
|
|
17
|
+
),
|
|
18
|
+
migrations.AlterModelOptions(
|
|
19
|
+
name="consoleserverport",
|
|
20
|
+
options={"ordering": ("device", "module__id", "_name")},
|
|
21
|
+
),
|
|
22
|
+
migrations.AlterModelOptions(
|
|
23
|
+
name="frontport",
|
|
24
|
+
options={"ordering": ("device", "module__id", "_name")},
|
|
25
|
+
),
|
|
26
|
+
migrations.AlterModelOptions(
|
|
27
|
+
name="interface",
|
|
28
|
+
options={"ordering": ("device", "module__id", nautobot.core.models.query_functions.CollateAsChar("_name"))},
|
|
29
|
+
),
|
|
30
|
+
migrations.AlterModelOptions(
|
|
31
|
+
name="poweroutlet",
|
|
32
|
+
options={"ordering": ("device", "module__id", "_name")},
|
|
33
|
+
),
|
|
34
|
+
migrations.AlterModelOptions(
|
|
35
|
+
name="powerport",
|
|
36
|
+
options={"ordering": ("device", "module__id", "_name")},
|
|
37
|
+
),
|
|
38
|
+
migrations.AlterModelOptions(
|
|
39
|
+
name="rearport",
|
|
40
|
+
options={"ordering": ("device", "module__id", "_name")},
|
|
41
|
+
),
|
|
42
|
+
]
|
|
@@ -2,6 +2,7 @@ import re
|
|
|
2
2
|
|
|
3
3
|
from django.contrib.contenttypes.fields import GenericForeignKey, GenericRelation
|
|
4
4
|
from django.contrib.contenttypes.models import ContentType
|
|
5
|
+
from django.core.cache import cache
|
|
5
6
|
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
6
7
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
|
7
8
|
from django.db import models, transaction
|
|
@@ -123,7 +124,7 @@ class ModularComponentModel(ComponentModel):
|
|
|
123
124
|
|
|
124
125
|
class Meta:
|
|
125
126
|
abstract = True
|
|
126
|
-
ordering = ("device", "
|
|
127
|
+
ordering = ("device", "module__id", "_name") # Module.ordering is complex/expensive so don't order by module
|
|
127
128
|
constraints = [
|
|
128
129
|
models.UniqueConstraint(
|
|
129
130
|
fields=("device", "name"),
|
|
@@ -646,7 +647,7 @@ class Interface(ModularComponentModel, CableTermination, PathEndpoint, BaseInter
|
|
|
646
647
|
)
|
|
647
648
|
|
|
648
649
|
class Meta(ModularComponentModel.Meta):
|
|
649
|
-
ordering = ("device", "
|
|
650
|
+
ordering = ("device", "module__id", CollateAsChar("_name")) # Module.ordering is complex; don't order by module
|
|
650
651
|
|
|
651
652
|
def clean(self):
|
|
652
653
|
super().clean()
|
|
@@ -1311,3 +1312,10 @@ class ModuleBay(PrimaryModel):
|
|
|
1311
1312
|
self.position = self.name
|
|
1312
1313
|
|
|
1313
1314
|
clean.alters_data = True
|
|
1315
|
+
|
|
1316
|
+
def save(self, *args, **kwargs):
|
|
1317
|
+
super().save(*args, **kwargs)
|
|
1318
|
+
|
|
1319
|
+
if self.parent_device is not None:
|
|
1320
|
+
# Set the has_module_bays cache key on the parent device - see Device.has_module_bays()
|
|
1321
|
+
cache.set(f"nautobot.dcim.device.{self.parent_device.pk}.has_module_bays", True, timeout=5)
|
nautobot/dcim/models/devices.py
CHANGED
|
@@ -2,6 +2,7 @@ from collections import OrderedDict
|
|
|
2
2
|
|
|
3
3
|
from django.contrib.contenttypes.fields import GenericRelation
|
|
4
4
|
from django.contrib.contenttypes.models import ContentType
|
|
5
|
+
from django.core.cache import cache
|
|
5
6
|
from django.core.exceptions import ValidationError
|
|
6
7
|
from django.core.serializers.json import DjangoJSONEncoder
|
|
7
8
|
from django.core.validators import MaxValueValidator, MinValueValidator
|
|
@@ -896,6 +897,8 @@ class Device(PrimaryModel, ConfigContextModel):
|
|
|
896
897
|
instantiated_components = []
|
|
897
898
|
for model, templates in component_models:
|
|
898
899
|
model.objects.bulk_create([x.instantiate(device=self) for x in templates])
|
|
900
|
+
cache_key = f"nautobot.dcim.device.{self.pk}.has_module_bays"
|
|
901
|
+
cache.delete(cache_key)
|
|
899
902
|
return instantiated_components
|
|
900
903
|
|
|
901
904
|
create_components.alters_data = True
|
|
@@ -988,6 +991,18 @@ class Device(PrimaryModel, ConfigContextModel):
|
|
|
988
991
|
"""
|
|
989
992
|
return Device.objects.filter(parent_bay__device=self.pk)
|
|
990
993
|
|
|
994
|
+
@property
|
|
995
|
+
def has_module_bays(self) -> bool:
|
|
996
|
+
"""
|
|
997
|
+
Cacheable property for determining whether this Device has any ModuleBays, and therefore may contain Modules.
|
|
998
|
+
"""
|
|
999
|
+
cache_key = f"nautobot.dcim.device.{self.pk}.has_module_bays"
|
|
1000
|
+
module_bays_exists = cache.get(cache_key)
|
|
1001
|
+
if module_bays_exists is None:
|
|
1002
|
+
module_bays_exists = self.module_bays.exists()
|
|
1003
|
+
cache.set(cache_key, module_bays_exists, timeout=5)
|
|
1004
|
+
return module_bays_exists
|
|
1005
|
+
|
|
991
1006
|
@property
|
|
992
1007
|
def all_modules(self):
|
|
993
1008
|
"""
|
|
@@ -998,6 +1013,9 @@ class Device(PrimaryModel, ConfigContextModel):
|
|
|
998
1013
|
# We artificially limit the recursion to 4 levels or we would be stuck in an infinite loop.
|
|
999
1014
|
recursion_depth = MODULE_RECURSION_DEPTH_LIMIT
|
|
1000
1015
|
qs = Module.objects.all()
|
|
1016
|
+
if not self.has_module_bays:
|
|
1017
|
+
# Short-circuit to avoid an expensive nested query
|
|
1018
|
+
return qs.none()
|
|
1001
1019
|
query = Q()
|
|
1002
1020
|
for level in range(recursion_depth):
|
|
1003
1021
|
recursive_query = "parent_module_bay__parent_module__" * level
|
|
@@ -398,40 +398,7 @@
|
|
|
398
398
|
</div>
|
|
399
399
|
</div>
|
|
400
400
|
{% endif %}
|
|
401
|
-
{%
|
|
402
|
-
<div id="dynamic_groups" role="tabpanel" class="tab-pane {% if request.GET.tab == 'dynamic_groups' %}active{% else %}fade{% endif %}">
|
|
403
|
-
<div class="row">
|
|
404
|
-
<div class="col-md-12">
|
|
405
|
-
<div class="alert alert-warning">
|
|
406
|
-
Dynamic group membership is cached for performance reasons,
|
|
407
|
-
therefore this table may not always be up-to-date.
|
|
408
|
-
<br>You can refresh the membership of any specific group by navigating to it from the list below
|
|
409
|
-
or from the <a href="{% url 'extras:dynamicgroup_list' %}">Dynamic Groups list view</a>.
|
|
410
|
-
<br>You can also refresh the membership of all groups by running the
|
|
411
|
-
<a href="{% url 'extras:job_run_by_class_path' class_path='nautobot.core.jobs.groups.RefreshDynamicGroupCaches' %}">Refresh Dynamic Group Caches job</a>.
|
|
412
|
-
</div>
|
|
413
|
-
</div>
|
|
414
|
-
</div>
|
|
415
|
-
<div class="row">
|
|
416
|
-
<div class="col-md-12">
|
|
417
|
-
<form method="post">
|
|
418
|
-
{% csrf_token %}
|
|
419
|
-
<div class="panel panel-default">
|
|
420
|
-
<div class="panel-heading">
|
|
421
|
-
<strong>Dynamic Groups</strong>
|
|
422
|
-
<div class="pull-right noprint">
|
|
423
|
-
<!-- Insert table config button here -->
|
|
424
|
-
</div>
|
|
425
|
-
</div>
|
|
426
|
-
<div class="table-responsive">
|
|
427
|
-
{% render_table associated_dynamic_groups_table 'inc/table.html' %}
|
|
428
|
-
</div>
|
|
429
|
-
</div>
|
|
430
|
-
</form>
|
|
431
|
-
</div>
|
|
432
|
-
</div>
|
|
433
|
-
</div>
|
|
434
|
-
{% endif %}
|
|
401
|
+
{% comment %}The dynamic_groups tab is intentionally omitted here for performance reasons.{% endcomment %}
|
|
435
402
|
{% if object.is_metadata_associable_model and perms.extras.view_objectmetadata %}
|
|
436
403
|
<div id="object_metadata" role="tabpanel" class="tab-pane {% if request.GET.tab == 'object_metadata' %}active{% else %}fade{% endif %}">
|
|
437
404
|
<div class="row">
|