nautobot 2.4.0b1__py3-none-any.whl → 2.4.2__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 +1 -0
- nautobot/circuits/api/views.py +4 -8
- nautobot/circuits/tables.py +2 -1
- nautobot/circuits/templates/circuits/circuit_create.html +1 -7
- nautobot/circuits/tests/integration/test_circuits_bulk_operations.py +43 -0
- nautobot/circuits/tests/integration/test_relationships.py +1 -1
- nautobot/circuits/views.py +3 -3
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/models.py +1 -1
- nautobot/cloud/views.py +0 -16
- nautobot/core/api/constants.py +11 -0
- nautobot/core/api/fields.py +5 -5
- nautobot/core/api/filter_backends.py +3 -9
- nautobot/core/api/schema.py +13 -2
- nautobot/core/api/serializers.py +40 -34
- nautobot/core/api/views.py +56 -4
- nautobot/core/apps/__init__.py +0 -5
- nautobot/core/celery/log.py +4 -4
- nautobot/core/celery/schedulers.py +2 -2
- nautobot/core/choices.py +2 -2
- nautobot/core/events/__init__.py +3 -3
- nautobot/core/filters.py +67 -35
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +14 -11
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/graphql/types.py +1 -1
- nautobot/core/jobs/__init__.py +28 -7
- nautobot/core/jobs/bulk_actions.py +285 -0
- nautobot/core/jobs/cleanup.py +48 -12
- nautobot/core/jobs/groups.py +1 -1
- nautobot/core/management/commands/validate_models.py +1 -1
- nautobot/core/models/__init__.py +3 -1
- nautobot/core/models/query_functions.py +2 -2
- nautobot/core/models/tree_queries.py +6 -3
- nautobot/core/settings.py +29 -2
- nautobot/core/settings.yaml +21 -0
- nautobot/core/tables.py +79 -61
- nautobot/core/templates/about.html +67 -0
- nautobot/core/templates/generic/object_bulk_destroy.html +1 -1
- nautobot/core/templates/inc/media.html +3 -0
- nautobot/core/templates/inc/nav_menu.html +1 -0
- nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
- nautobot/core/templates/inc/tenant_table_row.html +11 -0
- nautobot/core/templates/nautobot_config.py.j2 +13 -0
- nautobot/core/templates/search.html +7 -0
- 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 +7 -0
- nautobot/core/templatetags/helpers.py +11 -2
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +170 -15
- nautobot/core/testing/filters.py +45 -10
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/integration.py +514 -5
- nautobot/core/testing/mixins.py +7 -2
- nautobot/core/testing/views.py +44 -29
- nautobot/core/tests/integration/test_app_home.py +0 -1
- nautobot/core/tests/integration/test_app_navbar.py +0 -1
- nautobot/core/tests/integration/test_filters.py +0 -2
- nautobot/core/tests/integration/test_home.py +0 -1
- nautobot/core/tests/integration/test_navbar.py +0 -1
- nautobot/core/tests/integration/test_view_authentication.py +1 -0
- nautobot/core/tests/runner.py +1 -1
- nautobot/core/tests/test_api.py +98 -1
- nautobot/core/tests/test_csv.py +25 -3
- nautobot/core/tests/test_filters.py +209 -246
- nautobot/core/tests/test_forms.py +1 -0
- nautobot/core/tests/test_jobs.py +492 -1
- nautobot/core/tests/test_models.py +9 -0
- nautobot/core/tests/test_settings_schema.py +7 -0
- nautobot/core/tests/test_tables.py +100 -0
- nautobot/core/tests/test_utils.py +63 -1
- nautobot/core/tests/test_views.py +30 -3
- nautobot/core/ui/nav.py +1 -0
- nautobot/core/ui/object_detail.py +15 -1
- nautobot/core/urls.py +11 -0
- nautobot/core/utils/git.py +7 -2
- nautobot/core/utils/lookup.py +11 -8
- nautobot/core/utils/querysets.py +64 -0
- nautobot/core/utils/requests.py +24 -9
- nautobot/core/views/__init__.py +42 -0
- nautobot/core/views/generic.py +131 -197
- nautobot/core/views/mixins.py +136 -41
- nautobot/core/views/renderers.py +6 -6
- nautobot/core/views/utils.py +2 -2
- nautobot/dcim/api/serializers.py +56 -64
- nautobot/dcim/api/views.py +47 -113
- nautobot/dcim/constants.py +6 -13
- nautobot/dcim/factory.py +6 -1
- nautobot/dcim/filters/__init__.py +31 -2
- nautobot/dcim/forms.py +48 -17
- nautobot/dcim/graphql/types.py +2 -2
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
- nautobot/dcim/models/__init__.py +1 -1
- nautobot/dcim/models/device_component_templates.py +2 -2
- nautobot/dcim/models/device_components.py +22 -20
- nautobot/dcim/models/devices.py +10 -1
- nautobot/dcim/models/locations.py +3 -3
- nautobot/dcim/models/power.py +6 -5
- nautobot/dcim/models/racks.py +4 -4
- nautobot/dcim/tables/__init__.py +3 -3
- nautobot/dcim/tables/devices.py +9 -6
- nautobot/dcim/tables/devicetypes.py +2 -2
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/cable.html +1 -1
- nautobot/dcim/templates/dcim/controller_create.html +1 -7
- nautobot/dcim/templates/dcim/controller_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +2 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +5 -0
- nautobot/dcim/templates/dcim/device/base.html +1 -1
- nautobot/dcim/templates/dcim/device.html +3 -11
- nautobot/dcim/templates/dcim/device_component.html +1 -1
- nautobot/dcim/templates/dcim/device_edit.html +36 -37
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/location.html +2 -10
- nautobot/dcim/templates/dcim/location_edit.html +1 -7
- nautobot/dcim/templates/dcim/locationtype.html +1 -1
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/manufacturer.html +1 -1
- nautobot/dcim/templates/dcim/platform.html +1 -1
- nautobot/dcim/templates/dcim/powerfeed.html +1 -1
- nautobot/dcim/templates/dcim/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/rack.html +2 -10
- nautobot/dcim/templates/dcim/rack_edit.html +1 -7
- nautobot/dcim/templates/dcim/rackgroup.html +1 -1
- nautobot/dcim/templates/dcim/rackreservation.html +3 -11
- nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +1 -7
- nautobot/dcim/tests/integration/test_controller.py +62 -0
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
- nautobot/dcim/tests/integration/test_device_bulk_operations.py +30 -0
- nautobot/dcim/tests/integration/test_location_bulk_operations.py +43 -0
- nautobot/dcim/tests/test_api.py +16 -5
- nautobot/dcim/tests/test_filters.py +33 -0
- nautobot/dcim/tests/test_forms.py +51 -2
- nautobot/dcim/tests/test_graphql.py +52 -0
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +52 -9
- nautobot/dcim/tests/test_views.py +30 -84
- nautobot/dcim/views.py +13 -28
- nautobot/extras/api/customfields.py +2 -2
- nautobot/extras/api/serializers.py +123 -85
- nautobot/extras/api/views.py +33 -30
- nautobot/extras/constants.py +3 -0
- nautobot/extras/datasources/git.py +125 -0
- nautobot/extras/filters/__init__.py +8 -6
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +139 -31
- nautobot/extras/forms/mixins.py +14 -6
- nautobot/extras/group_sync.py +3 -3
- nautobot/extras/health_checks.py +1 -2
- nautobot/extras/jobs.py +85 -18
- nautobot/extras/managers.py +3 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +7 -9
- nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
- nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
- nautobot/extras/migrations/0122_add_graphqlquery_owner_content_type.py +34 -0
- nautobot/extras/models/__init__.py +1 -1
- nautobot/extras/models/contacts.py +1 -1
- nautobot/extras/models/customfields.py +41 -23
- nautobot/extras/models/datasources.py +85 -0
- nautobot/extras/models/groups.py +11 -9
- nautobot/extras/models/jobs.py +23 -4
- nautobot/extras/models/models.py +17 -2
- nautobot/extras/models/relationships.py +17 -5
- nautobot/extras/plugins/__init__.py +13 -2
- nautobot/extras/plugins/marketplace_manifest.yml +84 -79
- nautobot/extras/plugins/tables.py +16 -14
- nautobot/extras/plugins/views.py +65 -69
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/signals.py +15 -1
- nautobot/extras/tables.py +7 -5
- nautobot/extras/templates/extras/computedfield.html +1 -1
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +1 -1
- nautobot/extras/templates/extras/customfield.html +1 -1
- nautobot/extras/templates/extras/customlink.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup.html +2 -10
- nautobot/extras/templates/extras/exporttemplate.html +1 -1
- nautobot/extras/templates/extras/gitrepository.html +1 -1
- nautobot/extras/templates/extras/graphqlquery.html +1 -1
- nautobot/extras/templates/extras/job_detail.html +17 -1
- nautobot/extras/templates/extras/job_edit.html +1 -0
- nautobot/extras/templates/extras/jobbutton_retrieve.html +1 -1
- nautobot/extras/templates/extras/jobhook.html +1 -1
- nautobot/extras/templates/extras/jobqueue_retrieve.html +1 -9
- nautobot/extras/templates/extras/jobresult.html +1 -1
- nautobot/extras/templates/extras/marketplace.html +29 -11
- nautobot/extras/templates/extras/objectchange.html +1 -1
- nautobot/extras/templates/extras/plugin_detail.html +33 -16
- nautobot/extras/templates/extras/plugins_tiles.html +21 -10
- nautobot/extras/templates/extras/relationship.html +1 -63
- nautobot/extras/templates/extras/role_retrieve.html +1 -1
- nautobot/extras/templates/extras/scheduledjob.html +1 -1
- nautobot/extras/templates/extras/secret.html +1 -1
- nautobot/extras/templates/extras/secretsgroup.html +1 -1
- nautobot/extras/templates/extras/status.html +1 -1
- nautobot/extras/templates/extras/tag.html +1 -1
- nautobot/extras/templates/extras/webhook.html +1 -1
- nautobot/extras/templatetags/job_buttons.py +4 -4
- 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 +3 -1
- 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/singleton.py +16 -0
- 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/git_data/01-valid-files/graphql_queries/device_interfaces.gql +8 -0
- nautobot/extras/tests/git_data/01-valid-files/graphql_queries/device_names.gql +5 -0
- nautobot/extras/tests/git_data/02-invalid-files/graphql_queries/bad_device_names.gql +5 -0
- nautobot/extras/tests/git_helper.py +9 -1
- nautobot/extras/tests/integration/__init__.py +29 -16
- nautobot/extras/tests/integration/test_plugin_banner.py +0 -2
- nautobot/extras/tests/test_api.py +19 -13
- nautobot/extras/tests/test_customfields.py +50 -52
- nautobot/extras/tests/test_datasources.py +29 -1
- nautobot/extras/tests/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/test_filters.py +6 -6
- nautobot/extras/tests/test_forms.py +33 -1
- nautobot/extras/tests/test_jobs.py +178 -32
- nautobot/extras/tests/test_models.py +299 -10
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +120 -9
- nautobot/extras/tests/test_utils.py +22 -1
- nautobot/extras/tests/test_views.py +56 -194
- nautobot/extras/utils.py +20 -10
- nautobot/extras/views.py +85 -110
- nautobot/ipam/api/fields.py +3 -3
- nautobot/ipam/api/serializers.py +41 -33
- nautobot/ipam/api/views.py +68 -117
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +3 -2
- nautobot/ipam/lookups.py +101 -62
- nautobot/ipam/models.py +74 -18
- nautobot/ipam/querysets.py +2 -2
- nautobot/ipam/tables.py +25 -9
- nautobot/ipam/templates/ipam/ipaddress.html +2 -10
- nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
- nautobot/ipam/templates/ipam/prefix.html +2 -10
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
- nautobot/ipam/templates/ipam/rir.html +1 -1
- nautobot/ipam/templates/ipam/routetarget.html +1 -1
- nautobot/ipam/templates/ipam/service.html +1 -1
- nautobot/ipam/templates/ipam/vlan.html +2 -10
- nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
- nautobot/ipam/templates/ipam/vlangroup.html +1 -1
- nautobot/ipam/templates/ipam/vrf.html +1 -1
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
- nautobot/ipam/tests/test_api.py +436 -3
- nautobot/ipam/tests/test_forms.py +49 -47
- nautobot/ipam/tests/test_migrations.py +30 -30
- nautobot/ipam/tests/test_models.py +119 -34
- nautobot/ipam/tests/test_querysets.py +63 -1
- nautobot/ipam/tests/test_utils.py +41 -2
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/utils/__init__.py +54 -17
- nautobot/ipam/views.py +61 -87
- 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 +40 -2
- 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 +131 -14
- nautobot/project-static/docs/apps/index.html +131 -14
- nautobot/project-static/docs/apps/nautobot-apps.html +132 -16
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js → bundle.60a45f97.min.js} +2 -2
- nautobot/project-static/docs/assets/javascripts/{bundle.83f73b43.min.js.map → bundle.60a45f97.min.js.map} +2 -2
- nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js → search.f8cc74c7.min.js} +1 -1
- nautobot/project-static/docs/assets/javascripts/workers/{search.6ce7567c.min.js.map → search.f8cc74c7.min.js.map} +1 -1
- nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css → main.a40c8224.min.css} +1 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +147 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +144 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +459 -132
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +175 -28
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +180 -31
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +138 -16
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +137 -15
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +164 -27
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +187 -38
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +193 -31
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +216 -48
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +324 -75
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +666 -175
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +194 -46
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +538 -177
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +578 -221
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +145 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +156 -25
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +492 -65
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +705 -215
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +943 -422
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +144 -17
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +619 -200
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +474 -159
- nautobot/project-static/docs/development/apps/api/configuration-view.html +131 -14
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/global-search.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/graphql.html +131 -14
- nautobot/project-static/docs/development/apps/api/models/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +131 -14
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +153 -17
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +131 -14
- nautobot/project-static/docs/development/apps/api/prometheus.html +131 -14
- nautobot/project-static/docs/development/apps/api/setup.html +131 -14
- nautobot/project-static/docs/development/apps/api/testing.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +131 -14
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/base-template.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/index.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/notes.html +131 -14
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +137 -16
- nautobot/project-static/docs/development/apps/api/views/urls.html +131 -14
- nautobot/project-static/docs/development/apps/index.html +131 -14
- nautobot/project-static/docs/development/apps/migration/code-updates.html +131 -14
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +131 -14
- nautobot/project-static/docs/development/apps/migration/from-v1.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +131 -14
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +131 -14
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +135 -18
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +131 -14
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +297 -25
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +131 -14
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +131 -14
- nautobot/project-static/docs/development/core/application-registry.html +131 -14
- nautobot/project-static/docs/development/core/best-practices.html +131 -14
- nautobot/project-static/docs/development/core/bootstrap-ui.html +131 -14
- nautobot/project-static/docs/development/core/caching.html +131 -14
- nautobot/project-static/docs/development/core/controllers.html +131 -14
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +158 -84
- nautobot/project-static/docs/development/core/generic-views.html +131 -14
- nautobot/project-static/docs/development/core/getting-started.html +334 -234
- nautobot/project-static/docs/development/core/homepage.html +134 -17
- nautobot/project-static/docs/development/core/index.html +131 -14
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9829 -0
- nautobot/project-static/docs/development/core/model-checklist.html +141 -22
- nautobot/project-static/docs/development/core/model-features.html +131 -14
- nautobot/project-static/docs/development/core/natural-keys.html +131 -14
- nautobot/project-static/docs/development/core/navigation-menu.html +131 -14
- nautobot/project-static/docs/development/core/release-checklist.html +134 -17
- nautobot/project-static/docs/development/core/role-internals.html +131 -14
- nautobot/project-static/docs/development/core/settings.html +131 -14
- nautobot/project-static/docs/development/core/style-guide.html +134 -17
- nautobot/project-static/docs/development/core/templates.html +132 -15
- nautobot/project-static/docs/development/core/testing.html +131 -14
- nautobot/project-static/docs/development/core/ui-component-framework.html +454 -283
- nautobot/project-static/docs/development/core/user-preferences.html +131 -14
- nautobot/project-static/docs/development/index.html +131 -14
- nautobot/project-static/docs/development/jobs/index.html +301 -132
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +131 -14
- nautobot/project-static/docs/index.html +139 -33
- 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/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +132 -17
- nautobot/project-static/docs/overview/design_philosophy.html +131 -14
- nautobot/project-static/docs/release-notes/index.html +137 -22
- nautobot/project-static/docs/release-notes/version-1.0.html +319 -203
- nautobot/project-static/docs/release-notes/version-1.1.html +316 -200
- nautobot/project-static/docs/release-notes/version-1.2.html +391 -275
- nautobot/project-static/docs/release-notes/version-1.3.html +417 -301
- nautobot/project-static/docs/release-notes/version-1.4.html +502 -387
- nautobot/project-static/docs/release-notes/version-1.5.html +690 -576
- nautobot/project-static/docs/release-notes/version-1.6.html +989 -457
- nautobot/project-static/docs/release-notes/version-2.0.html +613 -499
- nautobot/project-static/docs/release-notes/version-2.1.html +448 -334
- nautobot/project-static/docs/release-notes/version-2.2.html +441 -327
- nautobot/project-static/docs/release-notes/version-2.3.html +1171 -451
- nautobot/project-static/docs/release-notes/version-2.4.html +800 -111
- nautobot/project-static/docs/requirements.txt +2 -2
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +303 -287
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +133 -16
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +131 -14
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +195 -18
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +134 -17
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +131 -14
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +133 -16
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +151 -18
- nautobot/project-static/docs/user-guide/administration/installation/index.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +132 -15
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +131 -14
- nautobot/project-static/docs/user-guide/administration/installation/services.html +131 -14
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +131 -14
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +131 -14
- nautobot/project-static/docs/user-guide/administration/security/index.html +9420 -0
- nautobot/project-static/docs/user-guide/administration/security/notices.html +9843 -0
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +131 -14
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +134 -18
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +131 -14
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +135 -22
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +134 -17
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +131 -14
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +134 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +236 -34
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +131 -14
- 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/ip-address-merge-tool.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +131 -14
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +134 -17
- nautobot/project-static/docs/{development/core/local-k8s.html → user-guide/feature-guides/wireless-networks-and-controllers.html} +632 -566
- nautobot/project-static/docs/user-guide/index.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +135 -18
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +451 -16
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +135 -17
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +134 -17
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9797 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +132 -15
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +179 -35
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +159 -15
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +131 -14
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +131 -14
- nautobot/project-static/js/forms.js +1 -1
- nautobot/tenancy/api/views.py +9 -13
- nautobot/tenancy/templates/tenancy/tenant.html +1 -2
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/views.py +4 -2
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +5 -4
- nautobot/users/api/views.py +3 -3
- nautobot/virtualization/api/serializers.py +4 -4
- nautobot/virtualization/api/views.py +5 -24
- nautobot/virtualization/filters.py +20 -3
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster.html +1 -1
- nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
- nautobot/virtualization/templates/virtualization/clustergroup.html +1 -1
- nautobot/virtualization/templates/virtualization/clustertype.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -10
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
- nautobot/virtualization/templates/virtualization/vminterface.html +1 -1
- nautobot/virtualization/tests/test_filters.py +17 -0
- nautobot/wireless/filters.py +2 -2
- nautobot/wireless/forms.py +1 -1
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +1 -9
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
- nautobot/wireless/tests/test_filters.py +29 -1
- nautobot/wireless/tests/test_views.py +22 -1
- nautobot/wireless/views.py +0 -10
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/METADATA +9 -9
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/RECORD +667 -610
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/WHEEL +1 -1
- nautobot/core/fixtures/user-data.json +0 -59
- /nautobot/project-static/docs/assets/stylesheets/{main.6f8fc17f.min.css.map → main.a40c8224.min.css.map} +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/NOTICE +0 -0
- {nautobot-2.4.0b1.dist-info → nautobot-2.4.2.dist-info}/entry_points.txt +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
from unittest import mock
|
|
1
2
|
import uuid
|
|
2
3
|
|
|
3
4
|
from django import forms as django_forms
|
|
@@ -14,11 +15,13 @@ from nautobot.core.api import utils as api_utils
|
|
|
14
15
|
from nautobot.core.forms.utils import compress_range
|
|
15
16
|
from nautobot.core.models import fields as core_fields, utils as models_utils, validators
|
|
16
17
|
from nautobot.core.testing import TestCase
|
|
17
|
-
from nautobot.core.utils import data as data_utils, filtering, lookup, requests
|
|
18
|
+
from nautobot.core.utils import data as data_utils, filtering, lookup, querysets, requests
|
|
18
19
|
from nautobot.core.utils.migrations import update_object_change_ct_for_replaced_models
|
|
19
20
|
from nautobot.dcim import filters as dcim_filters, forms as dcim_forms, models as dcim_models, tables
|
|
20
21
|
from nautobot.extras import models as extras_models, utils as extras_utils
|
|
21
22
|
from nautobot.extras.choices import ObjectChangeActionChoices, RelationshipTypeChoices
|
|
23
|
+
from nautobot.extras.filters import StatusFilterSet
|
|
24
|
+
from nautobot.extras.forms import StatusForm
|
|
22
25
|
from nautobot.extras.models import ObjectChange
|
|
23
26
|
from nautobot.ipam import models as ipam_models
|
|
24
27
|
|
|
@@ -65,6 +68,18 @@ class NormalizeQueryDictTest(TestCase):
|
|
|
65
68
|
{"foo": "1", "bar": ["2", "3"], "baz": ""},
|
|
66
69
|
)
|
|
67
70
|
|
|
71
|
+
self.assertDictEqual(
|
|
72
|
+
requests.normalize_querydict(QueryDict("name=Sample Status&content_types=1"), form_class=StatusForm),
|
|
73
|
+
{"name": "Sample Status", "content_types": ["1"]},
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
self.assertDictEqual(
|
|
77
|
+
requests.normalize_querydict(
|
|
78
|
+
QueryDict("name=Sample Status&content_types=dcim.device"), filterset=StatusFilterSet()
|
|
79
|
+
),
|
|
80
|
+
{"name": ["Sample Status"], "content_types": ["dcim.device"]},
|
|
81
|
+
)
|
|
82
|
+
|
|
68
83
|
|
|
69
84
|
class DeepMergeTest(TestCase):
|
|
70
85
|
"""
|
|
@@ -267,6 +282,14 @@ class GetFooForModelTest(TestCase):
|
|
|
267
282
|
lookup.get_model_for_view_name("unknown:plugins:example_app:examplemodel_list")
|
|
268
283
|
self.assertEqual(str(err.exception), "Unexpected View Name: unknown:plugins:example_app:examplemodel_list")
|
|
269
284
|
|
|
285
|
+
def test_get_table_class_string_from_view_name(self):
|
|
286
|
+
# Testing UIViewSet
|
|
287
|
+
self.assertEqual(lookup.get_table_class_string_from_view_name("circuits:circuit_list"), "CircuitTable")
|
|
288
|
+
# Testing Legacy View
|
|
289
|
+
self.assertEqual(lookup.get_table_class_string_from_view_name("dcim:location_list"), "LocationTable")
|
|
290
|
+
# Testing unconventional table name
|
|
291
|
+
self.assertEqual(lookup.get_table_class_string_from_view_name("ipam:prefix_list"), "PrefixDetailTable")
|
|
292
|
+
|
|
270
293
|
|
|
271
294
|
class IsTaggableTest(TestCase):
|
|
272
295
|
def test_is_taggable_true(self):
|
|
@@ -908,3 +931,42 @@ class TestMigrationUtils(TestCase):
|
|
|
908
931
|
)
|
|
909
932
|
self.assertEqual(ObjectChange.objects.get(request_id=request_id).changed_object_type, location_ct)
|
|
910
933
|
self.assertEqual(ObjectChange.objects.get(request_id=request_id).related_object_type, location_ct)
|
|
934
|
+
|
|
935
|
+
|
|
936
|
+
class TestQuerySetUtils(TestCase):
|
|
937
|
+
def test_maybe_select_related(self):
|
|
938
|
+
# If possible, select_related should be called
|
|
939
|
+
queryset = ipam_models.IPAddress.objects.all()
|
|
940
|
+
with mock.patch.object(queryset, "select_related", wraps=queryset.select_related) as mock_select_related:
|
|
941
|
+
new_queryset = querysets.maybe_select_related(queryset, ["parent", "status"])
|
|
942
|
+
mock_select_related.assert_called_with("parent", "status")
|
|
943
|
+
self.assertIsNot(new_queryset, queryset)
|
|
944
|
+
|
|
945
|
+
# Case where it shouldn't be called
|
|
946
|
+
queryset = ipam_models.IPAddress.objects.values_list("host", flat=True)
|
|
947
|
+
with mock.patch.object(queryset, "select_related", wraps=queryset.select_related) as mock_select_related:
|
|
948
|
+
new_queryset = querysets.maybe_select_related(queryset, ["parent", "status"])
|
|
949
|
+
mock_select_related.assert_not_called()
|
|
950
|
+
self.assertIs(new_queryset, queryset)
|
|
951
|
+
|
|
952
|
+
# Another case where it shouldn't be called
|
|
953
|
+
queryset = ipam_models.IPAddress.objects.difference(ipam_models.IPAddress.objects.filter(ip_version=4))
|
|
954
|
+
with mock.patch.object(queryset, "select_related", wraps=queryset.select_related) as mock_select_related:
|
|
955
|
+
new_queryset = querysets.maybe_select_related(queryset, ["parent", "status"])
|
|
956
|
+
mock_select_related.assert_not_called()
|
|
957
|
+
self.assertIs(new_queryset, queryset)
|
|
958
|
+
|
|
959
|
+
def test_maybe_prefetch_related(self):
|
|
960
|
+
# If possible, prefetch_related should be called
|
|
961
|
+
queryset = ipam_models.IPAddress.objects.all()
|
|
962
|
+
with mock.patch.object(queryset, "prefetch_related", wraps=queryset.prefetch_related) as mock_prefetch_related:
|
|
963
|
+
new_queryset = querysets.maybe_prefetch_related(queryset, ["nat_outside_list"])
|
|
964
|
+
mock_prefetch_related.assert_called_with("nat_outside_list")
|
|
965
|
+
self.assertIsNot(new_queryset, queryset)
|
|
966
|
+
|
|
967
|
+
# Case where it shouldn't be called
|
|
968
|
+
queryset = ipam_models.IPAddress.objects.difference(ipam_models.IPAddress.objects.filter(ip_version=4))
|
|
969
|
+
with mock.patch.object(queryset, "prefetch_related", wraps=queryset.prefetch_related) as mock_prefetch_related:
|
|
970
|
+
new_queryset = querysets.maybe_prefetch_related(queryset, ["nat_outside_list"])
|
|
971
|
+
mock_prefetch_related.assert_not_called()
|
|
972
|
+
self.assertIs(new_queryset, queryset)
|
|
@@ -664,9 +664,7 @@ class ExampleViewWithCustomPermissionsTest(TestCase):
|
|
|
664
664
|
self.user.is_staff = True
|
|
665
665
|
self.user.save()
|
|
666
666
|
response = self.client.get(url)
|
|
667
|
-
self.
|
|
668
|
-
response_body = response.content.decode(response.charset)
|
|
669
|
-
self.assertIn("You are viewing a table of example models", response_body)
|
|
667
|
+
self.assertBodyContains(response, "You are viewing a table of example models")
|
|
670
668
|
|
|
671
669
|
|
|
672
670
|
class TestObjectDetailView(TestCase):
|
|
@@ -715,3 +713,32 @@ class TestObjectDetailView(TestCase):
|
|
|
715
713
|
self.assertInHTML(name_copy, response_data)
|
|
716
714
|
# ASN do not have a value, therefore no copy btn
|
|
717
715
|
self.assertNotIn("#asn_copy", response_data)
|
|
716
|
+
|
|
717
|
+
|
|
718
|
+
class SearchRobotsTestCase(TestCase):
|
|
719
|
+
def test_robots_disallowed(self):
|
|
720
|
+
"""
|
|
721
|
+
Test that the robots.txt file is accessible to all users and defaults to disallowing all bots.
|
|
722
|
+
"""
|
|
723
|
+
url = reverse("robots_txt")
|
|
724
|
+
response = self.client.get(url)
|
|
725
|
+
self.assertHttpStatus(response, 200)
|
|
726
|
+
self.assertBodyContains(response, "User-Agent: *")
|
|
727
|
+
self.assertBodyContains(response, "Disallow: /")
|
|
728
|
+
|
|
729
|
+
url = reverse("home")
|
|
730
|
+
response = self.client.get(url)
|
|
731
|
+
self.assertContains(response, '<meta name="robots" content="noindex, nofollow">', html=True)
|
|
732
|
+
|
|
733
|
+
@override_settings(PUBLISH_ROBOTS_TXT=False)
|
|
734
|
+
def test_robots_allowed(self):
|
|
735
|
+
"""
|
|
736
|
+
Test that the robots.txt file is not published if PUBLISH_ROBOTS_TXT is set to False.
|
|
737
|
+
"""
|
|
738
|
+
url = reverse("robots_txt")
|
|
739
|
+
response = self.client.get(url)
|
|
740
|
+
self.assertHttpStatus(response, 404)
|
|
741
|
+
|
|
742
|
+
url = reverse("home")
|
|
743
|
+
response = self.client.get(url)
|
|
744
|
+
self.assertNotContains(response, '<meta name="robots" content="noindex, nofollow">', html=True)
|
nautobot/core/ui/nav.py
CHANGED
|
@@ -119,6 +119,7 @@ class NavMenuGroup(NavMenuBase, PermissionsMixin):
|
|
|
119
119
|
elif not all(isinstance(item, NavMenuItem) for item in items):
|
|
120
120
|
raise TypeError("All items defined in a group must be an instance of NavMenuItem")
|
|
121
121
|
self.items = items
|
|
122
|
+
super().__init__(permissions=self.permissions)
|
|
122
123
|
|
|
123
124
|
|
|
124
125
|
class NavMenuItem(NavMenuBase, PermissionsMixin):
|
|
@@ -586,7 +586,21 @@ class DataTablePanel(Panel):
|
|
|
586
586
|
|
|
587
587
|
|
|
588
588
|
class ObjectsTablePanel(Panel):
|
|
589
|
-
"""A panel that renders a Table of objects (typically related objects, rather than the "main" object of a view).
|
|
589
|
+
"""A panel that renders a Table of objects (typically related objects, rather than the "main" object of a view).
|
|
590
|
+
Has built-in pagination support and "Add" button at bottom of the Table.
|
|
591
|
+
|
|
592
|
+
It renders the django-tables2 classes with Nautobot additions. You can pass the instance of Table Class
|
|
593
|
+
already configured in context and set the `context_table_key` or pass a Table Class to `__init__` via `table_class`.
|
|
594
|
+
|
|
595
|
+
When `table_class` is set, you need to pass `table_filter` or `table_attribute` for fetching data purpose.
|
|
596
|
+
|
|
597
|
+
Data fetching can be optimized by using `select_related_fields`, `prefetch_related_fields`.
|
|
598
|
+
|
|
599
|
+
How Table is displayed can be changed by using `include_columns`, `exclude_columns`, `table_title`,
|
|
600
|
+
`hide_hierarchy_ui`, `related_field_name` or `enable_bulk_actions`.
|
|
601
|
+
|
|
602
|
+
Please check the Args list for further details.
|
|
603
|
+
"""
|
|
590
604
|
|
|
591
605
|
def __init__(
|
|
592
606
|
self,
|
nautobot/core/urls.py
CHANGED
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
from django.conf import settings
|
|
2
|
+
from django.http import HttpResponse, HttpResponseNotFound
|
|
2
3
|
from django.urls import include, path
|
|
3
4
|
from django.views.generic import TemplateView
|
|
4
5
|
from django.views.static import serve
|
|
5
6
|
|
|
6
7
|
from nautobot.core.views import (
|
|
8
|
+
AboutView,
|
|
7
9
|
CustomGraphQLView,
|
|
8
10
|
get_file_with_authorization,
|
|
9
11
|
HomeView,
|
|
@@ -27,6 +29,7 @@ from .admin import admin_site
|
|
|
27
29
|
urlpatterns = [
|
|
28
30
|
# Base views
|
|
29
31
|
path("", HomeView.as_view(), name="home"),
|
|
32
|
+
path("about/", AboutView.as_view(), name="about"),
|
|
30
33
|
path("search/", SearchView.as_view(), name="search"),
|
|
31
34
|
# Login/logout
|
|
32
35
|
path("login/", LoginView.as_view(), name="login"),
|
|
@@ -76,6 +79,14 @@ urlpatterns = [
|
|
|
76
79
|
path(
|
|
77
80
|
"template.css", TemplateView.as_view(template_name="template.css", content_type="text/css"), name="template_css"
|
|
78
81
|
),
|
|
82
|
+
# The response is conditional as opposed to wrapping the path() call in an if statement to be able to test the setting with current test setup
|
|
83
|
+
path(
|
|
84
|
+
"robots.txt",
|
|
85
|
+
lambda x: HttpResponse("User-Agent: *\nDisallow: /", content_type="text/plain")
|
|
86
|
+
if settings.PUBLISH_ROBOTS_TXT
|
|
87
|
+
else HttpResponseNotFound(),
|
|
88
|
+
name="robots_txt",
|
|
89
|
+
),
|
|
79
90
|
]
|
|
80
91
|
|
|
81
92
|
|
nautobot/core/utils/git.py
CHANGED
|
@@ -57,7 +57,7 @@ class BranchDoesNotExist(Exception):
|
|
|
57
57
|
|
|
58
58
|
|
|
59
59
|
class GitRepo:
|
|
60
|
-
def __init__(self, path, url, clone_initially=True):
|
|
60
|
+
def __init__(self, path, url, clone_initially=True, branch=None, depth=0):
|
|
61
61
|
"""
|
|
62
62
|
Ensure that we have a clone of the given remote Git repository URL at the given local directory path.
|
|
63
63
|
|
|
@@ -65,6 +65,8 @@ class GitRepo:
|
|
|
65
65
|
path (str): path to git repo
|
|
66
66
|
url (str): git repo url
|
|
67
67
|
clone_initially (bool): True if the repo needs to be cloned
|
|
68
|
+
branch (str): branch to checkout
|
|
69
|
+
depth (int): depth of the clone
|
|
68
70
|
"""
|
|
69
71
|
self.url = url
|
|
70
72
|
self.sanitized_url = sanitize(url)
|
|
@@ -73,7 +75,10 @@ class GitRepo:
|
|
|
73
75
|
elif clone_initially:
|
|
74
76
|
# Don't log `url` as it may include authentication details.
|
|
75
77
|
logger.debug("Cloning git repository to %s...", path)
|
|
76
|
-
|
|
78
|
+
if not depth:
|
|
79
|
+
self.repo = Repo.clone_from(url, to_path=path, env=GIT_ENVIRONMENT, branch=branch)
|
|
80
|
+
else:
|
|
81
|
+
self.repo = Repo.clone_from(url, to_path=path, env=GIT_ENVIRONMENT, branch=branch, depth=depth)
|
|
77
82
|
else:
|
|
78
83
|
self.repo = Repo.init(path)
|
|
79
84
|
self.repo.create_remote("origin", url=url)
|
nautobot/core/utils/lookup.py
CHANGED
|
@@ -8,7 +8,7 @@ from django.conf import settings
|
|
|
8
8
|
from django.contrib.auth.models import Group
|
|
9
9
|
from django.contrib.contenttypes.models import ContentType
|
|
10
10
|
from django.db.models import Model
|
|
11
|
-
from django.urls import get_resolver, URLPattern, URLResolver
|
|
11
|
+
from django.urls import get_resolver, resolve, reverse, URLPattern, URLResolver
|
|
12
12
|
from django.utils.module_loading import import_string
|
|
13
13
|
from django.views.generic.base import RedirectView
|
|
14
14
|
|
|
@@ -213,7 +213,7 @@ def get_related_field_for_models(from_model, to_model):
|
|
|
213
213
|
return matching_field
|
|
214
214
|
|
|
215
215
|
|
|
216
|
-
def get_table_for_model(model):
|
|
216
|
+
def get_table_for_model(model, suffix=None):
|
|
217
217
|
"""Return the `Table` class associated with a given `model`.
|
|
218
218
|
|
|
219
219
|
The `Table` class is expected to be in the `tables` module within the application
|
|
@@ -223,11 +223,12 @@ def get_table_for_model(model):
|
|
|
223
223
|
|
|
224
224
|
Args:
|
|
225
225
|
model (BaseModel): A model class
|
|
226
|
+
suffix (str): A replacement suffix for the table name (e.g. `DetailTable`, such as to retrieve `FooDetailTable`)
|
|
226
227
|
|
|
227
228
|
Returns:
|
|
228
229
|
(Union[Table, None]): Either the `Table` class or `None`
|
|
229
230
|
"""
|
|
230
|
-
return get_related_class_for_model(model, module_name="tables", object_suffix="Table")
|
|
231
|
+
return get_related_class_for_model(model, module_name="tables", object_suffix=suffix or "Table")
|
|
231
232
|
|
|
232
233
|
|
|
233
234
|
def get_view_for_model(model, view_type=""):
|
|
@@ -276,11 +277,13 @@ def get_table_class_string_from_view_name(view_name):
|
|
|
276
277
|
Returns:
|
|
277
278
|
table_class_name (String): The name of the model table class or None e.g. LocationTable, CircuitTable
|
|
278
279
|
"""
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
280
|
+
|
|
281
|
+
view_func = resolve(reverse(view_name)).func
|
|
282
|
+
view_class = getattr(view_func, "cls", getattr(view_func, "view_class", None))
|
|
283
|
+
if hasattr(view_class, "table_class"):
|
|
284
|
+
return view_class.table_class.__name__
|
|
285
|
+
if hasattr(view_class, "table"):
|
|
286
|
+
return view_class.table.__name__
|
|
284
287
|
return None
|
|
285
288
|
|
|
286
289
|
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import logging
|
|
2
|
+
|
|
3
|
+
from django.db import NotSupportedError
|
|
4
|
+
|
|
5
|
+
logger = logging.getLogger(__name__)
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def maybe_select_related(queryset, select_fields):
|
|
9
|
+
"""Attempt to perform a select_related() on the given queryset, but fail gracefully if not permitted."""
|
|
10
|
+
model = queryset.model
|
|
11
|
+
|
|
12
|
+
# Django doesn't allow .select_related() on a QuerySet that had .values()/.values_list() applied, or
|
|
13
|
+
# one that has had union()/intersection()/difference() applied.
|
|
14
|
+
# We can detect and avoid these cases the same way that Django itself does.
|
|
15
|
+
if queryset._fields is not None:
|
|
16
|
+
logger.debug(
|
|
17
|
+
"NOT applying select_related(%s) to %s QuerySet as it includes .values()/.values_list()",
|
|
18
|
+
select_fields,
|
|
19
|
+
model.__name__,
|
|
20
|
+
)
|
|
21
|
+
elif queryset.query.combinator:
|
|
22
|
+
logger.debug(
|
|
23
|
+
"NOT applying select_related(%s) to %s QuerySet as it is a combinator query",
|
|
24
|
+
select_fields,
|
|
25
|
+
model.__name__,
|
|
26
|
+
)
|
|
27
|
+
else:
|
|
28
|
+
logger.debug("Applying .select_related(%s) to %s QuerySet", select_fields, model.__name__)
|
|
29
|
+
# Belt and suspenders - we should have avoided any error cases above, but be safe anyway:
|
|
30
|
+
try:
|
|
31
|
+
queryset = queryset.select_related(*select_fields)
|
|
32
|
+
except (TypeError, ValueError, NotSupportedError) as exc:
|
|
33
|
+
logger.warning(
|
|
34
|
+
"Unexpected error when trying to .select_related() on %s QuerySet: %s",
|
|
35
|
+
model.__name__,
|
|
36
|
+
exc,
|
|
37
|
+
)
|
|
38
|
+
|
|
39
|
+
return queryset
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
def maybe_prefetch_related(queryset, prefetch_fields):
|
|
43
|
+
"""Attempt to perform a select_related() on the given queryset, but fail gracefully if not permitted."""
|
|
44
|
+
model = queryset.model
|
|
45
|
+
|
|
46
|
+
if queryset.query.combinator:
|
|
47
|
+
logger.debug(
|
|
48
|
+
"NOT applying prefetch_related(%s) to %s QuerySet as it is a combinator query",
|
|
49
|
+
prefetch_fields,
|
|
50
|
+
model.__name__,
|
|
51
|
+
)
|
|
52
|
+
else:
|
|
53
|
+
logger.debug("Applying .prefetch_related(%s) to %s QuerySet", prefetch_fields, model.__name__)
|
|
54
|
+
# Belt and suspenders - we should have avoided any error cases above, but be safe anyway:
|
|
55
|
+
try:
|
|
56
|
+
queryset = queryset.prefetch_related(*prefetch_fields)
|
|
57
|
+
except (AttributeError, TypeError, ValueError, NotSupportedError) as exc:
|
|
58
|
+
logger.warning(
|
|
59
|
+
"Unexpected error when trying to .prefetch_related() on %s QuerySet: %s",
|
|
60
|
+
model.__name__,
|
|
61
|
+
exc,
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
return queryset
|
nautobot/core/utils/requests.py
CHANGED
|
@@ -141,22 +141,35 @@ def get_filterable_params_from_filter_params(filter_params, non_filter_params, f
|
|
|
141
141
|
return final_filter_params
|
|
142
142
|
|
|
143
143
|
|
|
144
|
-
def normalize_querydict(querydict, form_class=None):
|
|
144
|
+
def normalize_querydict(querydict, form_class=None, filterset=None):
|
|
145
145
|
"""
|
|
146
|
-
|
|
146
|
+
Converts a QueryDict into a standard, mutable dictionary while preserving multiple values as lists.
|
|
147
147
|
|
|
148
|
-
|
|
148
|
+
Example:
|
|
149
|
+
A QueryDict like:
|
|
150
|
+
QueryDict('foo=1&bar=2&bar=3&baz=')
|
|
149
151
|
|
|
150
|
-
|
|
152
|
+
Converts to:
|
|
153
|
+
{'foo': '1', 'bar': ['2', '3'], 'baz': ''}
|
|
151
154
|
|
|
152
|
-
|
|
155
|
+
This function ensures that fields with multiple values are handled correctly, as QueryDict
|
|
156
|
+
does not inherently preserve multiple values as lists.
|
|
153
157
|
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
+
Args:
|
|
159
|
+
querydict (QueryDict): The QueryDict to be normalized.
|
|
160
|
+
form_class (forms.Form, optional): A form class to identify fields that should be treated as
|
|
161
|
+
lists (e.g., `MultipleChoiceField` or `ModelMultipleChoiceField`).
|
|
162
|
+
filterset (django_filters.FilterSet, optional): A FilterSet instance to identify filters that
|
|
163
|
+
should preserve multiple values as lists (e.g., non-single-choice fields).
|
|
164
|
+
|
|
165
|
+
Raises:
|
|
166
|
+
AttributeError: If both `form_class` and `filterset` are provided.
|
|
158
167
|
"""
|
|
168
|
+
if form_class and filterset:
|
|
169
|
+
raise AttributeError("Either form_class or filterset_class is to be provided not both")
|
|
170
|
+
|
|
159
171
|
result = {}
|
|
172
|
+
|
|
160
173
|
if querydict:
|
|
161
174
|
for key, value_list in querydict.lists():
|
|
162
175
|
if len(value_list) > 1:
|
|
@@ -171,6 +184,8 @@ def normalize_querydict(querydict, form_class=None):
|
|
|
171
184
|
):
|
|
172
185
|
# Even though there's only a single value in the querydict for this key, the form wants it as a list
|
|
173
186
|
result[key] = value_list
|
|
187
|
+
elif filterset is not None and filterset.filters.get(key) and not is_single_choice_field(filterset, key):
|
|
188
|
+
result[key] = value_list
|
|
174
189
|
else:
|
|
175
190
|
# Only a single value in the querydict for this key, and no guidance otherwise, so make it single
|
|
176
191
|
result[key] = value_list[0]
|
nautobot/core/views/__init__.py
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import contextlib
|
|
2
|
+
import datetime
|
|
2
3
|
import logging
|
|
3
4
|
import os
|
|
4
5
|
import platform
|
|
@@ -45,6 +46,7 @@ from nautobot.core.celery import app
|
|
|
45
46
|
from nautobot.core.constants import SEARCH_MAX_RESULTS
|
|
46
47
|
from nautobot.core.forms import SearchForm
|
|
47
48
|
from nautobot.core.releases import get_latest_release
|
|
49
|
+
from nautobot.core.utils.config import get_settings_or_config
|
|
48
50
|
from nautobot.core.utils.lookup import get_route_for_model
|
|
49
51
|
from nautobot.core.utils.permissions import get_permission_for_model
|
|
50
52
|
from nautobot.extras.forms import GraphQLQueryForm
|
|
@@ -480,6 +482,46 @@ def get_file_with_authorization(request, *args, **kwargs):
|
|
|
480
482
|
return get_file(request, *args, **kwargs)
|
|
481
483
|
|
|
482
484
|
|
|
485
|
+
class AboutView(AccessMixin, TemplateView):
|
|
486
|
+
"""
|
|
487
|
+
Nautobot About View which displays general information about Nautobot and contact details
|
|
488
|
+
for Network to Code.
|
|
489
|
+
"""
|
|
490
|
+
|
|
491
|
+
template_name = "about.html"
|
|
492
|
+
|
|
493
|
+
def get(self, request, *args, **kwargs):
|
|
494
|
+
# Redirect user to login page if not authenticated
|
|
495
|
+
if not request.user.is_authenticated:
|
|
496
|
+
return self.handle_no_permission()
|
|
497
|
+
# Check whether a new release is available. (Only for staff/superusers.)
|
|
498
|
+
new_release = None
|
|
499
|
+
if request.user.is_staff or request.user.is_superuser:
|
|
500
|
+
latest_release, release_url = get_latest_release()
|
|
501
|
+
if isinstance(latest_release, version.Version):
|
|
502
|
+
current_version = version.parse(settings.VERSION)
|
|
503
|
+
if latest_release > current_version:
|
|
504
|
+
new_release = {
|
|
505
|
+
"version": str(latest_release),
|
|
506
|
+
"url": release_url,
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
# Support contract state
|
|
510
|
+
support_expiration_date = get_settings_or_config("NTC_SUPPORT_CONTRACT_EXPIRATION_DATE")
|
|
511
|
+
support_contract_active = support_expiration_date and support_expiration_date >= datetime.date.today()
|
|
512
|
+
|
|
513
|
+
context = self.get_context_data()
|
|
514
|
+
context.update(
|
|
515
|
+
{
|
|
516
|
+
"new_release": new_release,
|
|
517
|
+
"support_contract_active": support_contract_active,
|
|
518
|
+
"support_expiration_date": support_expiration_date,
|
|
519
|
+
}
|
|
520
|
+
)
|
|
521
|
+
|
|
522
|
+
return self.render_to_response(context)
|
|
523
|
+
|
|
524
|
+
|
|
483
525
|
class RenderJinjaView(LoginRequiredMixin, TemplateView):
|
|
484
526
|
"""Render a Jinja template with context data."""
|
|
485
527
|
|