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
nautobot/dcim/views.py
CHANGED
|
@@ -58,7 +58,9 @@ from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
|
58
58
|
from nautobot.core.views.viewsets import NautobotUIViewSet
|
|
59
59
|
from nautobot.dcim.choices import LocationDataToContactActionChoices
|
|
60
60
|
from nautobot.dcim.forms import LocationMigrateDataToContactForm
|
|
61
|
+
from nautobot.dcim.utils import get_all_network_driver_mappings
|
|
61
62
|
from nautobot.extras.models import Contact, ContactAssociation, Role, Status, Team
|
|
63
|
+
from nautobot.extras.tables import DynamicGroupTable
|
|
62
64
|
from nautobot.extras.views import ObjectChangeLogView, ObjectConfigContextView, ObjectDynamicGroupsView
|
|
63
65
|
from nautobot.ipam.models import IPAddress, Prefix, Service, VLAN
|
|
64
66
|
from nautobot.ipam.tables import InterfaceIPAddressTable, InterfaceVLANTable, VRFDeviceAssignmentTable, VRFTable
|
|
@@ -523,11 +525,41 @@ class RackGroupUIViewSet(NautobotUIViewSet):
|
|
|
523
525
|
#
|
|
524
526
|
|
|
525
527
|
|
|
526
|
-
class
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
528
|
+
class RackUIViewSet(NautobotUIViewSet):
|
|
529
|
+
bulk_update_form_class = forms.RackBulkEditForm
|
|
530
|
+
filterset_class = filters.RackFilterSet
|
|
531
|
+
filterset_form_class = forms.RackFilterForm
|
|
532
|
+
form_class = forms.RackForm
|
|
533
|
+
serializer_class = serializers.RackSerializer
|
|
534
|
+
table_class = tables.RackDetailTable
|
|
535
|
+
queryset = Rack.objects.select_related("location", "tenant__tenant_group", "rack_group", "role")
|
|
536
|
+
|
|
537
|
+
def get_extra_context(self, request, instance):
|
|
538
|
+
context = super().get_extra_context(request, instance)
|
|
539
|
+
|
|
540
|
+
if self.action == "retrieve":
|
|
541
|
+
# Get 0U and child devices located within the rack
|
|
542
|
+
context["nonracked_devices"] = Device.objects.filter(rack=instance, position__isnull=True).select_related(
|
|
543
|
+
"device_type__manufacturer"
|
|
544
|
+
)
|
|
545
|
+
|
|
546
|
+
peer_racks = Rack.objects.restrict(request.user, "view").filter(location=instance.location)
|
|
547
|
+
|
|
548
|
+
if instance.rack_group:
|
|
549
|
+
peer_racks = peer_racks.filter(rack_group=instance.rack_group)
|
|
550
|
+
else:
|
|
551
|
+
peer_racks = peer_racks.filter(rack_group__isnull=True)
|
|
552
|
+
|
|
553
|
+
context["next_rack"] = peer_racks.filter(name__gt=instance.name).order_by("name").first()
|
|
554
|
+
context["prev_rack"] = peer_racks.filter(name__lt=instance.name).order_by("-name").first()
|
|
555
|
+
|
|
556
|
+
context["reservations"] = RackReservation.objects.restrict(request.user, "view").filter(rack=instance)
|
|
557
|
+
context["power_feeds"] = (
|
|
558
|
+
PowerFeed.objects.restrict(request.user, "view").filter(rack=instance).select_related("power_panel")
|
|
559
|
+
)
|
|
560
|
+
context["device_count"] = Device.objects.restrict(request.user, "view").filter(rack=instance).count()
|
|
561
|
+
|
|
562
|
+
return context
|
|
531
563
|
|
|
532
564
|
|
|
533
565
|
class RackElevationListView(generic.ObjectListView):
|
|
@@ -583,70 +615,6 @@ class RackElevationListView(generic.ObjectListView):
|
|
|
583
615
|
}
|
|
584
616
|
|
|
585
617
|
|
|
586
|
-
class RackView(generic.ObjectView):
|
|
587
|
-
queryset = Rack.objects.select_related("location", "tenant__tenant_group", "rack_group", "role")
|
|
588
|
-
|
|
589
|
-
def get_extra_context(self, request, instance):
|
|
590
|
-
# Get 0U and child devices located within the rack
|
|
591
|
-
nonracked_devices = Device.objects.filter(rack=instance, position__isnull=True).select_related(
|
|
592
|
-
"device_type__manufacturer"
|
|
593
|
-
)
|
|
594
|
-
|
|
595
|
-
peer_racks = Rack.objects.restrict(request.user, "view").filter(location=instance.location)
|
|
596
|
-
|
|
597
|
-
if instance.rack_group:
|
|
598
|
-
peer_racks = peer_racks.filter(rack_group=instance.rack_group)
|
|
599
|
-
else:
|
|
600
|
-
peer_racks = peer_racks.filter(rack_group__isnull=True)
|
|
601
|
-
next_rack = peer_racks.filter(name__gt=instance.name).order_by("name").first()
|
|
602
|
-
prev_rack = peer_racks.filter(name__lt=instance.name).order_by("-name").first()
|
|
603
|
-
|
|
604
|
-
reservations = RackReservation.objects.restrict(request.user, "view").filter(rack=instance)
|
|
605
|
-
power_feeds = (
|
|
606
|
-
PowerFeed.objects.restrict(request.user, "view").filter(rack=instance).select_related("power_panel")
|
|
607
|
-
)
|
|
608
|
-
|
|
609
|
-
device_count = Device.objects.restrict(request.user, "view").filter(rack=instance).count()
|
|
610
|
-
|
|
611
|
-
return {
|
|
612
|
-
"device_count": device_count,
|
|
613
|
-
"reservations": reservations,
|
|
614
|
-
"power_feeds": power_feeds,
|
|
615
|
-
"nonracked_devices": nonracked_devices,
|
|
616
|
-
"next_rack": next_rack,
|
|
617
|
-
"prev_rack": prev_rack,
|
|
618
|
-
**super().get_extra_context(request, instance),
|
|
619
|
-
}
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
class RackEditView(generic.ObjectEditView):
|
|
623
|
-
queryset = Rack.objects.all()
|
|
624
|
-
model_form = forms.RackForm
|
|
625
|
-
template_name = "dcim/rack_edit.html"
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
class RackDeleteView(generic.ObjectDeleteView):
|
|
629
|
-
queryset = Rack.objects.all()
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
class RackBulkImportView(generic.BulkImportView): # 3.0 TODO: remove, unused
|
|
633
|
-
queryset = Rack.objects.all()
|
|
634
|
-
table = tables.RackTable
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
class RackBulkEditView(generic.BulkEditView):
|
|
638
|
-
queryset = Rack.objects.all()
|
|
639
|
-
filterset = filters.RackFilterSet
|
|
640
|
-
table = tables.RackTable
|
|
641
|
-
form = forms.RackBulkEditForm
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
class RackBulkDeleteView(generic.BulkDeleteView):
|
|
645
|
-
queryset = Rack.objects.all()
|
|
646
|
-
filterset = filters.RackFilterSet
|
|
647
|
-
table = tables.RackTable
|
|
648
|
-
|
|
649
|
-
|
|
650
618
|
#
|
|
651
619
|
# Rack reservations
|
|
652
620
|
#
|
|
@@ -1665,6 +1633,8 @@ class PlatformUIViewSet(NautobotUIViewSet):
|
|
|
1665
1633
|
context = super().get_extra_context(request, instance)
|
|
1666
1634
|
if self.action == "retrieve":
|
|
1667
1635
|
context["network_driver_tool_names"] = instance.fetch_network_driver_mappings()
|
|
1636
|
+
if self.action in ["create", "update"]:
|
|
1637
|
+
context["network_driver_names"] = sorted(get_all_network_driver_mappings().keys())
|
|
1668
1638
|
return context
|
|
1669
1639
|
|
|
1670
1640
|
|
|
@@ -1701,7 +1671,39 @@ class DeviceView(generic.ObjectView):
|
|
|
1701
1671
|
"tenant__tenant_group",
|
|
1702
1672
|
).prefetch_related("images", "software_image_files")
|
|
1703
1673
|
|
|
1704
|
-
|
|
1674
|
+
class DeviceDetailContent(object_detail.ObjectDetailContent):
|
|
1675
|
+
"""
|
|
1676
|
+
Override base ObjectDetailContent to render dynamic-groups table as a separate view/tab instead of inline.
|
|
1677
|
+
"""
|
|
1678
|
+
|
|
1679
|
+
def __init__(self, **kwargs):
|
|
1680
|
+
super().__init__(**kwargs)
|
|
1681
|
+
# Remove inline tab definition
|
|
1682
|
+
for tab in list(self._tabs):
|
|
1683
|
+
if isinstance(tab, object_detail._ObjectDetailGroupsTab):
|
|
1684
|
+
self._tabs.remove(tab)
|
|
1685
|
+
# Add distinct-view tab definition
|
|
1686
|
+
self._tabs.append(
|
|
1687
|
+
object_detail.DistinctViewTab(
|
|
1688
|
+
weight=object_detail.Tab.WEIGHT_GROUPS_TAB,
|
|
1689
|
+
tab_id="dynamic_groups",
|
|
1690
|
+
label="Dynamic Groups",
|
|
1691
|
+
url_name="dcim:device_dynamicgroups",
|
|
1692
|
+
related_object_attribute="dynamic_groups",
|
|
1693
|
+
panels=(
|
|
1694
|
+
object_detail.ObjectsTablePanel(
|
|
1695
|
+
weight=100,
|
|
1696
|
+
table_class=DynamicGroupTable,
|
|
1697
|
+
table_attribute="dynamic_groups",
|
|
1698
|
+
exclude_columns=["content_type"],
|
|
1699
|
+
add_button_route=None,
|
|
1700
|
+
related_field_name="member_id",
|
|
1701
|
+
),
|
|
1702
|
+
),
|
|
1703
|
+
)
|
|
1704
|
+
)
|
|
1705
|
+
|
|
1706
|
+
object_detail_content = DeviceDetailContent(
|
|
1705
1707
|
extra_buttons=(
|
|
1706
1708
|
object_detail.DropdownButton(
|
|
1707
1709
|
weight=100,
|
|
@@ -2188,7 +2190,7 @@ class DeviceChangeLogView(ObjectChangeLogView):
|
|
|
2188
2190
|
base_template = "dcim/device/base.html"
|
|
2189
2191
|
|
|
2190
2192
|
|
|
2191
|
-
class DeviceDynamicGroupsView(ObjectDynamicGroupsView):
|
|
2193
|
+
class DeviceDynamicGroupsView(ObjectDynamicGroupsView):
|
|
2192
2194
|
base_template = "dcim/device/base.html"
|
|
2193
2195
|
|
|
2194
2196
|
|
nautobot/extras/choices.py
CHANGED
|
@@ -483,22 +483,30 @@ class SecretsGroupAccessTypeChoices(ChoiceSet):
|
|
|
483
483
|
|
|
484
484
|
|
|
485
485
|
class SecretsGroupSecretTypeChoices(ChoiceSet):
|
|
486
|
+
TYPE_AUTHKEY = "authentication-key"
|
|
487
|
+
TYPE_AUTHPROTOCOL = "authentication-protocol"
|
|
486
488
|
TYPE_KEY = "key"
|
|
489
|
+
TYPE_NOTES = "notes"
|
|
487
490
|
TYPE_PASSWORD = "password" # noqa: S105 # hardcoded-password-string -- false positive
|
|
491
|
+
TYPE_PRIVALGORITHM = "private-algorithm"
|
|
492
|
+
TYPE_PRIVKEY = "private-key"
|
|
488
493
|
TYPE_SECRET = "secret" # noqa: S105 # hardcoded-password-string -- false positive
|
|
489
494
|
TYPE_TOKEN = "token" # noqa: S105 # hardcoded-password-string -- false positive
|
|
490
|
-
TYPE_USERNAME = "username"
|
|
491
495
|
TYPE_URL = "url"
|
|
492
|
-
|
|
496
|
+
TYPE_USERNAME = "username"
|
|
493
497
|
|
|
494
498
|
CHOICES = (
|
|
499
|
+
(TYPE_AUTHKEY, "Authentication Key"),
|
|
500
|
+
(TYPE_AUTHPROTOCOL, "Authentication Protocol"),
|
|
495
501
|
(TYPE_KEY, "Key"),
|
|
502
|
+
(TYPE_NOTES, "Notes"),
|
|
496
503
|
(TYPE_PASSWORD, "Password"),
|
|
504
|
+
(TYPE_PRIVALGORITHM, "Private Algorithm"),
|
|
505
|
+
(TYPE_PRIVKEY, "Private Key"),
|
|
497
506
|
(TYPE_SECRET, "Secret"),
|
|
498
507
|
(TYPE_TOKEN, "Token"),
|
|
499
|
-
(TYPE_USERNAME, "Username"),
|
|
500
508
|
(TYPE_URL, "URL"),
|
|
501
|
-
(
|
|
509
|
+
(TYPE_USERNAME, "Username"),
|
|
502
510
|
)
|
|
503
511
|
|
|
504
512
|
|
|
@@ -74,7 +74,9 @@ class CustomFieldModelFilterSetMixin(django_filters.FilterSet):
|
|
|
74
74
|
CustomFieldTypeChoices.TYPE_SELECT: CustomFieldSelectFilter,
|
|
75
75
|
}
|
|
76
76
|
|
|
77
|
-
custom_fields = CustomField.objects.get_for_model(
|
|
77
|
+
custom_fields = CustomField.objects.get_for_model(
|
|
78
|
+
self._meta.model, exclude_filter_disabled=True, get_queryset=False
|
|
79
|
+
)
|
|
78
80
|
for cf in custom_fields:
|
|
79
81
|
# Determine filter class for this CustomField type, default to CustomFieldCharFilter
|
|
80
82
|
new_filter_name = cf.add_prefix_to_cf_key()
|
|
@@ -220,13 +222,13 @@ class RelationshipModelFilterSetMixin(django_filters.FilterSet):
|
|
|
220
222
|
"""
|
|
221
223
|
Append form fields for all Relationships assigned to this model.
|
|
222
224
|
"""
|
|
223
|
-
src_relationships, dst_relationships = Relationship.objects.get_for_model(
|
|
225
|
+
src_relationships, dst_relationships = Relationship.objects.get_for_model(
|
|
226
|
+
model=model, hidden=False, get_queryset=False
|
|
227
|
+
)
|
|
224
228
|
|
|
225
|
-
|
|
226
|
-
self._append_relationships_side([rel], RelationshipSideChoices.SIDE_SOURCE, model)
|
|
229
|
+
self._append_relationships_side(src_relationships, RelationshipSideChoices.SIDE_SOURCE, model)
|
|
227
230
|
|
|
228
|
-
|
|
229
|
-
self._append_relationships_side([rel], RelationshipSideChoices.SIDE_DESTINATION, model)
|
|
231
|
+
self._append_relationships_side(dst_relationships, RelationshipSideChoices.SIDE_DESTINATION, model)
|
|
230
232
|
|
|
231
233
|
def _append_relationships_side(self, relationships, initial_side, model):
|
|
232
234
|
"""
|
nautobot/extras/forms/forms.py
CHANGED
|
@@ -197,6 +197,7 @@ __all__ = (
|
|
|
197
197
|
"SecretFilterForm",
|
|
198
198
|
"SecretForm",
|
|
199
199
|
"SecretsGroupAssociationFormSet",
|
|
200
|
+
"SecretsGroupBulkEditForm",
|
|
200
201
|
"SecretsGroupFilterForm",
|
|
201
202
|
"SecretsGroupForm",
|
|
202
203
|
"StaticGroupAssociationFilterForm",
|
|
@@ -2082,6 +2083,14 @@ class RoleFilterForm(NautobotFilterForm):
|
|
|
2082
2083
|
#
|
|
2083
2084
|
|
|
2084
2085
|
|
|
2086
|
+
class SecretsGroupBulkEditForm(NautobotBulkEditForm):
|
|
2087
|
+
pk = forms.ModelMultipleChoiceField(queryset=SecretsGroup.objects.all(), widget=forms.MultipleHiddenInput())
|
|
2088
|
+
description = forms.CharField(max_length=CHARFIELD_MAX_LENGTH, required=False)
|
|
2089
|
+
|
|
2090
|
+
class Meta:
|
|
2091
|
+
model = SecretsGroup
|
|
2092
|
+
|
|
2093
|
+
|
|
2085
2094
|
def provider_choices():
|
|
2086
2095
|
return sorted([(slug, provider.name) for slug, provider in registry["secrets_providers"].items()])
|
|
2087
2096
|
|
nautobot/extras/forms/mixins.py
CHANGED
|
@@ -95,7 +95,7 @@ class CustomFieldModelFilterFormMixin(forms.Form):
|
|
|
95
95
|
def __init__(self, *args, **kwargs):
|
|
96
96
|
super().__init__(*args, **kwargs)
|
|
97
97
|
|
|
98
|
-
custom_fields = CustomField.objects.get_for_model(self.model, exclude_filter_disabled=True)
|
|
98
|
+
custom_fields = CustomField.objects.get_for_model(self.model, exclude_filter_disabled=True, get_queryset=False)
|
|
99
99
|
self.custom_fields = []
|
|
100
100
|
for cf in custom_fields:
|
|
101
101
|
field_name = cf.add_prefix_to_cf_key()
|
|
@@ -714,7 +714,9 @@ class RelationshipModelFilterFormMixin(forms.Form):
|
|
|
714
714
|
"""
|
|
715
715
|
Append form fields for all Relationships assigned to this model.
|
|
716
716
|
"""
|
|
717
|
-
src_relationships, dst_relationships = Relationship.objects.get_for_model(
|
|
717
|
+
src_relationships, dst_relationships = Relationship.objects.get_for_model(
|
|
718
|
+
model=self.model, hidden=False, get_queryset=False
|
|
719
|
+
)
|
|
718
720
|
|
|
719
721
|
for rel in src_relationships:
|
|
720
722
|
self._append_relationships_side([rel], RelationshipSideChoices.SIDE_SOURCE)
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
# Generated by Django 3.2.16 on 2022-11-19 23:15
|
|
2
2
|
|
|
3
3
|
from collections import namedtuple
|
|
4
|
-
import logging
|
|
5
4
|
|
|
6
5
|
from django.db import migrations, models
|
|
7
6
|
|
|
@@ -24,8 +23,6 @@ color_map = {
|
|
|
24
23
|
"success": ColorChoices.COLOR_GREEN,
|
|
25
24
|
}
|
|
26
25
|
|
|
27
|
-
logger = logging.getLogger(__name__)
|
|
28
|
-
|
|
29
26
|
|
|
30
27
|
def create_equivalent_roles_of_virtualmachine_device_role(apps):
|
|
31
28
|
"""Create equivalent roles for the VirtualMachine DeviceRole."""
|
|
@@ -82,17 +79,43 @@ def create_roles(apps, roles_to_create, content_types):
|
|
|
82
79
|
"description": old_role.description,
|
|
83
80
|
"color": getattr(old_role, "color", color_map["default"]),
|
|
84
81
|
"weight": getattr(old_role, "weight", None),
|
|
82
|
+
"_custom_field_data": getattr(old_role, "_custom_field_data", {}),
|
|
85
83
|
},
|
|
86
84
|
)
|
|
87
85
|
if created:
|
|
88
|
-
|
|
86
|
+
print(f" Created Role {new_role.name!r}")
|
|
87
|
+
else:
|
|
88
|
+
updated = False
|
|
89
|
+
# Fix up in the case of overlapping roles
|
|
90
|
+
if new_role.weight is None and hasattr(old_role, "weight"):
|
|
91
|
+
new_role.weight = old_role.weight
|
|
92
|
+
updated = True
|
|
93
|
+
if old_role.description and not new_role.description:
|
|
94
|
+
new_role.description = old_role.description
|
|
95
|
+
updated = True
|
|
96
|
+
if hasattr(old_role, "_custom_field_data"):
|
|
97
|
+
for field, value in old_role._custom_field_data.items():
|
|
98
|
+
if field in new_role._custom_field_data:
|
|
99
|
+
if new_role._custom_field_data[field] != value:
|
|
100
|
+
print(
|
|
101
|
+
f" Value conflict for custom field {field!r} for role {new_role.name!r} - DATA LOSS"
|
|
102
|
+
)
|
|
103
|
+
else:
|
|
104
|
+
new_role._custom_field_data[field] = value
|
|
105
|
+
updated = True
|
|
106
|
+
if updated:
|
|
107
|
+
print(f" Updated Role {new_role.name!r}")
|
|
108
|
+
new_role.save()
|
|
109
|
+
else:
|
|
110
|
+
print(f" No changes to already-created Role {new_role.name!r}")
|
|
111
|
+
|
|
89
112
|
if old_role_ct and hasattr(old_role, "pk"):
|
|
90
113
|
# Move over existing object change records to the new role we created
|
|
91
114
|
updated_count = ObjectChange.objects.filter(
|
|
92
115
|
changed_object_type=old_role_ct, changed_object_id=old_role.pk
|
|
93
116
|
).update(changed_object_type=new_role_ct, changed_object_id=new_role.pk)
|
|
94
|
-
|
|
95
|
-
f
|
|
117
|
+
print(
|
|
118
|
+
f" Updated {updated_count} ObjectChanges from the existing {old_role.name!r} {old_role._meta.label}"
|
|
96
119
|
)
|
|
97
120
|
|
|
98
121
|
# This is for all of the change records for roles which no longer exist
|
|
@@ -100,7 +123,7 @@ def create_roles(apps, roles_to_create, content_types):
|
|
|
100
123
|
updated_count = ObjectChange.objects.filter(changed_object_type=old_role_ct).update(
|
|
101
124
|
changed_object_type=new_role_ct
|
|
102
125
|
)
|
|
103
|
-
|
|
126
|
+
print(f" Updated {updated_count} leftover ObjectChanges from deleted {old_role_ct.model} records.")
|
|
104
127
|
|
|
105
128
|
roles = Role.objects.filter(name__in=[roles.name for roles in roles_to_create])
|
|
106
129
|
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Generated by Django 4.2.23 on 2025-07-31 23:49
|
|
2
|
+
|
|
3
|
+
from django.db import migrations, models
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("extras", "0123_alter_joblogentry_created"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AddIndex(
|
|
13
|
+
model_name="joblogentry",
|
|
14
|
+
index=models.Index(fields=["job_result", "created"], name="extras_joblog_jr_created_idx"),
|
|
15
|
+
),
|
|
16
|
+
]
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
from collections import OrderedDict
|
|
1
|
+
from collections import defaultdict, OrderedDict
|
|
2
2
|
from datetime import date, datetime
|
|
3
3
|
import json
|
|
4
4
|
import logging
|
|
@@ -48,21 +48,42 @@ logger = logging.getLogger(__name__)
|
|
|
48
48
|
class ComputedFieldManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
49
49
|
use_in_migrations = True
|
|
50
50
|
|
|
51
|
-
def get_for_model(self, model):
|
|
51
|
+
def get_for_model(self, model, get_queryset=True):
|
|
52
52
|
"""
|
|
53
53
|
Return all ComputedFields assigned to the given model.
|
|
54
|
+
|
|
55
|
+
Returns a queryset by default, or a list if `get_queryset` param is False.
|
|
54
56
|
"""
|
|
55
57
|
concrete_model = model._meta.concrete_model
|
|
56
58
|
cache_key = f"{self.get_for_model.cache_key_prefix}.{concrete_model._meta.label_lower}"
|
|
59
|
+
list_cache_key = f"{cache_key}.list"
|
|
60
|
+
if not get_queryset:
|
|
61
|
+
listing = cache.get(list_cache_key)
|
|
62
|
+
if listing is not None:
|
|
63
|
+
return listing
|
|
57
64
|
queryset = cache.get(cache_key)
|
|
58
65
|
if queryset is None:
|
|
59
66
|
content_type = ContentType.objects.get_for_model(concrete_model)
|
|
60
67
|
queryset = self.get_queryset().filter(content_type=content_type)
|
|
61
68
|
cache.set(cache_key, queryset)
|
|
69
|
+
if not get_queryset:
|
|
70
|
+
listing = list(queryset)
|
|
71
|
+
cache.set(list_cache_key, listing)
|
|
72
|
+
return listing
|
|
62
73
|
return queryset
|
|
63
74
|
|
|
64
75
|
get_for_model.cache_key_prefix = "nautobot.extras.computedfield.get_for_model"
|
|
65
76
|
|
|
77
|
+
def populate_list_caches(self):
|
|
78
|
+
"""Populate all caches for `get_for_model(..., get_queryset=False)` lookups."""
|
|
79
|
+
queryset = self.all().select_related("content_type")
|
|
80
|
+
listings = defaultdict(list)
|
|
81
|
+
for cf in queryset:
|
|
82
|
+
listings[f"{cf.content_type.app_label}.{cf.content_type.model}"].append(cf)
|
|
83
|
+
for ct in ContentType.objects.all():
|
|
84
|
+
label = f"{ct.app_label}.{ct.model}"
|
|
85
|
+
cache.set(f"{self.get_for_model.cache_key_prefix}.{label}.list", listings[label])
|
|
86
|
+
|
|
66
87
|
|
|
67
88
|
@extras_features("graphql")
|
|
68
89
|
class ComputedField(
|
|
@@ -370,18 +391,24 @@ class CustomFieldModel(models.Model):
|
|
|
370
391
|
class CustomFieldManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
371
392
|
use_in_migrations = True
|
|
372
393
|
|
|
373
|
-
def get_for_model(self, model, exclude_filter_disabled=False):
|
|
394
|
+
def get_for_model(self, model, exclude_filter_disabled=False, get_queryset=True):
|
|
374
395
|
"""
|
|
375
396
|
Return (and cache) all CustomFields assigned to the given model.
|
|
376
397
|
|
|
377
398
|
Args:
|
|
378
399
|
model (Model): The django model to which custom fields are registered
|
|
379
400
|
exclude_filter_disabled (bool): Exclude any custom fields which have filter logic disabled
|
|
401
|
+
get_queryset (bool): Whether to return a QuerySet or a list.
|
|
380
402
|
"""
|
|
381
403
|
concrete_model = model._meta.concrete_model
|
|
382
404
|
cache_key = (
|
|
383
405
|
f"{self.get_for_model.cache_key_prefix}.{concrete_model._meta.label_lower}.{exclude_filter_disabled}"
|
|
384
406
|
)
|
|
407
|
+
list_cache_key = f"{cache_key}.list"
|
|
408
|
+
if not get_queryset:
|
|
409
|
+
listing = cache.get(list_cache_key)
|
|
410
|
+
if listing is not None:
|
|
411
|
+
return listing
|
|
385
412
|
queryset = cache.get(cache_key)
|
|
386
413
|
if queryset is None:
|
|
387
414
|
content_type = ContentType.objects.get_for_model(concrete_model)
|
|
@@ -389,6 +416,10 @@ class CustomFieldManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
|
389
416
|
if exclude_filter_disabled:
|
|
390
417
|
queryset = queryset.exclude(filter_logic=CustomFieldFilterLogicChoices.FILTER_DISABLED)
|
|
391
418
|
cache.set(cache_key, queryset)
|
|
419
|
+
if not get_queryset:
|
|
420
|
+
listing = list(queryset)
|
|
421
|
+
cache.set(list_cache_key, listing)
|
|
422
|
+
return listing
|
|
392
423
|
return queryset
|
|
393
424
|
|
|
394
425
|
get_for_model.cache_key_prefix = "nautobot.extras.customfield.get_for_model"
|
|
@@ -405,6 +436,24 @@ class CustomFieldManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
|
405
436
|
|
|
406
437
|
keys_for_model.cache_key_prefix = "nautobot.extras.customfield.keys_for_model"
|
|
407
438
|
|
|
439
|
+
def populate_list_caches(self):
|
|
440
|
+
"""Populate all caches for `get_for_model(..., get_queryset=False)` and `keys_for_model` lookups."""
|
|
441
|
+
queryset = self.all().prefetch_related("content_types")
|
|
442
|
+
cf_listings = defaultdict(lambda: defaultdict(list))
|
|
443
|
+
key_listings = defaultdict(list)
|
|
444
|
+
for cf in queryset:
|
|
445
|
+
for ct in cf.content_types.all():
|
|
446
|
+
label = f"{ct.app_label}.{ct.model}"
|
|
447
|
+
cf_listings[label][False].append(cf)
|
|
448
|
+
if cf.filter_logic != CustomFieldFilterLogicChoices.FILTER_DISABLED:
|
|
449
|
+
cf_listings[label][True].append(cf)
|
|
450
|
+
key_listings[label].append(cf.key)
|
|
451
|
+
for ct in ContentType.objects.all():
|
|
452
|
+
label = f"{ct.app_label}.{ct.model}"
|
|
453
|
+
cache.set(f"{self.get_for_model.cache_key_prefix}.{label}.True.list", cf_listings[label][True])
|
|
454
|
+
cache.set(f"{self.get_for_model.cache_key_prefix}.{label}.False.list", cf_listings[label][False])
|
|
455
|
+
cache.set(f"{self.keys_for_model.cache_key_prefix}.{label}", key_listings[label])
|
|
456
|
+
|
|
408
457
|
|
|
409
458
|
@extras_features("webhooks")
|
|
410
459
|
class CustomField(
|
nautobot/extras/models/jobs.py
CHANGED
|
@@ -543,6 +543,12 @@ class JobLogEntry(BaseModel):
|
|
|
543
543
|
ordering = ["created"]
|
|
544
544
|
get_latest_by = "created"
|
|
545
545
|
verbose_name_plural = "job log entries"
|
|
546
|
+
indexes = [
|
|
547
|
+
models.Index(
|
|
548
|
+
name="extras_joblog_jr_created_idx",
|
|
549
|
+
fields=["job_result", "created"],
|
|
550
|
+
)
|
|
551
|
+
]
|
|
546
552
|
|
|
547
553
|
|
|
548
554
|
#
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from collections import defaultdict
|
|
1
2
|
import logging
|
|
2
3
|
|
|
3
4
|
from django import forms
|
|
@@ -422,31 +423,38 @@ class RelationshipModel(models.Model):
|
|
|
422
423
|
class RelationshipManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
423
424
|
use_in_migrations = True
|
|
424
425
|
|
|
425
|
-
def get_for_model(self, model, hidden=None):
|
|
426
|
+
def get_for_model(self, model, hidden=None, get_queryset=True):
|
|
426
427
|
"""
|
|
427
428
|
Return all Relationships assigned to the given model.
|
|
428
429
|
|
|
429
430
|
Args:
|
|
430
431
|
model (Model): The django model to which relationships are registered
|
|
431
432
|
hidden (bool): Filter based on the value of the hidden flag, or None to not apply this filter
|
|
433
|
+
get_queryset (bool): Whether to return querysets or object lists.
|
|
432
434
|
|
|
433
|
-
Returns a tuple of source and destination scoped relationship querysets.
|
|
435
|
+
Returns a tuple of source and destination scoped relationship record querysets/lists.
|
|
434
436
|
"""
|
|
435
437
|
return (
|
|
436
|
-
self.get_for_model_source(model, hidden=hidden),
|
|
437
|
-
self.get_for_model_destination(model, hidden=hidden),
|
|
438
|
+
self.get_for_model_source(model, hidden=hidden, get_queryset=get_queryset),
|
|
439
|
+
self.get_for_model_destination(model, hidden=hidden, get_queryset=get_queryset),
|
|
438
440
|
)
|
|
439
441
|
|
|
440
|
-
def get_for_model_source(self, model, hidden=None):
|
|
442
|
+
def get_for_model_source(self, model, hidden=None, get_queryset=True):
|
|
441
443
|
"""
|
|
442
444
|
Return all Relationships assigned to the given model for the source side only.
|
|
443
445
|
|
|
444
446
|
Args:
|
|
445
447
|
model (Model): The django model to which relationships are registered
|
|
446
448
|
hidden (bool): Filter based on the value of the hidden flag, or None to not apply this filter
|
|
449
|
+
get_queryset (bool): Whether to return a queryset or an object list.
|
|
447
450
|
"""
|
|
448
451
|
concrete_model = model._meta.concrete_model
|
|
449
452
|
cache_key = f"{self.get_for_model_source.cache_key_prefix}.{concrete_model._meta.label_lower}.{hidden}"
|
|
453
|
+
list_cache_key = f"{cache_key}.list"
|
|
454
|
+
if not get_queryset:
|
|
455
|
+
listing = cache.get(list_cache_key)
|
|
456
|
+
if listing is not None:
|
|
457
|
+
return listing
|
|
450
458
|
queryset = cache.get(cache_key)
|
|
451
459
|
if queryset is None:
|
|
452
460
|
content_type = ContentType.objects.get_for_model(concrete_model)
|
|
@@ -456,20 +464,30 @@ class RelationshipManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
|
456
464
|
if hidden is not None:
|
|
457
465
|
queryset = queryset.filter(source_hidden=hidden)
|
|
458
466
|
cache.set(cache_key, queryset)
|
|
467
|
+
if not get_queryset:
|
|
468
|
+
listing = list(queryset)
|
|
469
|
+
cache.set(list_cache_key, listing)
|
|
470
|
+
return listing
|
|
459
471
|
return queryset
|
|
460
472
|
|
|
461
473
|
get_for_model_source.cache_key_prefix = "nautobot.extras.relationship.get_for_model_source"
|
|
462
474
|
|
|
463
|
-
def get_for_model_destination(self, model, hidden=None):
|
|
475
|
+
def get_for_model_destination(self, model, hidden=None, get_queryset=True):
|
|
464
476
|
"""
|
|
465
477
|
Return all Relationships assigned to the given model for the destination side only.
|
|
466
478
|
|
|
467
479
|
Args:
|
|
468
480
|
model (Model): The django model to which relationships are registered
|
|
469
481
|
hidden (bool): Filter based on the value of the hidden flag, or None to not apply this filter
|
|
482
|
+
get_queryset (bool): Whether to return a queryset or an object list.
|
|
470
483
|
"""
|
|
471
484
|
concrete_model = model._meta.concrete_model
|
|
472
485
|
cache_key = f"{self.get_for_model_destination.cache_key_prefix}.{concrete_model._meta.label_lower}.{hidden}"
|
|
486
|
+
list_cache_key = f"{cache_key}.list"
|
|
487
|
+
if not get_queryset:
|
|
488
|
+
listing = cache.get(list_cache_key)
|
|
489
|
+
if listing is not None:
|
|
490
|
+
return listing
|
|
473
491
|
queryset = cache.get(cache_key)
|
|
474
492
|
if queryset is None:
|
|
475
493
|
content_type = ContentType.objects.get_for_model(concrete_model)
|
|
@@ -481,6 +499,10 @@ class RelationshipManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
|
481
499
|
if hidden is not None:
|
|
482
500
|
queryset = queryset.filter(destination_hidden=hidden)
|
|
483
501
|
cache.set(cache_key, queryset)
|
|
502
|
+
if not get_queryset:
|
|
503
|
+
listing = list(queryset)
|
|
504
|
+
cache.set(list_cache_key, listing)
|
|
505
|
+
return listing
|
|
484
506
|
return queryset
|
|
485
507
|
|
|
486
508
|
get_for_model_destination.cache_key_prefix = "nautobot.extras.relationship.get_for_model_destination"
|
|
@@ -495,6 +517,33 @@ class RelationshipManager(BaseManager.from_queryset(RestrictedQuerySet)):
|
|
|
495
517
|
| Q(destination_type=content_type, required_on=RelationshipRequiredSideChoices.DESTINATION_SIDE_REQUIRED)
|
|
496
518
|
)
|
|
497
519
|
|
|
520
|
+
def populate_list_caches(self):
|
|
521
|
+
"""Populate all relevant caches for `get_for_model(..., get_queryset=False)` and related lookups."""
|
|
522
|
+
queryset = self.all().select_related("source_type", "destination_type")
|
|
523
|
+
listings = defaultdict(lambda: defaultdict(lambda: defaultdict(list)))
|
|
524
|
+
for rel in queryset:
|
|
525
|
+
listings["source"][f"{rel.source_type.app_label}.{rel.source_type.model}"]["None"].append(rel)
|
|
526
|
+
listings["source"][f"{rel.source_type.app_label}.{rel.source_type.model}"][str(rel.source_hidden)].append(
|
|
527
|
+
rel
|
|
528
|
+
)
|
|
529
|
+
listings["destination"][f"{rel.destination_type.app_label}.{rel.destination_type.model}"]["None"].append(
|
|
530
|
+
rel
|
|
531
|
+
)
|
|
532
|
+
listings["destination"][f"{rel.destination_type.app_label}.{rel.destination_type.model}"][
|
|
533
|
+
str(rel.destination_hidden)
|
|
534
|
+
].append(rel)
|
|
535
|
+
for ct in ContentType.objects.all():
|
|
536
|
+
label = f"{ct.app_label}.{ct.model}"
|
|
537
|
+
for hidden in ["None", "True", "False"]:
|
|
538
|
+
cache.set(
|
|
539
|
+
f"{self.get_for_model_source.cache_key_prefix}.{label}.{hidden}.list",
|
|
540
|
+
listings["source"][label][hidden],
|
|
541
|
+
)
|
|
542
|
+
cache.set(
|
|
543
|
+
f"{self.get_for_model_destination.cache_key_prefix}.{label}.{hidden}.list",
|
|
544
|
+
listings["destination"][label][hidden],
|
|
545
|
+
)
|
|
546
|
+
|
|
498
547
|
|
|
499
548
|
class Relationship(
|
|
500
549
|
ChangeLoggedModel,
|