nautobot 2.4.0__py3-none-any.whl → 2.4.0b1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/__init__.py +1 -1
- nautobot/apps/api.py +8 -8
- nautobot/apps/change_logging.py +2 -2
- nautobot/apps/choices.py +4 -4
- nautobot/apps/events.py +3 -3
- nautobot/apps/factory.py +2 -2
- nautobot/apps/filters.py +1 -1
- nautobot/apps/forms.py +20 -20
- nautobot/apps/graphql.py +2 -2
- nautobot/apps/jobs.py +8 -8
- nautobot/apps/models.py +19 -19
- nautobot/apps/tables.py +1 -1
- nautobot/apps/testing.py +10 -10
- nautobot/apps/ui.py +2 -2
- nautobot/apps/utils.py +7 -7
- nautobot/apps/views.py +7 -7
- nautobot/circuits/api/serializers.py +0 -1
- nautobot/circuits/api/views.py +8 -4
- nautobot/circuits/tables.py +1 -2
- nautobot/circuits/templates/circuits/circuit_create.html +7 -1
- nautobot/circuits/views.py +3 -3
- nautobot/cloud/api/views.py +10 -6
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/views.py +16 -0
- nautobot/core/api/fields.py +5 -5
- nautobot/core/api/filter_backends.py +9 -3
- nautobot/core/api/schema.py +2 -13
- nautobot/core/api/serializers.py +34 -40
- nautobot/core/api/views.py +4 -56
- nautobot/core/celery/log.py +4 -4
- nautobot/core/celery/schedulers.py +1 -1
- nautobot/core/choices.py +2 -2
- nautobot/core/events/__init__.py +3 -3
- nautobot/core/filters.py +16 -21
- nautobot/core/fixtures/user-data.json +59 -0
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +11 -14
- nautobot/core/forms/forms.py +2 -33
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +7 -28
- nautobot/core/jobs/cleanup.py +12 -48
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/models/__init__.py +1 -1
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +3 -6
- nautobot/core/settings.py +2 -29
- nautobot/core/settings.yaml +0 -21
- nautobot/core/tables.py +60 -74
- nautobot/core/templates/inc/media.html +0 -3
- nautobot/core/templates/inc/nav_menu.html +0 -1
- nautobot/core/templates/nautobot_config.py.j2 +0 -13
- nautobot/core/templates/search.html +0 -7
- nautobot/core/templates/utilities/render_jinja2.html +1 -1
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +0 -7
- nautobot/core/templatetags/helpers.py +2 -11
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +15 -170
- nautobot/core/testing/filters.py +2 -25
- nautobot/core/testing/forms.py +0 -2
- nautobot/core/testing/mixins.py +2 -7
- nautobot/core/testing/views.py +29 -44
- nautobot/core/tests/integration/test_app_home.py +1 -0
- nautobot/core/tests/integration/test_app_navbar.py +1 -0
- nautobot/core/tests/integration/test_filters.py +2 -0
- nautobot/core/tests/integration/test_home.py +1 -0
- nautobot/core/tests/integration/test_navbar.py +1 -0
- nautobot/core/tests/integration/test_view_authentication.py +0 -1
- nautobot/core/tests/runner.py +1 -1
- nautobot/core/tests/test_api.py +1 -98
- nautobot/core/tests/test_csv.py +3 -25
- nautobot/core/tests/test_forms.py +0 -1
- nautobot/core/tests/test_jobs.py +1 -303
- nautobot/core/tests/test_settings_schema.py +0 -7
- nautobot/core/tests/test_tables.py +0 -100
- nautobot/core/tests/test_utils.py +1 -63
- nautobot/core/tests/test_views.py +3 -30
- nautobot/core/ui/nav.py +0 -1
- nautobot/core/ui/object_detail.py +1 -15
- nautobot/core/urls.py +0 -11
- nautobot/core/utils/lookup.py +8 -11
- nautobot/core/utils/requests.py +9 -24
- nautobot/core/views/__init__.py +0 -42
- nautobot/core/views/generic.py +176 -78
- nautobot/core/views/mixins.py +34 -94
- nautobot/core/views/renderers.py +6 -6
- nautobot/dcim/api/serializers.py +62 -54
- nautobot/dcim/api/views.py +113 -47
- nautobot/dcim/filters/__init__.py +2 -31
- nautobot/dcim/forms.py +17 -36
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/models/__init__.py +1 -1
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +20 -22
- nautobot/dcim/models/devices.py +1 -10
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +5 -6
- nautobot/dcim/models/racks.py +4 -4
- nautobot/dcim/tables/__init__.py +3 -3
- nautobot/dcim/tables/devices.py +5 -7
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +7 -1
- nautobot/dcim/templates/dcim/controller_retrieve.html +9 -1
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +0 -2
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +0 -5
- nautobot/dcim/templates/dcim/device.html +9 -1
- nautobot/dcim/templates/dcim/device_edit.html +37 -36
- nautobot/dcim/templates/dcim/location.html +9 -1
- nautobot/dcim/templates/dcim/location_edit.html +7 -1
- nautobot/dcim/templates/dcim/rack.html +9 -1
- nautobot/dcim/templates/dcim/rack_edit.html +7 -1
- nautobot/dcim/templates/dcim/rackreservation.html +9 -1
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +9 -1
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +7 -1
- nautobot/dcim/tests/test_api.py +3 -16
- nautobot/dcim/tests/test_filters.py +0 -33
- nautobot/dcim/tests/test_forms.py +2 -51
- nautobot/dcim/tests/test_graphql.py +0 -52
- nautobot/dcim/tests/test_models.py +5 -34
- nautobot/dcim/tests/test_views.py +83 -21
- nautobot/dcim/views.py +13 -1
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +85 -90
- nautobot/extras/api/views.py +27 -22
- nautobot/extras/constants.py +0 -2
- nautobot/extras/filters/__init__.py +6 -8
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +31 -139
- nautobot/extras/forms/mixins.py +5 -13
- nautobot/extras/group_sync.py +3 -3
- nautobot/extras/health_checks.py +2 -1
- nautobot/extras/jobs.py +12 -70
- nautobot/extras/managers.py +1 -3
- nautobot/extras/migrations/0018_joblog_data_migration.py +9 -7
- nautobot/extras/models/__init__.py +1 -1
- nautobot/extras/models/contacts.py +1 -1
- nautobot/extras/models/customfields.py +11 -12
- nautobot/extras/models/groups.py +9 -11
- nautobot/extras/models/jobs.py +4 -23
- nautobot/extras/models/models.py +2 -2
- nautobot/extras/plugins/__init__.py +2 -13
- nautobot/extras/plugins/marketplace_manifest.yml +79 -84
- nautobot/extras/plugins/tables.py +14 -16
- nautobot/extras/plugins/views.py +69 -65
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/tables.py +5 -7
- nautobot/extras/templates/extras/dynamicgroup.html +9 -1
- nautobot/extras/templates/extras/job_detail.html +0 -16
- nautobot/extras/templates/extras/job_edit.html +0 -1
- nautobot/extras/templates/extras/jobqueue_retrieve.html +9 -1
- nautobot/extras/templates/extras/marketplace.html +11 -29
- nautobot/extras/templates/extras/plugin_detail.html +15 -32
- nautobot/extras/templates/extras/plugins_tiles.html +10 -21
- nautobot/extras/test_jobs/api_test_job.py +1 -1
- nautobot/extras/test_jobs/atomic_transaction.py +2 -2
- nautobot/extras/test_jobs/dry_run.py +1 -1
- nautobot/extras/test_jobs/fail.py +5 -5
- nautobot/extras/test_jobs/file_output.py +1 -1
- nautobot/extras/test_jobs/file_upload_fail.py +1 -1
- nautobot/extras/test_jobs/file_upload_pass.py +1 -1
- nautobot/extras/test_jobs/ipaddress_vars.py +1 -3
- nautobot/extras/test_jobs/jobs_module/jobs_submodule/jobs.py +1 -1
- nautobot/extras/test_jobs/location_with_custom_field.py +1 -1
- nautobot/extras/test_jobs/log_redaction.py +1 -1
- nautobot/extras/test_jobs/log_skip_db_logging.py +1 -1
- nautobot/extras/test_jobs/modify_db.py +1 -1
- nautobot/extras/test_jobs/object_var_optional.py +1 -1
- nautobot/extras/test_jobs/object_var_required.py +1 -1
- nautobot/extras/test_jobs/object_vars.py +1 -1
- nautobot/extras/test_jobs/pass.py +3 -3
- nautobot/extras/test_jobs/profiling.py +1 -1
- nautobot/extras/test_jobs/relative_import.py +3 -3
- nautobot/extras/test_jobs/soft_time_limit_greater_than_time_limit.py +1 -1
- nautobot/extras/test_jobs/task_queues.py +1 -1
- nautobot/extras/tests/integration/test_plugin_banner.py +2 -0
- nautobot/extras/tests/test_api.py +13 -13
- nautobot/extras/tests/test_customfields.py +1 -1
- nautobot/extras/tests/test_datasources.py +1 -2
- nautobot/extras/tests/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/test_filters.py +6 -6
- nautobot/extras/tests/test_forms.py +1 -20
- nautobot/extras/tests/test_jobs.py +19 -160
- nautobot/extras/tests/test_models.py +10 -10
- nautobot/extras/tests/test_plugins.py +9 -62
- nautobot/extras/tests/test_relationships.py +9 -120
- nautobot/extras/tests/test_views.py +191 -52
- nautobot/extras/utils.py +2 -3
- nautobot/extras/views.py +98 -30
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +33 -41
- nautobot/ipam/api/views.py +117 -68
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +2 -3
- nautobot/ipam/lookups.py +62 -101
- nautobot/ipam/models.py +16 -66
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +7 -23
- nautobot/ipam/templates/ipam/ipaddress.html +9 -1
- nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +7 -1
- nautobot/ipam/templates/ipam/ipaddress_edit.html +7 -1
- nautobot/ipam/templates/ipam/prefix.html +9 -1
- nautobot/ipam/templates/ipam/prefix_edit.html +7 -1
- nautobot/ipam/templates/ipam/vlan.html +9 -1
- nautobot/ipam/templates/ipam/vlan_edit.html +7 -1
- nautobot/ipam/templates/ipam/vrf_edit.html +7 -1
- nautobot/ipam/tests/test_api.py +3 -416
- nautobot/ipam/tests/test_forms.py +47 -49
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +34 -95
- nautobot/ipam/tests/test_querysets.py +1 -63
- nautobot/ipam/tests/test_views.py +0 -3
- nautobot/ipam/utils/__init__.py +6 -36
- nautobot/ipam/views.py +87 -61
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +2 -40
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
- nautobot/project-static/docs/404.html +4 -46
- nautobot/project-static/docs/apps/index.html +4 -46
- nautobot/project-static/docs/apps/nautobot-apps.html +6 -47
- nautobot/project-static/docs/assets/_mkdocstrings.css +1 -25
- nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js → bundle.83f73b43.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.88dd0f4e.min.js.map → bundle.83f73b43.min.js.map} +2 -2
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +10 -62
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +7 -59
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +122 -374
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +18 -90
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +21 -95
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +6 -53
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +5 -52
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +17 -79
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +28 -102
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +21 -108
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +38 -131
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +65 -239
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +165 -581
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +36 -109
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +167 -453
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +211 -493
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +8 -60
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +15 -71
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +55 -407
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +205 -585
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +412 -858
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +7 -59
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +186 -448
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +147 -365
- nautobot/project-static/docs/development/apps/api/configuration-view.html +4 -46
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +4 -46
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +4 -46
- nautobot/project-static/docs/development/apps/api/models/global-search.html +4 -46
- nautobot/project-static/docs/development/apps/api/models/graphql.html +4 -46
- nautobot/project-static/docs/development/apps/api/models/index.html +4 -46
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +4 -46
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +7 -68
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +4 -46
- nautobot/project-static/docs/development/apps/api/prometheus.html +4 -46
- nautobot/project-static/docs/development/apps/api/setup.html +4 -46
- nautobot/project-static/docs/development/apps/api/testing.html +4 -46
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +4 -46
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +4 -46
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +4 -46
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +4 -46
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/base-template.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/index.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/notes.html +4 -46
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +6 -52
- nautobot/project-static/docs/development/apps/api/views/urls.html +4 -46
- nautobot/project-static/docs/development/apps/index.html +4 -46
- nautobot/project-static/docs/development/apps/migration/code-updates.html +4 -46
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +4 -46
- nautobot/project-static/docs/development/apps/migration/from-v1.html +4 -46
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +4 -46
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +4 -46
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +4 -46
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +4 -46
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +8 -50
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +4 -46
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +14 -211
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +4 -46
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +4 -46
- nautobot/project-static/docs/development/core/application-registry.html +4 -46
- nautobot/project-static/docs/development/core/best-practices.html +4 -46
- nautobot/project-static/docs/development/core/bootstrap-ui.html +4 -46
- nautobot/project-static/docs/development/core/caching.html +4 -46
- nautobot/project-static/docs/development/core/controllers.html +4 -46
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +74 -73
- nautobot/project-static/docs/development/core/generic-views.html +4 -46
- nautobot/project-static/docs/development/core/getting-started.html +224 -249
- nautobot/project-static/docs/development/core/homepage.html +7 -49
- nautobot/project-static/docs/development/core/index.html +4 -46
- nautobot/project-static/docs/development/core/{minikube-dev-environment-for-k8s-jobs.html → local-k8s.html} +168 -469
- nautobot/project-static/docs/development/core/model-checklist.html +12 -56
- nautobot/project-static/docs/development/core/model-features.html +4 -46
- nautobot/project-static/docs/development/core/natural-keys.html +4 -46
- nautobot/project-static/docs/development/core/navigation-menu.html +4 -46
- nautobot/project-static/docs/development/core/release-checklist.html +7 -49
- nautobot/project-static/docs/development/core/role-internals.html +4 -46
- nautobot/project-static/docs/development/core/settings.html +4 -46
- nautobot/project-static/docs/development/core/style-guide.html +7 -49
- nautobot/project-static/docs/development/core/templates.html +4 -46
- nautobot/project-static/docs/development/core/testing.html +4 -46
- nautobot/project-static/docs/development/core/ui-component-framework.html +273 -369
- nautobot/project-static/docs/development/core/user-preferences.html +4 -46
- nautobot/project-static/docs/development/index.html +4 -46
- nautobot/project-static/docs/development/jobs/index.html +122 -216
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +4 -46
- nautobot/project-static/docs/index.html +23 -54
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +7 -47
- nautobot/project-static/docs/overview/design_philosophy.html +4 -46
- nautobot/project-static/docs/release-notes/index.html +12 -52
- nautobot/project-static/docs/release-notes/version-1.0.html +193 -234
- nautobot/project-static/docs/release-notes/version-1.1.html +190 -231
- nautobot/project-static/docs/release-notes/version-1.2.html +265 -306
- nautobot/project-static/docs/release-notes/version-1.3.html +291 -332
- nautobot/project-static/docs/release-notes/version-1.4.html +377 -417
- nautobot/project-static/docs/release-notes/version-1.5.html +566 -605
- nautobot/project-static/docs/release-notes/version-1.6.html +447 -904
- nautobot/project-static/docs/release-notes/version-2.0.html +489 -528
- nautobot/project-static/docs/release-notes/version-2.1.html +324 -363
- nautobot/project-static/docs/release-notes/version-2.2.html +317 -356
- nautobot/project-static/docs/release-notes/version-2.3.html +352 -997
- nautobot/project-static/docs/release-notes/version-2.4.html +101 -417
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +287 -295
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +4 -46
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +4 -46
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +6 -48
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +4 -46
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +4 -46
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +8 -110
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +4 -46
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +6 -48
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +4 -46
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +4 -46
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +4 -46
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +8 -66
- nautobot/project-static/docs/user-guide/administration/installation/index.html +4 -46
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +5 -47
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +4 -46
- nautobot/project-static/docs/user-guide/administration/installation/services.html +4 -46
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +4 -46
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +4 -46
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +4 -46
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +8 -49
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +4 -46
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +12 -50
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +7 -49
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +4 -46
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +7 -51
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +4 -46
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +7 -49
- nautobot/project-static/docs/user-guide/index.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +8 -50
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +7 -50
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +7 -49
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +5 -47
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +25 -94
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +5 -74
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +4 -46
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +4 -46
- nautobot/project-static/js/forms.js +1 -1
- nautobot/tenancy/api/views.py +13 -9
- nautobot/tenancy/views.py +2 -4
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +4 -5
- nautobot/users/api/views.py +3 -3
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/api/views.py +24 -5
- nautobot/virtualization/filters.py +3 -20
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster_edit.html +7 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +9 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +8 -2
- nautobot/virtualization/tests/test_filters.py +0 -17
- nautobot/wireless/filters.py +2 -2
- nautobot/wireless/forms.py +1 -1
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +9 -1
- nautobot/wireless/tests/test_filters.py +1 -29
- nautobot/wireless/views.py +10 -0
- {nautobot-2.4.0.dist-info → nautobot-2.4.0b1.dist-info}/METADATA +6 -6
- {nautobot-2.4.0.dist-info → nautobot-2.4.0b1.dist-info}/RECORD +543 -591
- {nautobot-2.4.0.dist-info → nautobot-2.4.0b1.dist-info}/WHEEL +1 -1
- nautobot/core/api/constants.py +0 -11
- nautobot/core/jobs/bulk_actions.py +0 -248
- nautobot/core/templates/about.html +0 -67
- nautobot/core/templates/inc/tenancy_form_panel.html +0 -9
- nautobot/core/templates/inc/tenant_table_row.html +0 -11
- nautobot/core/utils/querysets.py +0 -64
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +0 -25
- nautobot/dcim/tests/integration/test_controller.py +0 -62
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +0 -71
- nautobot/dcim/tests/test_jobs.py +0 -118
- nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +0 -22
- nautobot/extras/migrations/0121_alter_team_contacts.py +0 -17
- nautobot/extras/test_jobs/singleton.py +0 -16
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +0 -9444
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +0 -9722
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +0 -42
- {nautobot-2.4.0.dist-info → nautobot-2.4.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.0.dist-info → nautobot-2.4.0b1.dist-info}/NOTICE +0 -0
- {nautobot-2.4.0.dist-info → nautobot-2.4.0b1.dist-info}/entry_points.txt +0 -0
nautobot/core/views/generic.py
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
from copy import deepcopy
|
|
2
2
|
import logging
|
|
3
3
|
import re
|
|
4
|
-
from typing import ClassVar, Optional
|
|
5
4
|
|
|
6
5
|
from django.conf import settings
|
|
7
6
|
from django.contrib import messages
|
|
@@ -9,11 +8,12 @@ from django.contrib.auth.mixins import LoginRequiredMixin
|
|
|
9
8
|
from django.contrib.auth.models import AnonymousUser
|
|
10
9
|
from django.contrib.contenttypes.models import ContentType
|
|
11
10
|
from django.core.exceptions import (
|
|
11
|
+
FieldDoesNotExist,
|
|
12
12
|
ObjectDoesNotExist,
|
|
13
13
|
ValidationError,
|
|
14
14
|
)
|
|
15
15
|
from django.db import IntegrityError, transaction
|
|
16
|
-
from django.db.models import
|
|
16
|
+
from django.db.models import ManyToManyField, ProtectedError, Q
|
|
17
17
|
from django.forms import Form, ModelMultipleChoiceField, MultipleHiddenInput
|
|
18
18
|
from django.http import HttpResponse
|
|
19
19
|
from django.shortcuts import get_object_or_404, redirect, render
|
|
@@ -22,8 +22,7 @@ from django.utils.encoding import iri_to_uri
|
|
|
22
22
|
from django.utils.html import format_html
|
|
23
23
|
from django.utils.http import url_has_allowed_host_and_scheme
|
|
24
24
|
from django.views.generic import View
|
|
25
|
-
from
|
|
26
|
-
from django_tables2 import RequestConfig, Table
|
|
25
|
+
from django_tables2 import RequestConfig
|
|
27
26
|
|
|
28
27
|
from nautobot.core.api.utils import get_serializer_for_model
|
|
29
28
|
from nautobot.core.constants import MAX_PAGE_SIZE_DEFAULT
|
|
@@ -48,7 +47,7 @@ from nautobot.core.utils.requests import (
|
|
|
48
47
|
get_filterable_params_from_filter_params,
|
|
49
48
|
normalize_querydict,
|
|
50
49
|
)
|
|
51
|
-
from nautobot.core.views.mixins import
|
|
50
|
+
from nautobot.core.views.mixins import EditAndDeleteAllModelMixin, GetReturnURLMixin, ObjectPermissionRequiredMixin
|
|
52
51
|
from nautobot.core.views.paginator import EnhancedPaginator, get_paginate_count
|
|
53
52
|
from nautobot.core.views.utils import (
|
|
54
53
|
check_filter_for_display,
|
|
@@ -59,7 +58,9 @@ from nautobot.core.views.utils import (
|
|
|
59
58
|
prepare_cloned_fields,
|
|
60
59
|
view_changes_not_saved,
|
|
61
60
|
)
|
|
61
|
+
from nautobot.extras.context_managers import deferred_change_logging_for_bulk_operation
|
|
62
62
|
from nautobot.extras.models import ExportTemplate, SavedView, UserSavedViewAssociation
|
|
63
|
+
from nautobot.extras.utils import bulk_delete_with_bulk_change_logging, remove_prefix_from_cf_key
|
|
63
64
|
|
|
64
65
|
|
|
65
66
|
class GenericView(LoginRequiredMixin, View):
|
|
@@ -78,8 +79,8 @@ class ObjectView(ObjectPermissionRequiredMixin, View):
|
|
|
78
79
|
template_name: Name of the template to use
|
|
79
80
|
"""
|
|
80
81
|
|
|
81
|
-
queryset
|
|
82
|
-
template_name
|
|
82
|
+
queryset = None
|
|
83
|
+
template_name = None
|
|
83
84
|
object_detail_content = None
|
|
84
85
|
|
|
85
86
|
def get_required_permission(self):
|
|
@@ -141,10 +142,10 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
141
142
|
non_filter_params: List of query parameters that are **not** used for queryset filtering
|
|
142
143
|
"""
|
|
143
144
|
|
|
144
|
-
queryset
|
|
145
|
-
filterset
|
|
146
|
-
filterset_form
|
|
147
|
-
table
|
|
145
|
+
queryset = None
|
|
146
|
+
filterset = None
|
|
147
|
+
filterset_form = None
|
|
148
|
+
table = None
|
|
148
149
|
template_name = "generic/object_list.html"
|
|
149
150
|
action_buttons = ("add", "import", "export")
|
|
150
151
|
non_filter_params = (
|
|
@@ -161,11 +162,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
161
162
|
def get_filter_params(self, request):
|
|
162
163
|
"""Helper function - take request.GET and discard any parameters that are not used for queryset filtering."""
|
|
163
164
|
params = request.GET.copy()
|
|
164
|
-
filter_params = get_filterable_params_from_filter_params(
|
|
165
|
-
params,
|
|
166
|
-
self.non_filter_params,
|
|
167
|
-
self.filterset(), # pylint: disable=not-callable # this fn is only called if filterset is not None
|
|
168
|
-
)
|
|
165
|
+
filter_params = get_filterable_params_from_filter_params(params, self.non_filter_params, self.filterset())
|
|
169
166
|
if params.get("saved_view") and not filter_params and not params.get("all_filters_removed"):
|
|
170
167
|
return SavedView.objects.get(pk=params.get("saved_view")).config.get("filter_params", {})
|
|
171
168
|
return filter_params
|
|
@@ -239,9 +236,9 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
239
236
|
except ObjectDoesNotExist:
|
|
240
237
|
pass
|
|
241
238
|
|
|
242
|
-
if self.filterset
|
|
239
|
+
if self.filterset:
|
|
243
240
|
filter_params = self.get_filter_params(request)
|
|
244
|
-
filterset = self.filterset(filter_params, self.queryset)
|
|
241
|
+
filterset = self.filterset(filter_params, self.queryset)
|
|
245
242
|
self.queryset = filterset.qs
|
|
246
243
|
if not filterset.is_valid():
|
|
247
244
|
messages.error(
|
|
@@ -269,7 +266,7 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
269
266
|
else:
|
|
270
267
|
dynamic_filter_form = DynamicFilterFormSet(filterset=filterset)
|
|
271
268
|
|
|
272
|
-
if self.filterset_form
|
|
269
|
+
if self.filterset_form:
|
|
273
270
|
filter_form = self.filterset_form(filter_params, label_suffix="")
|
|
274
271
|
|
|
275
272
|
# Check for export template rendering
|
|
@@ -329,14 +326,14 @@ class ObjectListView(ObjectPermissionRequiredMixin, View):
|
|
|
329
326
|
messages.error(request, f"Saved view {current_saved_view_pk} not found")
|
|
330
327
|
|
|
331
328
|
# Construct the objects table
|
|
332
|
-
if self.table
|
|
329
|
+
if self.table:
|
|
333
330
|
if self.request.GET.getlist("sort") or (
|
|
334
331
|
current_saved_view is not None and current_saved_view.config.get("sort_order")
|
|
335
332
|
):
|
|
336
333
|
hide_hierarchy_ui = True # hide tree hierarchy if custom sort is used
|
|
337
334
|
table_changes_pending = self.request.GET.get("table_changes_pending", False)
|
|
338
335
|
|
|
339
|
-
table = self.table(
|
|
336
|
+
table = self.table(
|
|
340
337
|
self.queryset,
|
|
341
338
|
table_changes_pending=table_changes_pending,
|
|
342
339
|
saved_view=current_saved_view,
|
|
@@ -413,8 +410,8 @@ class ObjectEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
413
410
|
template_name: The name of the template
|
|
414
411
|
"""
|
|
415
412
|
|
|
416
|
-
queryset
|
|
417
|
-
model_form
|
|
413
|
+
queryset = None
|
|
414
|
+
model_form = None
|
|
418
415
|
template_name = "generic/object_create.html"
|
|
419
416
|
|
|
420
417
|
def get_required_permission(self):
|
|
@@ -556,7 +553,7 @@ class ObjectDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
556
553
|
template_name: The name of the template
|
|
557
554
|
"""
|
|
558
555
|
|
|
559
|
-
queryset
|
|
556
|
+
queryset = None
|
|
560
557
|
template_name = "generic/object_delete.html"
|
|
561
558
|
|
|
562
559
|
def get_required_permission(self):
|
|
@@ -636,9 +633,9 @@ class BulkCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
636
633
|
template_name: The name of the template
|
|
637
634
|
"""
|
|
638
635
|
|
|
639
|
-
queryset
|
|
640
|
-
form
|
|
641
|
-
model_form
|
|
636
|
+
queryset = None
|
|
637
|
+
form = None
|
|
638
|
+
model_form = None
|
|
642
639
|
pattern_target = ""
|
|
643
640
|
template_name = None
|
|
644
641
|
|
|
@@ -745,8 +742,8 @@ class ObjectImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
745
742
|
template_name: The name of the template
|
|
746
743
|
"""
|
|
747
744
|
|
|
748
|
-
queryset
|
|
749
|
-
model_form
|
|
745
|
+
queryset = None
|
|
746
|
+
model_form = None
|
|
750
747
|
related_object_forms = {}
|
|
751
748
|
template_name = "generic/object_import.html"
|
|
752
749
|
|
|
@@ -890,8 +887,8 @@ class BulkImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): #
|
|
|
890
887
|
template_name: The name of the template
|
|
891
888
|
"""
|
|
892
889
|
|
|
893
|
-
queryset
|
|
894
|
-
table
|
|
890
|
+
queryset = None
|
|
891
|
+
table = None
|
|
895
892
|
template_name = "generic/object_bulk_import.html"
|
|
896
893
|
|
|
897
894
|
def __init__(self, *args, **kwargs):
|
|
@@ -985,7 +982,7 @@ class BulkImportView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View): #
|
|
|
985
982
|
)
|
|
986
983
|
|
|
987
984
|
|
|
988
|
-
class BulkEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin,
|
|
985
|
+
class BulkEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, EditAndDeleteAllModelMixin, View):
|
|
989
986
|
"""
|
|
990
987
|
Edit objects in bulk.
|
|
991
988
|
|
|
@@ -996,10 +993,10 @@ class BulkEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, BulkEditAnd
|
|
|
996
993
|
template_name: The name of the template
|
|
997
994
|
"""
|
|
998
995
|
|
|
999
|
-
queryset
|
|
1000
|
-
filterset
|
|
1001
|
-
table
|
|
1002
|
-
form
|
|
996
|
+
queryset = None
|
|
997
|
+
filterset = None
|
|
998
|
+
table = None
|
|
999
|
+
form = None
|
|
1003
1000
|
template_name = "generic/object_bulk_edit.html"
|
|
1004
1001
|
|
|
1005
1002
|
def get_required_permission(self):
|
|
@@ -1035,7 +1032,93 @@ class BulkEditView(GetReturnURLMixin, ObjectPermissionRequiredMixin, BulkEditAnd
|
|
|
1035
1032
|
|
|
1036
1033
|
if form.is_valid():
|
|
1037
1034
|
logger.debug("Form validation was successful")
|
|
1038
|
-
|
|
1035
|
+
form_custom_fields = getattr(form, "custom_fields", [])
|
|
1036
|
+
form_relationships = getattr(form, "relationships", [])
|
|
1037
|
+
standard_fields = [
|
|
1038
|
+
field
|
|
1039
|
+
for field in form.fields
|
|
1040
|
+
if field not in form_custom_fields + form_relationships + ["pk"] + ["object_note"]
|
|
1041
|
+
]
|
|
1042
|
+
nullified_fields = request.POST.getlist("_nullify")
|
|
1043
|
+
|
|
1044
|
+
try:
|
|
1045
|
+
with deferred_change_logging_for_bulk_operation():
|
|
1046
|
+
updated_objects = []
|
|
1047
|
+
queryset = queryset if edit_all else queryset.filter(pk__in=form.cleaned_data["pk"])
|
|
1048
|
+
for obj in queryset:
|
|
1049
|
+
obj = self.alter_obj(obj, request, [], kwargs)
|
|
1050
|
+
|
|
1051
|
+
# Update standard fields. If a field is listed in _nullify, delete its value.
|
|
1052
|
+
for name in standard_fields:
|
|
1053
|
+
try:
|
|
1054
|
+
model_field = model._meta.get_field(name)
|
|
1055
|
+
except FieldDoesNotExist:
|
|
1056
|
+
# This form field is used to modify a field rather than set its value directly
|
|
1057
|
+
model_field = None
|
|
1058
|
+
|
|
1059
|
+
# Handle nullification
|
|
1060
|
+
if name in form.nullable_fields and name in nullified_fields:
|
|
1061
|
+
if isinstance(model_field, ManyToManyField):
|
|
1062
|
+
getattr(obj, name).set([])
|
|
1063
|
+
else:
|
|
1064
|
+
setattr(obj, name, None if model_field is not None and model_field.null else "")
|
|
1065
|
+
|
|
1066
|
+
# ManyToManyFields
|
|
1067
|
+
elif isinstance(model_field, ManyToManyField):
|
|
1068
|
+
if form.cleaned_data[name]:
|
|
1069
|
+
getattr(obj, name).set(form.cleaned_data[name])
|
|
1070
|
+
# Normal fields
|
|
1071
|
+
elif form.cleaned_data[name] not in (None, ""):
|
|
1072
|
+
setattr(obj, name, form.cleaned_data[name])
|
|
1073
|
+
|
|
1074
|
+
# Update custom fields
|
|
1075
|
+
for field_name in form_custom_fields:
|
|
1076
|
+
if field_name in form.nullable_fields and field_name in nullified_fields:
|
|
1077
|
+
obj.cf[remove_prefix_from_cf_key(field_name)] = None
|
|
1078
|
+
elif form.cleaned_data.get(field_name) not in (None, "", []):
|
|
1079
|
+
obj.cf[remove_prefix_from_cf_key(field_name)] = form.cleaned_data[field_name]
|
|
1080
|
+
|
|
1081
|
+
obj.full_clean()
|
|
1082
|
+
obj.save()
|
|
1083
|
+
updated_objects.append(obj)
|
|
1084
|
+
logger.debug(f"Saved {obj} (PK: {obj.pk})")
|
|
1085
|
+
|
|
1086
|
+
# Add/remove tags
|
|
1087
|
+
if form.cleaned_data.get("add_tags", None):
|
|
1088
|
+
obj.tags.add(*form.cleaned_data["add_tags"])
|
|
1089
|
+
if form.cleaned_data.get("remove_tags", None):
|
|
1090
|
+
obj.tags.remove(*form.cleaned_data["remove_tags"])
|
|
1091
|
+
|
|
1092
|
+
if hasattr(form, "save_relationships") and callable(form.save_relationships):
|
|
1093
|
+
# Add/remove relationship associations
|
|
1094
|
+
form.save_relationships(instance=obj, nullified_fields=nullified_fields)
|
|
1095
|
+
|
|
1096
|
+
if hasattr(form, "save_note") and callable(form.save_note):
|
|
1097
|
+
form.save_note(instance=obj, user=request.user)
|
|
1098
|
+
|
|
1099
|
+
self.extra_post_save_action(obj, form)
|
|
1100
|
+
|
|
1101
|
+
# Enforce object-level permissions
|
|
1102
|
+
if self.queryset.filter(pk__in=[obj.pk for obj in updated_objects]).count() != len(
|
|
1103
|
+
updated_objects
|
|
1104
|
+
):
|
|
1105
|
+
raise ObjectDoesNotExist
|
|
1106
|
+
|
|
1107
|
+
if updated_objects:
|
|
1108
|
+
msg = f"Updated {len(updated_objects)} {model._meta.verbose_name_plural}"
|
|
1109
|
+
logger.info(msg)
|
|
1110
|
+
messages.success(self.request, msg)
|
|
1111
|
+
|
|
1112
|
+
return redirect(self.get_return_url(request))
|
|
1113
|
+
|
|
1114
|
+
except ValidationError as e:
|
|
1115
|
+
messages.error(self.request, f"{obj} failed validation: {e}")
|
|
1116
|
+
|
|
1117
|
+
except ObjectDoesNotExist:
|
|
1118
|
+
msg = "Object update failed due to object-level permissions violation"
|
|
1119
|
+
logger.debug(msg)
|
|
1120
|
+
form.add_error(None, msg)
|
|
1121
|
+
|
|
1039
1122
|
else:
|
|
1040
1123
|
logger.debug("Form validation failed")
|
|
1041
1124
|
|
|
@@ -1084,7 +1167,7 @@ class BulkRenameView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
1084
1167
|
An extendable view for renaming objects in bulk.
|
|
1085
1168
|
"""
|
|
1086
1169
|
|
|
1087
|
-
queryset
|
|
1170
|
+
queryset = None
|
|
1088
1171
|
template_name = "generic/object_bulk_rename.html"
|
|
1089
1172
|
|
|
1090
1173
|
def __init__(self, *args, **kwargs):
|
|
@@ -1179,7 +1262,7 @@ class BulkRenameView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View):
|
|
|
1179
1262
|
return ""
|
|
1180
1263
|
|
|
1181
1264
|
|
|
1182
|
-
class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin,
|
|
1265
|
+
class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, EditAndDeleteAllModelMixin, View):
|
|
1183
1266
|
"""
|
|
1184
1267
|
Delete objects in bulk.
|
|
1185
1268
|
|
|
@@ -1190,10 +1273,10 @@ class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, BulkEditA
|
|
|
1190
1273
|
template_name: The name of the template
|
|
1191
1274
|
"""
|
|
1192
1275
|
|
|
1193
|
-
queryset
|
|
1194
|
-
filterset
|
|
1195
|
-
table
|
|
1196
|
-
form
|
|
1276
|
+
queryset = None
|
|
1277
|
+
filterset = None
|
|
1278
|
+
table = None
|
|
1279
|
+
form = None
|
|
1197
1280
|
template_name = "generic/object_bulk_delete.html"
|
|
1198
1281
|
|
|
1199
1282
|
def get_required_permission(self):
|
|
@@ -1202,30 +1285,48 @@ class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, BulkEditA
|
|
|
1202
1285
|
def get(self, request):
|
|
1203
1286
|
return redirect(self.get_return_url(request))
|
|
1204
1287
|
|
|
1288
|
+
def _perform_delete_operation(self, request, queryset, model):
|
|
1289
|
+
logger = logging.getLogger(__name__ + ".BulkDeleteView")
|
|
1290
|
+
self.perform_pre_delete(request, queryset)
|
|
1291
|
+
try:
|
|
1292
|
+
_, deleted_info = bulk_delete_with_bulk_change_logging(queryset)
|
|
1293
|
+
deleted_count = deleted_info[model._meta.label]
|
|
1294
|
+
except ProtectedError as e:
|
|
1295
|
+
logger.info("Caught ProtectedError while attempting to delete objects")
|
|
1296
|
+
handle_protectederror(queryset, request, e)
|
|
1297
|
+
return redirect(self.get_return_url(request))
|
|
1298
|
+
msg = f"Deleted {deleted_count} {model._meta.verbose_name_plural}"
|
|
1299
|
+
logger.info(msg)
|
|
1300
|
+
messages.success(request, msg)
|
|
1301
|
+
return redirect(self.get_return_url(request))
|
|
1302
|
+
|
|
1205
1303
|
def post(self, request, **kwargs):
|
|
1206
1304
|
logger = logging.getLogger(f"{__name__}.BulkDeleteView")
|
|
1207
1305
|
model = self.queryset.model
|
|
1208
|
-
delete_all = request.POST.get("_all")
|
|
1209
1306
|
|
|
1210
1307
|
# Are we deleting *all* objects in the queryset or just a selected subset?
|
|
1211
|
-
if
|
|
1308
|
+
if request.POST.get("_all"):
|
|
1212
1309
|
queryset = self._get_bulk_edit_delete_all_queryset(request)
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1310
|
+
|
|
1311
|
+
if "_confirm" in request.POST:
|
|
1312
|
+
return self._perform_delete_operation(request, queryset, model)
|
|
1313
|
+
|
|
1314
|
+
context = self._bulk_delete_all_context(request, queryset)
|
|
1315
|
+
context.update(self.extra_context())
|
|
1316
|
+
return render(request, self.template_name, context)
|
|
1317
|
+
|
|
1318
|
+
pk_list = request.POST.getlist("pk")
|
|
1217
1319
|
|
|
1218
1320
|
form_cls = self.get_form()
|
|
1219
1321
|
|
|
1220
1322
|
if "_confirm" in request.POST:
|
|
1221
1323
|
form = form_cls(request.POST)
|
|
1222
|
-
# Set pk field requirement here instead of BulkDeleteForm since get_form() may return a different form class
|
|
1223
|
-
if delete_all:
|
|
1224
|
-
form.fields["pk"].required = False
|
|
1225
|
-
|
|
1226
1324
|
if form.is_valid():
|
|
1227
1325
|
logger.debug("Form validation was successful")
|
|
1228
|
-
|
|
1326
|
+
|
|
1327
|
+
# Delete objects
|
|
1328
|
+
queryset = self.queryset.filter(pk__in=pk_list)
|
|
1329
|
+
return self._perform_delete_operation(request, queryset, model)
|
|
1229
1330
|
else:
|
|
1230
1331
|
logger.debug("Form validation failed")
|
|
1231
1332
|
|
|
@@ -1238,26 +1339,23 @@ class BulkDeleteView(GetReturnURLMixin, ObjectPermissionRequiredMixin, BulkEditA
|
|
|
1238
1339
|
)
|
|
1239
1340
|
|
|
1240
1341
|
# Retrieve objects being deleted
|
|
1241
|
-
table =
|
|
1242
|
-
if not
|
|
1243
|
-
|
|
1244
|
-
|
|
1245
|
-
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
if "actions" in table.columns:
|
|
1252
|
-
table.columns.hide("actions")
|
|
1342
|
+
table = self.table(self.queryset.filter(pk__in=pk_list), orderable=False)
|
|
1343
|
+
if not table.rows:
|
|
1344
|
+
messages.warning(
|
|
1345
|
+
request,
|
|
1346
|
+
f"No {model._meta.verbose_name_plural} were selected for deletion.",
|
|
1347
|
+
)
|
|
1348
|
+
return redirect(self.get_return_url(request))
|
|
1349
|
+
# Hide actions column if present
|
|
1350
|
+
if "actions" in table.columns:
|
|
1351
|
+
table.columns.hide("actions")
|
|
1253
1352
|
|
|
1254
1353
|
context = {
|
|
1255
1354
|
"form": form,
|
|
1256
1355
|
"obj_type_plural": model._meta.verbose_name_plural,
|
|
1257
1356
|
"table": table,
|
|
1258
1357
|
"return_url": self.get_return_url(request),
|
|
1259
|
-
"total_objs_to_delete":
|
|
1260
|
-
"delete_all": delete_all,
|
|
1358
|
+
"total_objs_to_delete": len(table.rows),
|
|
1261
1359
|
}
|
|
1262
1360
|
context.update(self.extra_context())
|
|
1263
1361
|
return render(request, self.template_name, context)
|
|
@@ -1293,9 +1391,9 @@ class ComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin, View
|
|
|
1293
1391
|
Add one or more components (e.g. interfaces, console ports, etc.) to a Device or VirtualMachine.
|
|
1294
1392
|
"""
|
|
1295
1393
|
|
|
1296
|
-
queryset
|
|
1297
|
-
form
|
|
1298
|
-
model_form
|
|
1394
|
+
queryset = None
|
|
1395
|
+
form = None
|
|
1396
|
+
model_form = None
|
|
1299
1397
|
template_name = "dcim/device_component_add.html"
|
|
1300
1398
|
|
|
1301
1399
|
def get_required_permission(self):
|
|
@@ -1395,13 +1493,13 @@ class BulkComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin,
|
|
|
1395
1493
|
Add one or more components (e.g. interfaces, console ports, etc.) to a set of Devices or VirtualMachines.
|
|
1396
1494
|
"""
|
|
1397
1495
|
|
|
1398
|
-
parent_model
|
|
1496
|
+
parent_model = None
|
|
1399
1497
|
parent_field = None
|
|
1400
|
-
form
|
|
1401
|
-
queryset
|
|
1402
|
-
model_form
|
|
1403
|
-
filterset
|
|
1404
|
-
table
|
|
1498
|
+
form = None
|
|
1499
|
+
queryset = None
|
|
1500
|
+
model_form = None
|
|
1501
|
+
filterset = None
|
|
1502
|
+
table = None
|
|
1405
1503
|
template_name = "generic/object_bulk_add_component.html"
|
|
1406
1504
|
|
|
1407
1505
|
def get_required_permission(self):
|
|
@@ -1415,7 +1513,7 @@ class BulkComponentCreateView(GetReturnURLMixin, ObjectPermissionRequiredMixin,
|
|
|
1415
1513
|
|
|
1416
1514
|
# Are we editing *all* objects in the queryset or just a selected subset?
|
|
1417
1515
|
if request.POST.get("_all") and self.filterset is not None:
|
|
1418
|
-
pk_list = [obj.pk for obj in self.filterset(request.GET, self.parent_model.objects.only("pk")).qs]
|
|
1516
|
+
pk_list = [obj.pk for obj in self.filterset(request.GET, self.parent_model.objects.only("pk")).qs]
|
|
1419
1517
|
else:
|
|
1420
1518
|
pk_list = request.POST.getlist("pk")
|
|
1421
1519
|
|