nautobot 2.0.0a2__py3-none-any.whl → 2.0.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.
- nautobot/__init__.py +1 -5
- nautobot/apps/api.py +6 -8
- nautobot/apps/forms.py +0 -2
- nautobot/apps/ui.py +0 -8
- nautobot/circuits/api/serializers.py +9 -119
- nautobot/circuits/api/urls.py +1 -1
- nautobot/circuits/api/views.py +0 -1
- nautobot/circuits/choices.py +0 -2
- nautobot/circuits/filters.py +7 -6
- nautobot/circuits/forms.py +3 -73
- nautobot/circuits/migrations/0001_initial_part_1.py +0 -1
- nautobot/circuits/migrations/0002_initial_part_2.py +0 -1
- nautobot/circuits/migrations/0003_auto_slug.py +0 -1
- nautobot/circuits/migrations/0004_increase_provider_account_length.py +0 -1
- nautobot/circuits/migrations/0005_providernetwork.py +0 -1
- nautobot/circuits/migrations/0006_cache_circuit_terminations.py +0 -1
- nautobot/circuits/migrations/0007_circuitterminations_primary_model.py +0 -1
- nautobot/circuits/migrations/0008_add_natural_indexing.py +0 -1
- nautobot/circuits/migrations/0009_circuittermination_location.py +0 -1
- nautobot/circuits/migrations/0010_rename_foreign_keys_and_related_names.py +0 -1
- nautobot/circuits/migrations/0011_remove_site_foreign_key_from_circuit_termination_class.py +0 -1
- nautobot/circuits/migrations/0012_created_datetime.py +0 -1
- nautobot/circuits/migrations/0013_alter_circuittermination__path.py +0 -1
- nautobot/circuits/migrations/0014_related_name_changes.py +1 -2
- nautobot/circuits/migrations/0015_remove_circuittype_provider_slug.py +20 -0
- nautobot/circuits/migrations/0016_tagsfield.py +34 -0
- nautobot/circuits/migrations/0017_fixup_null_statuses.py +22 -0
- nautobot/circuits/migrations/0018_status_nonnullable.py +22 -0
- nautobot/circuits/models.py +3 -93
- nautobot/circuits/navigation.py +14 -69
- nautobot/circuits/signals.py +0 -2
- nautobot/circuits/tables.py +42 -5
- nautobot/circuits/templates/circuits/circuit_retrieve.html +1 -1
- nautobot/circuits/templates/circuits/circuittermination_retrieve.html +1 -1
- nautobot/circuits/templates/circuits/circuittype_retrieve.html +1 -1
- nautobot/circuits/templates/circuits/provider_create.html +0 -1
- nautobot/circuits/templates/circuits/provider_retrieve.html +1 -1
- nautobot/circuits/tests/integration/test_relationships.py +13 -16
- nautobot/circuits/tests/test_api.py +13 -43
- nautobot/circuits/tests/test_filters.py +20 -15
- nautobot/circuits/tests/test_models.py +7 -3
- nautobot/circuits/tests/test_views.py +57 -67
- nautobot/circuits/views.py +18 -9
- nautobot/core/api/__init__.py +8 -2
- nautobot/core/api/authentication.py +0 -3
- nautobot/core/api/fields.py +15 -6
- nautobot/core/api/filter_backends.py +3 -2
- nautobot/core/api/metadata.py +237 -30
- nautobot/core/api/mixins.py +94 -0
- nautobot/core/api/pagination.py +3 -3
- nautobot/core/api/parsers.py +154 -0
- nautobot/core/api/renderers.py +153 -2
- nautobot/core/api/schema.py +47 -3
- nautobot/core/api/serializers.py +377 -37
- nautobot/core/api/urls.py +11 -3
- nautobot/core/api/utils.py +174 -2
- nautobot/core/api/versioning.py +32 -10
- nautobot/core/api/views.py +266 -75
- nautobot/core/apps/__init__.py +138 -221
- nautobot/core/celery/__init__.py +112 -41
- nautobot/core/celery/backends.py +19 -13
- nautobot/core/celery/control.py +46 -0
- nautobot/core/celery/encoders.py +53 -0
- nautobot/core/celery/log.py +38 -0
- nautobot/core/celery/schedulers.py +23 -4
- nautobot/core/celery/task.py +1 -16
- nautobot/core/checks.py +0 -27
- nautobot/core/choices.py +21 -113
- nautobot/core/{cli.py → cli/__init__.py} +1 -2
- nautobot/core/cli/__main__.py +3 -0
- nautobot/core/constants.py +25 -43
- nautobot/core/context_processors.py +12 -0
- nautobot/core/filters.py +2 -2
- nautobot/core/forms/__init__.py +0 -4
- nautobot/core/forms/fields.py +39 -68
- nautobot/core/forms/forms.py +27 -27
- nautobot/core/forms/utils.py +7 -59
- nautobot/core/forms/widgets.py +0 -1
- nautobot/core/graphql/__init__.py +2 -2
- nautobot/core/graphql/schema.py +4 -27
- nautobot/core/jobs/__init__.py +75 -0
- nautobot/core/management/commands/build_ui.py +255 -0
- nautobot/core/management/commands/celery.py +0 -1
- nautobot/core/management/commands/generate_test_data.py +18 -13
- nautobot/core/management/commands/post_upgrade.py +24 -24
- nautobot/core/management/commands/validate_models.py +0 -1
- nautobot/core/middleware.py +0 -1
- nautobot/core/models/__init__.py +26 -1
- nautobot/core/models/fields.py +24 -5
- nautobot/core/models/generics.py +2 -46
- nautobot/core/models/managers.py +5 -0
- nautobot/core/models/name_color_content_types.py +1 -19
- nautobot/core/models/tree_queries.py +14 -4
- nautobot/core/models/utils.py +9 -10
- nautobot/core/models/validators.py +17 -8
- nautobot/core/releases.py +8 -10
- nautobot/core/settings.py +81 -53
- nautobot/core/tables.py +5 -5
- nautobot/core/tasks.py +4 -7
- nautobot/core/templates/base.html +1 -49
- nautobot/core/templates/base_django.html +49 -0
- nautobot/core/templates/base_react.html +55 -0
- nautobot/core/templates/buttons/export.html +6 -4
- nautobot/core/templates/generic/object_bulk_create.html +10 -21
- nautobot/core/templates/generic/object_list.html +4 -1
- nautobot/core/templates/generic/object_retrieve_plugin_full_width.html +3 -0
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/javascript.html +0 -14
- nautobot/core/templates/inc/nav_menu.html +28 -33
- nautobot/core/templates/inc/object_details_advanced_panel.html +13 -0
- nautobot/core/templates/inc/relationships_table_rows.html +2 -2
- nautobot/core/templates/nautobot_config.py.j2 +8 -25
- nautobot/core/templates/plugin_template/__init__.py-tpl +1 -2
- nautobot/core/templates/rest_framework/api.html +8 -0
- nautobot/core/templatetags/buttons.py +32 -29
- nautobot/core/templatetags/helpers.py +1 -1
- nautobot/core/testing/__init__.py +47 -44
- nautobot/core/testing/api.py +365 -47
- nautobot/core/testing/filters.py +12 -7
- nautobot/core/testing/integration.py +1 -1
- nautobot/core/testing/migrations.py +2 -0
- nautobot/core/testing/mixins.py +22 -12
- nautobot/core/testing/schema.py +2 -1
- nautobot/core/testing/views.py +28 -51
- nautobot/core/tests/integration/test_filters.py +17 -8
- nautobot/core/tests/integration/test_navbar.py +11 -34
- nautobot/core/tests/integration/test_plugin_navbar.py +9 -103
- nautobot/core/tests/nautobot_config.py +2 -3
- nautobot/core/tests/runner.py +0 -1
- nautobot/core/tests/test_api.py +290 -24
- nautobot/core/tests/test_authentication.py +57 -14
- nautobot/core/tests/test_checks.py +0 -7
- nautobot/core/tests/test_choices.py +0 -1
- nautobot/core/tests/test_filters.py +117 -110
- nautobot/core/tests/test_forms.py +47 -110
- nautobot/core/tests/test_graphql.py +158 -135
- nautobot/core/tests/test_logging.py +4 -1
- nautobot/core/tests/test_managers.py +3 -5
- nautobot/core/tests/test_models.py +2 -0
- nautobot/core/tests/test_ordering.py +0 -2
- nautobot/core/tests/test_paginator.py +3 -1
- nautobot/core/tests/test_releases.py +12 -12
- nautobot/core/tests/test_templatetags_helpers.py +7 -4
- nautobot/core/tests/test_utils.py +112 -78
- nautobot/core/tests/test_views.py +12 -17
- nautobot/core/tests/test_views_utils.py +6 -9
- nautobot/core/utils/data.py +17 -0
- nautobot/core/utils/deprecation.py +13 -20
- nautobot/core/utils/filtering.py +53 -9
- nautobot/core/utils/git.py +12 -4
- nautobot/core/utils/lookup.py +3 -1
- nautobot/core/utils/requests.py +23 -116
- nautobot/core/views/__init__.py +1 -2
- nautobot/core/views/generic.py +131 -119
- nautobot/core/views/mixins.py +53 -62
- nautobot/core/views/paginator.py +0 -1
- nautobot/core/views/renderers.py +14 -12
- nautobot/core/views/utils.py +87 -4
- nautobot/dcim/api/serializers.py +160 -672
- nautobot/dcim/api/urls.py +1 -1
- nautobot/dcim/api/views.py +7 -46
- nautobot/dcim/choices.py +2 -25
- nautobot/dcim/elevations.py +0 -1
- nautobot/dcim/factory.py +15 -4
- nautobot/dcim/filters/__init__.py +42 -13
- nautobot/dcim/form_mixins.py +1 -27
- nautobot/dcim/forms.py +58 -797
- nautobot/dcim/management/commands/trace_paths.py +0 -1
- nautobot/dcim/migrations/0001_initial_part_1.py +0 -1
- nautobot/dcim/migrations/0002_initial_part_2.py +0 -1
- nautobot/dcim/migrations/0003_initial_part_3.py +0 -1
- nautobot/dcim/migrations/0004_initial_part_4.py +0 -1
- nautobot/dcim/migrations/0005_device_local_context_schema.py +0 -1
- nautobot/dcim/migrations/0006_auto_slug.py +0 -1
- nautobot/dcim/migrations/0007_device_secrets_group.py +0 -1
- nautobot/dcim/migrations/0008_increase_all_serial_lengths.py +0 -1
- nautobot/dcim/migrations/0009_add_natural_indexing.py +0 -1
- nautobot/dcim/migrations/0010_interface_status.py +0 -1
- nautobot/dcim/migrations/0011_interface_status_data_migration.py +0 -1
- nautobot/dcim/migrations/0012_interface_parent_bridge.py +0 -1
- nautobot/dcim/migrations/0013_location_location_type.py +0 -1
- nautobot/dcim/migrations/0014_location_status_data_migration.py +0 -1
- nautobot/dcim/migrations/0015_device_components__changeloggedmodel.py +0 -1
- nautobot/dcim/migrations/0016_device_components__timestamp_data_migration.py +0 -1
- nautobot/dcim/migrations/0017_locationtype_nestable.py +0 -1
- nautobot/dcim/migrations/0018_device_redundancy_group.py +0 -1
- nautobot/dcim/migrations/0019_device_redundancy_group_data_migration.py +0 -1
- nautobot/dcim/migrations/0020_move_site_fields_to_location_model.py +0 -1
- nautobot/dcim/migrations/0021_mptt_to_tree_queries.py +0 -1
- nautobot/dcim/migrations/0022_interface_mac_address_data_migration.py +0 -1
- nautobot/dcim/migrations/0023_alter_interface_mac_address.py +0 -1
- nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -2
- nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -14
- nautobot/dcim/migrations/0026_rename_device_and_rack_role.py +0 -1
- nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -2
- nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -2
- nautobot/dcim/migrations/0029_add_tree_managers_and_foreign_keys_pre_data_migration.py +0 -1
- nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
- nautobot/dcim/migrations/0031_rename_path_end_point_related_name.py +0 -1
- nautobot/dcim/migrations/0032_remove_site_foreign_key_from_dcim_models.py +0 -1
- nautobot/dcim/migrations/0033_created_datetime.py +0 -1
- nautobot/dcim/migrations/0034_fixup_fks_and_related_names.py +0 -1
- nautobot/dcim/migrations/0035_related_name_changes.py +1 -2
- nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -2
- nautobot/dcim/migrations/0037_interface_ip_addresses_m2m.py +0 -1
- nautobot/dcim/migrations/0038_alter_location_managers.py +0 -1
- nautobot/dcim/migrations/0039_remove_slug.py +24 -0
- nautobot/dcim/migrations/0040_tagsfield.py +109 -0
- nautobot/dcim/migrations/0041_ipam__namespaces.py +25 -0
- nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
- nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
- nautobot/dcim/models/cables.py +4 -35
- nautobot/dcim/models/device_component_templates.py +7 -2
- nautobot/dcim/models/device_components.py +26 -203
- nautobot/dcim/models/devices.py +30 -152
- nautobot/dcim/models/locations.py +3 -64
- nautobot/dcim/models/power.py +3 -51
- nautobot/dcim/models/racks.py +7 -86
- nautobot/dcim/navigation.py +141 -467
- nautobot/dcim/signals.py +0 -2
- nautobot/dcim/tables/devices.py +8 -5
- nautobot/dcim/tables/devicetypes.py +1 -1
- nautobot/dcim/tables/locations.py +2 -2
- nautobot/dcim/tables/power.py +2 -2
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/device.html +15 -4
- nautobot/dcim/templates/dcim/device_edit.html +6 -0
- nautobot/dcim/templates/dcim/deviceredundancygroup_create.html +0 -1
- nautobot/dcim/templates/dcim/devicetype.html +2 -2
- nautobot/dcim/templates/dcim/interface.html +4 -0
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/location.html +16 -1
- nautobot/dcim/templates/dcim/locationtype.html +15 -0
- nautobot/dcim/templates/dcim/power_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/rackgroup.html +0 -12
- nautobot/dcim/tests/integration/test_cable_connect_form.py +4 -4
- nautobot/dcim/tests/test_api.py +202 -130
- nautobot/dcim/tests/test_cablepaths.py +47 -42
- nautobot/dcim/tests/test_filters.py +156 -134
- nautobot/dcim/tests/test_forms.py +12 -213
- nautobot/dcim/tests/test_graphql.py +8 -3
- nautobot/dcim/tests/test_migrations.py +6 -11
- nautobot/dcim/tests/test_models.py +208 -158
- nautobot/dcim/tests/test_natural_ordering.py +12 -14
- nautobot/dcim/tests/test_signals.py +7 -4
- nautobot/dcim/tests/test_views.py +270 -264
- nautobot/dcim/urls.py +21 -26
- nautobot/dcim/views.py +14 -156
- nautobot/docs/additional-features/caching.md +6 -87
- nautobot/docs/additional-features/job-scheduling-and-approvals.md +3 -0
- nautobot/docs/additional-features/jobs.md +179 -197
- nautobot/docs/administration/nautobot-server.md +9 -24
- nautobot/docs/administration/nautobot-shell.md +6 -6
- nautobot/docs/administration/replicating-nautobot.md +0 -10
- nautobot/docs/configuration/index.md +9 -9
- nautobot/docs/configuration/optional-settings.md +32 -61
- nautobot/docs/configuration/required-settings.md +11 -52
- nautobot/docs/development/application-registry.md +2 -13
- nautobot/docs/development/best-practices.md +2 -1
- nautobot/docs/development/docker-compose-advanced-use-cases.md +1 -1
- nautobot/docs/development/extending-models.md +15 -17
- nautobot/docs/development/generic-views.md +0 -2
- nautobot/docs/development/getting-started.md +56 -6
- nautobot/docs/development/navigation-menu.md +22 -93
- nautobot/docs/development/react-ui.md +105 -0
- nautobot/docs/development/release-checklist.md +3 -3
- nautobot/docs/development/role-internals.md +1 -3
- nautobot/docs/development/style-guide.md +6 -4
- nautobot/docs/development/templates.md +2 -1
- nautobot/docs/docker/index.md +16 -14
- nautobot/docs/index.md +7 -3
- nautobot/docs/installation/index.md +4 -1
- nautobot/docs/installation/migrating-from-netbox.md +12 -43
- nautobot/docs/installation/migrating-from-postgresql.md +1 -1
- nautobot/docs/installation/nautobot.md +1 -1
- nautobot/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/docs/installation/upgrading-from-nautobot-v1.md +190 -636
- nautobot/docs/installation/upgrading.md +5 -2
- nautobot/docs/models/dcim/device.md +3 -0
- nautobot/docs/models/dcim/deviceredundancygroup.md +3 -3
- nautobot/docs/models/extras/computedfield.md +4 -4
- nautobot/docs/models/extras/dynamicgroup.md +9 -9
- nautobot/docs/models/extras/gitrepository.md +3 -0
- nautobot/docs/models/extras/job.md +1 -0
- nautobot/docs/models/extras/jobbutton.md +18 -13
- nautobot/docs/models/extras/jobhook.md +7 -4
- nautobot/docs/models/extras/jobresult.md +6 -2
- nautobot/docs/models/extras/relationship.md +2 -2
- nautobot/docs/models/extras/status.md +6 -19
- nautobot/docs/models/ipam/ipaddress.md +3 -0
- nautobot/docs/models/ipam/vrf.md +0 -3
- nautobot/docs/models/virtualization/virtualmachine.md +3 -0
- nautobot/docs/plugins/development.md +92 -24
- nautobot/docs/release-notes/version-1.5.md +96 -0
- nautobot/docs/release-notes/version-2.0.md +216 -0
- nautobot/docs/requirements.txt +5 -4
- nautobot/docs/rest-api/overview.md +384 -215
- nautobot/docs/rest-api/ui-related-endpoints.md +9 -0
- nautobot/extras/admin.py +3 -5
- nautobot/extras/api/customfields.py +15 -39
- nautobot/extras/api/fields.py +0 -11
- nautobot/extras/api/mixins.py +45 -0
- nautobot/extras/api/relationships.py +63 -159
- nautobot/extras/api/serializers.py +165 -706
- nautobot/extras/api/urls.py +1 -1
- nautobot/extras/api/views.py +295 -282
- nautobot/extras/apps.py +4 -7
- nautobot/extras/choices.py +11 -22
- nautobot/extras/constants.py +9 -3
- nautobot/extras/datasources/__init__.py +2 -0
- nautobot/extras/datasources/git.py +135 -186
- nautobot/extras/datasources/registry.py +25 -35
- nautobot/extras/factory.py +1 -3
- nautobot/extras/filters/__init__.py +49 -47
- nautobot/extras/filters/mixins.py +10 -8
- nautobot/extras/forms/forms.py +72 -148
- nautobot/extras/forms/mixins.py +34 -57
- nautobot/extras/health_checks.py +0 -33
- nautobot/extras/jobs.py +387 -566
- nautobot/extras/management/__init__.py +55 -48
- nautobot/extras/management/commands/renaturalize.py +0 -1
- nautobot/extras/management/commands/runjob.py +24 -62
- nautobot/extras/management/commands/webhook_receiver.py +0 -1
- nautobot/extras/managers.py +30 -7
- nautobot/extras/migrations/0001_initial_part_1.py +0 -1
- nautobot/extras/migrations/0002_initial_part_2.py +0 -1
- nautobot/extras/migrations/0003_initial_part_3.py +0 -1
- nautobot/extras/migrations/0004_populate_default_status_records.py +0 -1
- nautobot/extras/migrations/0005_configcontext_device_types.py +0 -1
- nautobot/extras/migrations/0006_graphqlquery.py +0 -1
- nautobot/extras/migrations/0007_configcontextschema.py +0 -1
- nautobot/extras/migrations/0008_jobresult__custom_field_data.py +0 -1
- nautobot/extras/migrations/0009_computedfield.py +0 -1
- nautobot/extras/migrations/0010_change_cf_validation_max_min_field_to_bigint.py +0 -1
- nautobot/extras/migrations/0011_fileattachment_fileproxy.py +0 -1
- nautobot/extras/migrations/0012_healthchecktestmodel.py +0 -1
- nautobot/extras/migrations/0013_default_fallback_value_computedfield.py +0 -1
- nautobot/extras/migrations/0014_auto_slug.py +0 -1
- nautobot/extras/migrations/0015_scheduled_job.py +0 -1
- nautobot/extras/migrations/0016_secret.py +0 -1
- nautobot/extras/migrations/0017_joblogentry.py +0 -1
- nautobot/extras/migrations/0018_joblog_data_migration.py +0 -2
- nautobot/extras/migrations/0019_joblogentry__meta_options__related_name.py +0 -1
- nautobot/extras/migrations/0020_customfield_changelog.py +0 -1
- nautobot/extras/migrations/0021_customfield_changelog_data.py +0 -1
- nautobot/extras/migrations/0022_objectchange_object_datav2.py +0 -1
- nautobot/extras/migrations/0023_job_model.py +0 -1
- nautobot/extras/migrations/0024_job_data_migration.py +0 -1
- nautobot/extras/migrations/0025_add_advanced_ui_boolean_to_customfield_conputedfield_and_relationship.py +0 -1
- nautobot/extras/migrations/0026_job_add_gitrepository_fk.py +0 -1
- nautobot/extras/migrations/0027_job_gitrepository_data_migration.py +0 -1
- nautobot/extras/migrations/0028_job_reduce_source.py +0 -1
- nautobot/extras/migrations/0029_dynamicgroup.py +0 -1
- nautobot/extras/migrations/0030_webhook_alter_unique_together.py +0 -1
- nautobot/extras/migrations/0031_tag_content_types.py +0 -1
- nautobot/extras/migrations/0032_tag_content_types_data_migration.py +0 -1
- nautobot/extras/migrations/0033_add__optimized_indexing.py +0 -1
- nautobot/extras/migrations/0034_alter_fileattachment_mimetype.py +0 -1
- nautobot/extras/migrations/0035_scheduledjob_crontab.py +0 -1
- nautobot/extras/migrations/0036_job_add_has_sensitive_variables.py +0 -1
- nautobot/extras/migrations/0037_configcontextschema__remove_name_unique__create_constraint_unique_name_owner.py +0 -1
- nautobot/extras/migrations/0038_configcontext_locations.py +0 -1
- nautobot/extras/migrations/0039_objectchange__add_change_context.py +0 -1
- nautobot/extras/migrations/0040_dynamicgroup__dynamicgroupmembership.py +0 -1
- nautobot/extras/migrations/0041_jobresult_job_kwargs.py +0 -1
- nautobot/extras/migrations/0042_job__add_is_job_hook_receiver.py +0 -1
- nautobot/extras/migrations/0043_note.py +0 -1
- nautobot/extras/migrations/0044_add_job_hook.py +0 -1
- nautobot/extras/migrations/0045_add_custom_field_slug.py +0 -1
- nautobot/extras/migrations/0046_populate_custom_field_slug_label.py +0 -1
- nautobot/extras/migrations/0047_enforce_custom_field_slug.py +0 -1
- nautobot/extras/migrations/0048_alter_objectchange_change_context_detail.py +0 -1
- nautobot/extras/migrations/0049_alter_tag_slug.py +0 -1
- nautobot/extras/migrations/0050_customfield_grouping.py +0 -1
- nautobot/extras/migrations/0051_add_job_task_queues.py +0 -1
- nautobot/extras/migrations/0052_configcontext_device_redundancy_groups.py +0 -1
- nautobot/extras/migrations/0053_relationship_required_on.py +0 -1
- nautobot/extras/migrations/0054_scheduledjob_kwargs_request_user_change.py +0 -1
- nautobot/extras/migrations/0055_configcontext_dynamic_groups.py +0 -1
- nautobot/extras/migrations/0056_objectchange_add_reverse_time_idx.py +0 -1
- nautobot/extras/migrations/0057_jobbutton.py +0 -1
- nautobot/extras/migrations/0058_jobresult_add_time_status_idxs.py +38 -0
- nautobot/extras/migrations/{0058_joblogentry_scheduledjob_webhook_data_migration.py → 0059_joblogentry_scheduledjob_webhook_data_migration.py} +1 -2
- nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -2
- nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -8
- nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -33
- nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -2
- nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -2
- nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
- nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -2
- nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -3
- nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -2
- nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -2
- nautobot/extras/migrations/{0069_replace_related_names.py → 0070_replace_related_names.py} +1 -1
- nautobot/extras/migrations/{0070_rename_model_fields.py → 0071_rename_model_fields.py} +1 -2
- nautobot/extras/migrations/0072_job__unique_name_data_migration.py +86 -0
- nautobot/extras/migrations/{0072_job__unique_name.py → 0073_job__unique_name.py} +13 -10
- nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -2
- nautobot/extras/migrations/{0074_rename_slug_to_key_for_custom_field.py → 0075_rename_slug_to_key_for_custom_field.py} +1 -1
- nautobot/extras/migrations/{0075_migrate_custom_field_data.py → 0076_migrate_custom_field_data.py} +1 -1
- nautobot/extras/migrations/{0076_remove_name_field_and_make_label_field_non_nullable.py → 0077_remove_name_field_and_make_label_field_non_nullable.py} +1 -1
- nautobot/extras/migrations/0078_remove_slug.py +45 -0
- nautobot/extras/migrations/0079_tagsfield.py +28 -0
- nautobot/extras/migrations/0080_rename_relationship_slug_to_key.py +17 -0
- nautobot/extras/migrations/0081_rename_relationship_name_to_label.py +29 -0
- nautobot/extras/migrations/0082_ensure_relationship_keys_are_unique.py +43 -0
- nautobot/extras/migrations/0083_rename_computed_field_slug_to_key.py +21 -0
- nautobot/extras/migrations/0084_taggeditem_cleanup.py +43 -0
- nautobot/extras/migrations/0085_taggeditem_uniqueness.py +22 -0
- nautobot/extras/migrations/0086_job__celery_task_fields__dryrun_support.py +81 -0
- nautobot/extras/migrations/0087_job__commit_default_data_migration.py +26 -0
- nautobot/extras/migrations/0088_joblogentry__log_level_default.py +17 -0
- nautobot/extras/migrations/0089_joblogentry__log_level_data_migration.py +34 -0
- nautobot/extras/migrations/0090_scheduledjob__data_migration.py +57 -0
- nautobot/extras/models/__init__.py +2 -3
- nautobot/extras/models/change_logging.py +0 -36
- nautobot/extras/models/customfields.py +39 -33
- nautobot/extras/models/datasources.py +48 -50
- nautobot/extras/models/groups.py +5 -12
- nautobot/extras/models/jobs.py +190 -323
- nautobot/extras/models/mixins.py +0 -71
- nautobot/extras/models/models.py +1 -22
- nautobot/extras/models/relationships.py +20 -21
- nautobot/extras/models/roles.py +0 -23
- nautobot/extras/models/secrets.py +2 -31
- nautobot/extras/models/statuses.py +6 -5
- nautobot/extras/models/tags.py +2 -17
- nautobot/extras/navigation.py +89 -307
- nautobot/extras/plugins/__init__.py +3 -121
- nautobot/extras/plugins/utils.py +0 -3
- nautobot/extras/plugins/validators.py +5 -4
- nautobot/extras/plugins/views.py +16 -4
- nautobot/extras/querysets.py +1 -7
- nautobot/extras/registry.py +3 -0
- nautobot/extras/signals.py +26 -60
- nautobot/extras/tables.py +42 -49
- nautobot/extras/tasks.py +0 -12
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema.html +16 -1
- nautobot/extras/templates/extras/customfield.html +0 -13
- nautobot/extras/templates/extras/dynamicgroup_edit.html +0 -1
- nautobot/extras/templates/extras/gitrepository.html +3 -3
- nautobot/extras/templates/extras/inc/jobresult.html +10 -0
- nautobot/extras/templates/extras/inc/panel_jobhistory.html +1 -1
- nautobot/extras/templates/extras/job.html +35 -25
- nautobot/extras/templates/extras/job_approval_request.html +15 -30
- nautobot/extras/templates/extras/job_detail.html +13 -31
- nautobot/extras/templates/extras/job_edit.html +14 -17
- nautobot/extras/templates/extras/jobresult.html +24 -6
- nautobot/extras/templates/extras/objectchange_list.html +1 -1
- nautobot/extras/templates/extras/scheduledjob.html +2 -2
- nautobot/extras/templates/extras/secret.html +28 -0
- nautobot/extras/templates/extras/secret_edit.html +0 -1
- nautobot/extras/templates/extras/secretsgroup_edit.html +0 -1
- nautobot/extras/templatetags/custom_links.py +0 -2
- nautobot/extras/templatetags/job_buttons.py +1 -0
- nautobot/extras/templatetags/plugins.py +0 -1
- nautobot/extras/{tests/example_jobs → test_jobs}/api_test_job.py +13 -6
- nautobot/extras/test_jobs/atomic_transaction.py +53 -0
- nautobot/extras/test_jobs/dry_run.py +29 -0
- nautobot/extras/{tests/example_jobs/test_duplicate_name.py → test_jobs/duplicate_name.py} +4 -0
- nautobot/extras/test_jobs/duplicate_name2.py +9 -0
- nautobot/extras/test_jobs/fail.py +23 -0
- nautobot/extras/{tests/example_jobs/test_field_default.py → test_jobs/field_default.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_field_order.py → test_jobs/field_order.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_file_upload_fail.py → test_jobs/file_upload_fail.py} +11 -6
- nautobot/extras/test_jobs/file_upload_pass.py +25 -0
- nautobot/extras/test_jobs/has_sensitive_variables.py +25 -0
- nautobot/extras/test_jobs/ipaddress_vars.py +66 -0
- nautobot/extras/test_jobs/job_button_receiver.py +28 -0
- nautobot/extras/test_jobs/job_hook_receiver.py +29 -0
- nautobot/extras/test_jobs/job_variables.py +88 -0
- nautobot/extras/test_jobs/location_with_custom_field.py +45 -0
- nautobot/extras/test_jobs/log_redaction.py +20 -0
- nautobot/extras/test_jobs/log_skip_db_logging.py +17 -0
- nautobot/extras/test_jobs/modify_db.py +25 -0
- nautobot/extras/{tests/example_jobs/test_no_field_order.py → test_jobs/no_field_order.py} +4 -0
- nautobot/extras/test_jobs/object_var_optional.py +21 -0
- nautobot/extras/test_jobs/object_var_required.py +21 -0
- nautobot/extras/test_jobs/object_vars.py +26 -0
- nautobot/extras/test_jobs/pass.py +25 -0
- nautobot/extras/test_jobs/profiling.py +32 -0
- nautobot/extras/test_jobs/read_only_job.py +15 -0
- nautobot/extras/{tests/example_jobs/test_required_args.py → test_jobs/required_args.py} +4 -0
- nautobot/extras/{tests/example_jobs/test_soft_time_limit_greater_than_time_limit.py → test_jobs/soft_time_limit_greater_than_time_limit.py} +5 -1
- nautobot/extras/{tests/example_jobs/test_task_queues.py → test_jobs/task_queues.py} +5 -1
- nautobot/extras/tests/integration/__init__.py +3 -3
- nautobot/extras/tests/integration/test_computedfields.py +1 -1
- nautobot/extras/tests/integration/test_configcontextschema.py +7 -5
- nautobot/extras/tests/integration/test_customfields.py +4 -2
- nautobot/extras/tests/integration/test_dynamicgroups.py +2 -2
- nautobot/extras/tests/integration/test_jobs.py +25 -27
- nautobot/extras/tests/integration/test_notes.py +8 -4
- nautobot/extras/tests/integration/test_plugins.py +4 -4
- nautobot/extras/tests/integration/test_relationships.py +2 -2
- nautobot/extras/tests/test_api.py +371 -381
- nautobot/extras/tests/test_changelog.py +17 -16
- nautobot/extras/tests/test_context_managers.py +5 -6
- nautobot/extras/tests/test_customfields.py +112 -73
- nautobot/extras/tests/test_datasources.py +191 -117
- nautobot/extras/tests/test_dynamicgroups.py +45 -68
- nautobot/extras/tests/test_filters.py +170 -130
- nautobot/extras/tests/test_forms.py +107 -109
- nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
- nautobot/extras/tests/test_jobs.py +271 -273
- nautobot/extras/tests/test_management.py +3 -6
- nautobot/extras/tests/test_migrations.py +5 -3
- nautobot/extras/tests/test_models.py +121 -173
- nautobot/extras/tests/test_notes.py +0 -1
- nautobot/extras/tests/test_plugins.py +55 -89
- nautobot/extras/tests/test_relationships.py +174 -130
- nautobot/extras/tests/test_tags.py +6 -12
- nautobot/extras/tests/test_utils.py +31 -1
- nautobot/extras/tests/test_views.py +223 -184
- nautobot/extras/tests/test_webhooks.py +16 -15
- nautobot/extras/urls.py +69 -69
- nautobot/extras/utils.py +137 -163
- nautobot/extras/views.py +81 -153
- nautobot/ipam/api/fields.py +17 -0
- nautobot/ipam/api/serializers.py +77 -164
- nautobot/ipam/api/urls.py +4 -1
- nautobot/ipam/api/views.py +28 -19
- nautobot/ipam/apps.py +1 -0
- nautobot/ipam/choices.py +5 -12
- nautobot/ipam/constants.py +1 -0
- nautobot/ipam/factory.py +41 -30
- nautobot/ipam/filters.py +58 -25
- nautobot/ipam/forms.py +82 -211
- nautobot/ipam/graphql/types.py +0 -9
- nautobot/ipam/lookups.py +13 -8
- nautobot/ipam/management/commands/__init__.py +0 -0
- nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
- nautobot/ipam/migrations/0001_initial_part_1.py +0 -1
- nautobot/ipam/migrations/0002_initial_part_2.py +0 -1
- nautobot/ipam/migrations/0003_remove_max_length.py +0 -1
- nautobot/ipam/migrations/0004_fixup_p2p_broadcast.py +0 -1
- nautobot/ipam/migrations/0005_auto_slug.py +0 -1
- nautobot/ipam/migrations/0006_ipaddress_nat_outside_list.py +0 -1
- nautobot/ipam/migrations/0007_add_natural_indexing.py +0 -1
- nautobot/ipam/migrations/0008_prefix_vlan_vlangroup_location.py +0 -1
- nautobot/ipam/migrations/0009_alter_vlan_name.py +0 -1
- nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -2
- nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -39
- nautobot/ipam/migrations/0012_rename_ipam_roles.py +0 -1
- nautobot/ipam/migrations/0013_delete_role.py +0 -1
- nautobot/ipam/migrations/0014_rename_foreign_keys_and_related_names.py +0 -1
- nautobot/ipam/migrations/0015_prefix_add_type.py +0 -1
- nautobot/ipam/migrations/0016_prefix_type_data_migration.py +0 -3
- nautobot/ipam/migrations/0017_prefix_remove_is_pool.py +0 -1
- nautobot/ipam/migrations/0018_remove_site_foreign_key_from_ipam_models.py +0 -1
- nautobot/ipam/migrations/0019_created_datetime.py +0 -1
- nautobot/ipam/migrations/0020_related_name_changes.py +1 -2
- nautobot/ipam/migrations/0021_prefix_add_rir_and_date_allocated.py +0 -1
- nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +3 -5
- nautobot/ipam/migrations/0023_delete_aggregate.py +0 -1
- nautobot/ipam/migrations/0024_interface_to_ipaddress_m2m.py +0 -1
- nautobot/ipam/migrations/0025_interface_ipaddress_m2m_data_migration.py +0 -1
- nautobot/ipam/migrations/0026_ipaddress_remove_assigned_object.py +0 -1
- nautobot/ipam/migrations/0027_remove_rir_slug.py +16 -0
- nautobot/ipam/migrations/0028_tagsfield.py +44 -0
- nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
- nautobot/ipam/migrations/0030_ipam__namespaces.py +231 -0
- nautobot/ipam/migrations/0031_ipam__prefix__add_parent.py +58 -0
- nautobot/ipam/migrations/0032_ipam__namespaces_finish.py +63 -0
- nautobot/ipam/migrations/0033_fixup_null_statuses.py +26 -0
- nautobot/ipam/migrations/0034_status_nonnullable.py +36 -0
- nautobot/ipam/models.py +579 -368
- nautobot/ipam/navigation.py +36 -159
- nautobot/ipam/querysets.py +117 -90
- nautobot/ipam/signals.py +89 -0
- nautobot/ipam/tables.py +86 -28
- nautobot/ipam/templates/ipam/ipaddress.html +14 -30
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -0
- nautobot/ipam/templates/ipam/namespace_ipaddresses.html +11 -0
- nautobot/ipam/templates/ipam/namespace_prefixes.html +11 -0
- nautobot/ipam/templates/ipam/namespace_retrieve.html +42 -0
- nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
- nautobot/ipam/templates/ipam/prefix.html +27 -33
- nautobot/ipam/templates/ipam/prefix_edit.html +7 -1
- nautobot/ipam/templates/ipam/vlangroup.html +0 -13
- nautobot/ipam/templates/ipam/vrf.html +6 -4
- nautobot/ipam/templates/ipam/vrf_edit.html +20 -2
- nautobot/ipam/tests/integration/test_prefixes.py +4 -27
- nautobot/ipam/tests/test_api.py +60 -61
- nautobot/ipam/tests/test_filters.py +187 -126
- nautobot/ipam/tests/test_forms.py +12 -6
- nautobot/ipam/tests/test_graphql.py +8 -6
- nautobot/ipam/tests/test_migrations.py +8 -13
- nautobot/ipam/tests/test_models.py +426 -274
- nautobot/ipam/tests/test_ordering.py +6 -3
- nautobot/ipam/tests/test_querysets.py +340 -96
- nautobot/ipam/tests/test_views.py +100 -55
- nautobot/ipam/urls.py +28 -5
- nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
- nautobot/ipam/utils/migrations.py +713 -0
- nautobot/ipam/views.py +237 -122
- nautobot/project-static/docs/404.html +1399 -166
- nautobot/project-static/docs/additional-features/caching.html +1416 -320
- nautobot/project-static/docs/additional-features/change-logging.html +1389 -190
- nautobot/project-static/docs/additional-features/config-contexts.html +1389 -190
- nautobot/project-static/docs/additional-features/graphql.html +1389 -190
- nautobot/project-static/docs/additional-features/healthcheck.html +1389 -190
- nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1393 -190
- nautobot/project-static/docs/additional-features/jobs.html +1677 -460
- nautobot/project-static/docs/additional-features/napalm.html +1389 -190
- nautobot/project-static/docs/additional-features/prometheus-metrics.html +1389 -190
- nautobot/project-static/docs/additional-features/template-filters.html +1389 -190
- nautobot/project-static/docs/administration/celery-queues.html +1389 -190
- nautobot/project-static/docs/administration/nautobot-server.html +1553 -375
- nautobot/project-static/docs/administration/nautobot-shell.html +1395 -196
- nautobot/project-static/docs/administration/permissions.html +1389 -190
- nautobot/project-static/docs/administration/replicating-nautobot.html +1387 -207
- nautobot/project-static/docs/apps/index.html +1389 -190
- nautobot/project-static/docs/apps/nautobot-apps.html +1387 -175
- nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js +29 -0
- nautobot/project-static/docs/assets/javascripts/bundle.51198bba.min.js.map +8 -0
- nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js → search.208ed371.min.js} +9 -15
- nautobot/project-static/docs/assets/javascripts/workers/{search.16e2a7d4.min.js.map → search.208ed371.min.js.map} +4 -4
- nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/main.ded33207.min.css.map +1 -0
- nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css +1 -0
- nautobot/project-static/docs/assets/stylesheets/palette.a0c5b2b5.min.css.map +1 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1775 -590
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1389 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3588 -1922
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1461 -262
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1401 -170
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1396 -191
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +2095 -894
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2357 -1194
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +2258 -940
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1389 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1400 -201
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +11068 -7861
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2867 -2224
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1389 -190
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2641 -1573
- nautobot/project-static/docs/configuration/authentication/ldap.html +1389 -190
- nautobot/project-static/docs/configuration/authentication/remote.html +1389 -190
- nautobot/project-static/docs/configuration/authentication/sso.html +1389 -190
- nautobot/project-static/docs/configuration/index.html +1398 -199
- nautobot/project-static/docs/configuration/optional-settings.html +1418 -274
- nautobot/project-static/docs/configuration/required-settings.html +1419 -287
- nautobot/project-static/docs/core-functionality/circuits.html +1446 -247
- nautobot/project-static/docs/core-functionality/device-types.html +1448 -249
- nautobot/project-static/docs/core-functionality/devices.html +1452 -249
- nautobot/project-static/docs/core-functionality/ipam.html +1452 -253
- nautobot/project-static/docs/core-functionality/power.html +1448 -249
- nautobot/project-static/docs/core-functionality/secrets.html +1448 -249
- nautobot/project-static/docs/core-functionality/services.html +1448 -249
- nautobot/project-static/docs/core-functionality/sites-and-racks.html +1448 -249
- nautobot/project-static/docs/core-functionality/tenancy.html +1448 -249
- nautobot/project-static/docs/core-functionality/virtualization.html +1452 -249
- nautobot/project-static/docs/core-functionality/vlans.html +1448 -249
- nautobot/project-static/docs/development/application-registry.html +1393 -214
- nautobot/project-static/docs/development/best-practices.html +1392 -192
- nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1390 -191
- nautobot/project-static/docs/development/extending-models.html +1443 -257
- nautobot/project-static/docs/development/generic-views.html +1403 -174
- nautobot/project-static/docs/development/getting-started.html +1568 -262
- nautobot/project-static/docs/development/homepage.html +1389 -190
- nautobot/project-static/docs/development/index.html +1389 -190
- nautobot/project-static/docs/development/model-features.html +1389 -190
- nautobot/project-static/docs/development/natural-keys.html +1389 -190
- nautobot/project-static/docs/development/navigation-menu.html +1451 -330
- nautobot/project-static/docs/development/react-ui.html +4199 -0
- nautobot/project-static/docs/development/release-checklist.html +1392 -193
- nautobot/project-static/docs/development/role-internals.html +1402 -172
- nautobot/project-static/docs/development/style-guide.html +1399 -199
- nautobot/project-static/docs/development/templates.html +1391 -191
- nautobot/project-static/docs/development/testing.html +1389 -190
- nautobot/project-static/docs/development/user-preferences.html +1389 -190
- nautobot/project-static/docs/docker/index.html +1408 -206
- nautobot/project-static/docs/index.html +1397 -180
- nautobot/project-static/docs/installation/centos.html +1401 -170
- nautobot/project-static/docs/installation/external-authentication.html +1389 -190
- nautobot/project-static/docs/installation/http-server.html +1389 -190
- nautobot/project-static/docs/installation/index.html +1394 -191
- nautobot/project-static/docs/installation/migrating-from-netbox.html +1452 -305
- nautobot/project-static/docs/installation/migrating-from-postgresql.html +1390 -191
- nautobot/project-static/docs/installation/nautobot.html +1390 -191
- nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1389 -190
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +1401 -170
- nautobot/project-static/docs/installation/services.html +1389 -190
- nautobot/project-static/docs/installation/tables/v2-api-behavior-changes.yaml +70 -0
- nautobot/project-static/docs/installation/tables/v2-api-removed-fields.yaml +142 -0
- nautobot/project-static/docs/installation/tables/v2-api-renamed-fields.yaml +124 -0
- nautobot/project-static/docs/installation/tables/v2-code-location-changes.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-code-removals.yaml +67 -0
- nautobot/project-static/docs/installation/tables/v2-database-behavior-changes.yaml +37 -0
- nautobot/project-static/docs/installation/tables/v2-database-removed-fields.yaml +166 -0
- nautobot/project-static/docs/installation/tables/v2-database-renamed-fields.yaml +340 -0
- nautobot/project-static/docs/installation/tables/v2-filters-corrected-fields.yaml +28 -0
- nautobot/project-static/docs/installation/tables/v2-filters-enhanced-fields.yaml +241 -0
- nautobot/project-static/docs/installation/tables/v2-filters-removed-fields.yaml +553 -0
- nautobot/project-static/docs/installation/tables/v2-filters-renamed-fields.yaml +223 -0
- nautobot/project-static/docs/installation/tables/v2-logging-renamed-loggers.yaml +23 -0
- nautobot/project-static/docs/installation/ubuntu.html +1401 -170
- nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +4254 -1923
- nautobot/project-static/docs/installation/upgrading.html +1395 -192
- nautobot/project-static/docs/models/circuits/circuit.html +1427 -174
- nautobot/project-static/docs/models/circuits/circuittermination.html +1427 -174
- nautobot/project-static/docs/models/circuits/circuittype.html +1427 -174
- nautobot/project-static/docs/models/circuits/provider.html +1427 -174
- nautobot/project-static/docs/models/circuits/providernetwork.html +1427 -174
- nautobot/project-static/docs/models/dcim/cable.html +1458 -174
- nautobot/project-static/docs/models/dcim/consoleport.html +1427 -174
- nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/consoleserverport.html +1427 -174
- nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/device.html +1431 -174
- nautobot/project-static/docs/models/dcim/devicebay.html +1427 -174
- nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1522 -177
- nautobot/project-static/docs/models/dcim/devicetype.html +1427 -174
- nautobot/project-static/docs/models/dcim/frontport.html +1427 -174
- nautobot/project-static/docs/models/dcim/frontporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/interface.html +1427 -174
- nautobot/project-static/docs/models/dcim/interfacetemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/inventoryitem.html +1427 -174
- nautobot/project-static/docs/models/dcim/location.html +1427 -174
- nautobot/project-static/docs/models/dcim/locationtype.html +1427 -174
- nautobot/project-static/docs/models/dcim/manufacturer.html +1427 -174
- nautobot/project-static/docs/models/dcim/platform.html +1427 -174
- nautobot/project-static/docs/models/dcim/powerfeed.html +1425 -172
- nautobot/project-static/docs/models/dcim/poweroutlet.html +1427 -174
- nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/powerpanel.html +1425 -172
- nautobot/project-static/docs/models/dcim/powerport.html +1427 -174
- nautobot/project-static/docs/models/dcim/powerporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/rack.html +1427 -174
- nautobot/project-static/docs/models/dcim/rackgroup.html +1427 -174
- nautobot/project-static/docs/models/dcim/rackreservation.html +1427 -174
- nautobot/project-static/docs/models/dcim/rearport.html +1427 -174
- nautobot/project-static/docs/models/dcim/rearporttemplate.html +1427 -174
- nautobot/project-static/docs/models/dcim/region.html +1401 -170
- nautobot/project-static/docs/models/dcim/site.html +1401 -170
- nautobot/project-static/docs/models/dcim/virtualchassis.html +1425 -172
- nautobot/project-static/docs/models/extras/computedfield.html +1393 -194
- nautobot/project-static/docs/models/extras/configcontext.html +1465 -174
- nautobot/project-static/docs/models/extras/configcontextschema.html +1421 -168
- nautobot/project-static/docs/models/extras/customfield.html +1389 -190
- nautobot/project-static/docs/models/extras/customlink.html +1389 -190
- nautobot/project-static/docs/models/extras/dynamicgroup.html +1398 -199
- nautobot/project-static/docs/models/extras/exporttemplate.html +1389 -190
- nautobot/project-static/docs/models/extras/gitrepository.html +1393 -190
- nautobot/project-static/docs/models/extras/graphqlquery.html +1469 -171
- nautobot/project-static/docs/models/extras/imageattachment.html +1434 -181
- nautobot/project-static/docs/models/extras/job.html +1411 -157
- nautobot/project-static/docs/models/extras/jobbutton.html +1410 -207
- nautobot/project-static/docs/models/extras/jobhook.html +1397 -194
- nautobot/project-static/docs/models/extras/joblogentry.html +1408 -155
- nautobot/project-static/docs/models/extras/jobresult.html +1417 -159
- nautobot/project-static/docs/models/extras/note.html +1389 -190
- nautobot/project-static/docs/models/extras/relationship.html +1391 -192
- nautobot/project-static/docs/models/extras/role.html +1495 -198
- nautobot/project-static/docs/models/extras/secret.html +1492 -201
- nautobot/project-static/docs/models/extras/secretsgroup.html +1410 -157
- nautobot/project-static/docs/models/extras/status.html +1381 -221
- nautobot/project-static/docs/models/extras/tag.html +1389 -190
- nautobot/project-static/docs/models/extras/webhook.html +1389 -190
- nautobot/project-static/docs/models/ipam/ipaddress.html +1488 -200
- nautobot/project-static/docs/models/ipam/prefix.html +1410 -157
- nautobot/project-static/docs/models/ipam/rir.html +1410 -157
- nautobot/project-static/docs/models/ipam/routetarget.html +1410 -157
- nautobot/project-static/docs/models/ipam/service.html +1410 -157
- nautobot/project-static/docs/models/ipam/vlan.html +1410 -157
- nautobot/project-static/docs/models/ipam/vlangroup.html +1410 -157
- nautobot/project-static/docs/models/ipam/vrf.html +1410 -161
- nautobot/project-static/docs/models/tenancy/tenant.html +1412 -159
- nautobot/project-static/docs/models/tenancy/tenantgroup.html +1412 -159
- nautobot/project-static/docs/models/users/objectpermission.html +1462 -171
- nautobot/project-static/docs/models/users/token.html +1410 -157
- nautobot/project-static/docs/models/virtualization/cluster.html +1410 -157
- nautobot/project-static/docs/models/virtualization/clustergroup.html +1410 -157
- nautobot/project-static/docs/models/virtualization/clustertype.html +1410 -157
- nautobot/project-static/docs/models/virtualization/virtualmachine.html +1414 -157
- nautobot/project-static/docs/models/virtualization/vminterface.html +1410 -157
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/plugins/development.html +1916 -646
- nautobot/project-static/docs/plugins/index.html +1389 -190
- nautobot/project-static/docs/plugins/porting-from-netbox.html +1389 -190
- nautobot/project-static/docs/release-notes/index.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.0.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.1.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.2.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.3.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.4.html +1389 -190
- nautobot/project-static/docs/release-notes/version-1.5.html +2016 -397
- nautobot/project-static/docs/release-notes/version-2.0.html +1935 -287
- nautobot/project-static/docs/requirements.txt +5 -4
- nautobot/project-static/docs/rest-api/authentication.html +1389 -190
- nautobot/project-static/docs/rest-api/filtering.html +1389 -190
- nautobot/project-static/docs/rest-api/overview.html +2002 -576
- nautobot/project-static/docs/rest-api/ui-related-endpoints.html +4057 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +197 -187
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guides/custom-fields.html +1390 -191
- nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1392 -193
- nautobot/project-static/docs/user-guides/getting-started/index.html +1388 -189
- nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1388 -189
- nautobot/project-static/docs/user-guides/getting-started/ipam.html +1386 -187
- nautobot/project-static/docs/user-guides/getting-started/platforms.html +1448 -249
- nautobot/project-static/docs/user-guides/getting-started/regions.html +1411 -212
- nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1395 -196
- nautobot/project-static/docs/user-guides/getting-started/tenants.html +1448 -249
- nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1448 -249
- nautobot/project-static/docs/user-guides/git-data-source.html +1405 -206
- nautobot/project-static/docs/user-guides/graphql.html +1402 -203
- nautobot/project-static/docs/user-guides/relationships.html +1448 -249
- nautobot/project-static/docs/user-guides/s3-django-storage.html +1448 -249
- nautobot/project-static/js/forms.js +16 -9
- nautobot/project-static/js/theme.js +5 -0
- nautobot/tenancy/api/serializers.py +4 -34
- nautobot/tenancy/api/urls.py +1 -1
- nautobot/tenancy/filters/__init__.py +9 -7
- nautobot/tenancy/filters/mixins.py +3 -2
- nautobot/tenancy/forms.py +3 -36
- nautobot/tenancy/migrations/0001_initial.py +0 -1
- nautobot/tenancy/migrations/0002_auto_slug.py +0 -1
- nautobot/tenancy/migrations/0003_mptt_to_tree_queries.py +0 -1
- nautobot/tenancy/migrations/0004_change_tree_manager_on_tree_models.py +0 -1
- nautobot/tenancy/migrations/0005_rename_foreign_keys_and_related_names.py +0 -1
- nautobot/tenancy/migrations/0006_created_datetime.py +0 -1
- nautobot/tenancy/migrations/0007_remove_tenant_tenantgroup_slug.py +20 -0
- nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
- nautobot/tenancy/models.py +0 -30
- nautobot/tenancy/navigation.py +6 -39
- nautobot/tenancy/tables.py +4 -4
- nautobot/tenancy/templates/tenancy/tenant.html +12 -12
- nautobot/tenancy/templates/tenancy/tenant_edit.html +0 -1
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/tests/test_api.py +1 -12
- nautobot/tenancy/tests/test_filters.py +20 -12
- nautobot/tenancy/tests/test_views.py +11 -29
- nautobot/tenancy/urls.py +10 -10
- nautobot/tenancy/views.py +0 -3
- nautobot/ui/.eslintignore +6 -0
- nautobot/ui/.gitignore +10 -0
- nautobot/ui/.prettierignore +9 -0
- nautobot/ui/.prettierrc +4 -0
- nautobot/ui/README.md +33 -0
- nautobot/ui/app_imports.js.j2 +7 -0
- nautobot/ui/craco.config.js +46 -0
- nautobot/ui/jsconfig-base.json +11 -0
- nautobot/ui/jsconfig.json +5 -0
- nautobot/ui/lib/nautobot-craco-alias-plugin.js +40 -0
- nautobot/ui/package-lock.json +21451 -0
- nautobot/ui/package.json +70 -0
- nautobot/ui/public/index.html +47 -0
- nautobot/ui/public/logo192.png +0 -0
- nautobot/ui/public/logo512.png +0 -0
- nautobot/ui/public/manifest.json +25 -0
- nautobot/ui/public/nautobot_logo.svg +131 -0
- nautobot/ui/public/robots.txt +3 -0
- nautobot/ui/src/App.js +71 -0
- nautobot/ui/src/components/AppFullWidthComponents.js +8 -0
- nautobot/ui/src/components/AppTab.js +40 -0
- nautobot/ui/src/components/Apps.js +60 -0
- nautobot/ui/src/components/HomeChangelogPanel.js +98 -0
- nautobot/ui/src/components/HomePanel.js +58 -0
- nautobot/ui/src/components/JobHistoryTable.js +78 -0
- nautobot/ui/src/components/Layout.js +53 -0
- nautobot/ui/src/components/LoadingWidget.js +25 -0
- nautobot/ui/src/components/Navbar.js +116 -0
- nautobot/ui/src/components/NotificationPopover.js +27 -0
- nautobot/ui/src/components/ObjectListTable.js +209 -0
- nautobot/ui/src/components/ReferenceDataTag.js +35 -0
- nautobot/ui/src/components/RouterButton.js +10 -0
- nautobot/ui/src/components/RouterLink.js +10 -0
- nautobot/ui/src/components/SidebarNav.js +147 -0
- nautobot/ui/src/components/Table.js +48 -0
- nautobot/ui/src/components/TableItem.js +71 -0
- nautobot/ui/src/components/__tests__/AppFullWidthComponents.test.js +16 -0
- nautobot/ui/src/components/__tests__/AppTab.test.js +21 -0
- nautobot/ui/src/components/__tests__/Apps.test.js +14 -0
- nautobot/ui/src/components/__tests__/Layout.test.js +33 -0
- nautobot/ui/src/components/__tests__/Table.test.js +36 -0
- nautobot/ui/src/components/__tests__/TableItem.test.js +37 -0
- nautobot/ui/src/components/__tests__/paginator.test.js +43 -0
- nautobot/ui/src/components/__tests__/paginator_form.test.js +13 -0
- nautobot/ui/src/components/pagination.js +93 -0
- nautobot/ui/src/components/paginator.js +79 -0
- nautobot/ui/src/components/paginator_form.js +43 -0
- nautobot/ui/src/components/usePagination.js +57 -0
- nautobot/ui/src/constants/apiPath.js +10 -0
- nautobot/ui/src/constants/icons.js +15 -0
- nautobot/ui/src/constants/size.js +15 -0
- nautobot/ui/src/index.js +65 -0
- nautobot/ui/src/reportWebVitals.js +15 -0
- nautobot/ui/src/router.js +77 -0
- nautobot/ui/src/utils/api.js +131 -0
- nautobot/ui/src/utils/app-import.js +15 -0
- nautobot/ui/src/utils/color.js +15 -0
- nautobot/ui/src/utils/date.js +14 -0
- nautobot/ui/src/utils/index.js +15 -0
- nautobot/ui/src/utils/navigation.js +32 -0
- nautobot/ui/src/utils/session.js +64 -0
- nautobot/ui/src/utils/store.js +242 -0
- nautobot/ui/src/utils/string.js +6 -0
- nautobot/ui/src/utils/url.js +4 -0
- nautobot/ui/src/views/Home.js +138 -0
- nautobot/ui/src/views/InstalledApps.js +80 -0
- nautobot/ui/src/views/Login.js +48 -0
- nautobot/ui/src/views/Logout.js +20 -0
- nautobot/ui/src/views/__tests__/BSCreateViewTemplate.test.js +11 -0
- nautobot/ui/src/views/__tests__/BSListViewTemplate.test.js +107 -0
- nautobot/ui/src/views/__tests__/Login.test.js +15 -0
- nautobot/ui/src/views/generic/GenericView.js +142 -0
- nautobot/ui/src/views/generic/ObjectCreate.js +96 -0
- nautobot/ui/src/views/generic/ObjectList.js +127 -0
- nautobot/ui/src/views/generic/ObjectRetrieve.js +551 -0
- nautobot/users/admin.py +1 -1
- nautobot/users/api/serializers.py +51 -61
- nautobot/users/api/urls.py +1 -1
- nautobot/users/api/views.py +53 -2
- nautobot/users/migrations/0001_initial.py +0 -1
- nautobot/users/migrations/0002_token_ordering_by_created.py +0 -1
- nautobot/users/migrations/0003_alter_user_options.py +0 -1
- nautobot/users/migrations/0004_alter_user_managers.py +0 -1
- nautobot/users/tests/test_api.py +109 -28
- nautobot/users/tests/test_filters.py +0 -4
- nautobot/users/tests/test_models.py +0 -1
- nautobot/users/views.py +0 -7
- nautobot/virtualization/api/serializers.py +18 -132
- nautobot/virtualization/api/urls.py +1 -1
- nautobot/virtualization/api/views.py +1 -22
- nautobot/virtualization/choices.py +0 -2
- nautobot/virtualization/filters.py +12 -7
- nautobot/virtualization/forms.py +21 -117
- nautobot/virtualization/migrations/0001_initial.py +0 -1
- nautobot/virtualization/migrations/0002_virtualmachine_local_context_schema.py +0 -1
- nautobot/virtualization/migrations/0003_vminterface_verbose_name.py +0 -1
- nautobot/virtualization/migrations/0004_auto_slug.py +0 -1
- nautobot/virtualization/migrations/0005_add_natural_indexing.py +0 -1
- nautobot/virtualization/migrations/0006_vminterface_status.py +0 -1
- nautobot/virtualization/migrations/0007_vminterface_status_data_migration.py +0 -1
- nautobot/virtualization/migrations/0008_vminterface_parent.py +0 -1
- nautobot/virtualization/migrations/0009_cluster_location.py +0 -1
- nautobot/virtualization/migrations/0010_vminterface_mac_address_data_migration.py +0 -1
- nautobot/virtualization/migrations/0011_alter_vminterface_mac_address.py +0 -1
- nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -2
- nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -12
- nautobot/virtualization/migrations/0014_rename_virtualmachine_roles.py +0 -1
- nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -2
- nautobot/virtualization/migrations/0016_remove_site_foreign_key_from_cluster_class.py +0 -1
- nautobot/virtualization/migrations/0017_created_datetime.py +0 -1
- nautobot/virtualization/migrations/0018_related_name_changes.py +1 -2
- nautobot/virtualization/migrations/0019_vminterface_ip_addresses_m2m.py +0 -1
- nautobot/virtualization/migrations/0020_remove_clustergroup_clustertype_slug.py +20 -0
- nautobot/virtualization/migrations/0021_tagsfield_and_vminterface_to_primarymodel.py +39 -0
- nautobot/virtualization/migrations/0022_vminterface_timestamps_data_migration.py +17 -0
- nautobot/virtualization/migrations/0023_ipam__namespaces.py +25 -0
- nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
- nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
- nautobot/virtualization/models.py +39 -131
- nautobot/virtualization/navigation.py +18 -99
- nautobot/virtualization/tables.py +4 -4
- nautobot/virtualization/templates/virtualization/virtualmachine.html +13 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
- nautobot/virtualization/tests/test_api.py +42 -52
- nautobot/virtualization/tests/test_filters.py +98 -75
- nautobot/virtualization/tests/test_models.py +36 -13
- nautobot/virtualization/tests/test_views.py +68 -73
- nautobot/virtualization/urls.py +10 -10
- nautobot/virtualization/views.py +8 -14
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +15 -22
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +987 -834
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/WHEEL +1 -1
- nautobot/circuits/api/nested_serializers.py +0 -69
- nautobot/core/templates/plugin_template/navigation.py-tpl +0 -22
- nautobot/dcim/api/nested_serializers.py +0 -356
- nautobot/dcim/templates/dcim/device_import.html +0 -5
- nautobot/dcim/templates/dcim/device_import_child.html +0 -5
- nautobot/dcim/templates/dcim/inc/device_import_header.html +0 -4
- nautobot/extras/api/nested_serializers.py +0 -353
- nautobot/extras/migrations/0064_configcontext_data_migrations.py +0 -42
- nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -47
- nautobot/extras/reports.py +0 -60
- nautobot/extras/scripts.py +0 -72
- nautobot/extras/tests/example_jobs/script_variables.py +0 -67
- nautobot/extras/tests/example_jobs/test_duplicate_name2.py +0 -5
- nautobot/extras/tests/example_jobs/test_fail.py +0 -16
- nautobot/extras/tests/example_jobs/test_file_upload_pass.py +0 -20
- nautobot/extras/tests/example_jobs/test_ipaddress_vars.py +0 -52
- nautobot/extras/tests/example_jobs/test_job_button_receiver.py +0 -21
- nautobot/extras/tests/example_jobs/test_job_hook_receiver.py +0 -20
- nautobot/extras/tests/example_jobs/test_location_with_custom_field.py +0 -35
- nautobot/extras/tests/example_jobs/test_log_redaction.py +0 -14
- nautobot/extras/tests/example_jobs/test_modify_db.py +0 -19
- nautobot/extras/tests/example_jobs/test_object_var_optional.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_var_required.py +0 -14
- nautobot/extras/tests/example_jobs/test_object_vars.py +0 -29
- nautobot/extras/tests/example_jobs/test_pass.py +0 -19
- nautobot/extras/tests/example_jobs/test_read_only_fail.py +0 -24
- nautobot/extras/tests/example_jobs/test_read_only_no_commit_field.py +0 -10
- nautobot/extras/tests/example_jobs/test_read_only_pass.py +0 -22
- nautobot/ipam/api/nested_serializers.py +0 -143
- nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js +0 -29
- nautobot/project-static/docs/assets/javascripts/bundle.5a2dcb6a.min.js.map +0 -8
- nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js +0 -18
- nautobot/project-static/docs/assets/javascripts/extra/bundle.5f09fbc3.min.js.map +0 -8
- nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/extra.0d2c79a8.min.css.map +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/main.975780f9.min.css.map +0 -1
- nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css +0 -1
- nautobot/project-static/docs/assets/stylesheets/palette.2505c338.min.css.map +0 -1
- nautobot/tenancy/api/nested_serializers.py +0 -31
- nautobot/users/api/nested_serializers.py +0 -67
- nautobot/virtualization/api/nested_serializers.py +0 -65
- /nautobot/extras/{tests/example_jobs → test_jobs}/__init__.py +0 -0
- /nautobot/{dcim/models/sites.py → ipam/management/__init__.py} +0 -0
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.0a2.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
nautobot/dcim/forms.py
CHANGED
|
@@ -2,11 +2,7 @@ import re
|
|
|
2
2
|
|
|
3
3
|
from django import forms
|
|
4
4
|
from django.contrib.auth import get_user_model
|
|
5
|
-
from django.contrib.contenttypes.models import ContentType
|
|
6
|
-
from django.contrib.postgres.forms.array import SimpleArrayField
|
|
7
|
-
from django.core.exceptions import ObjectDoesNotExist, ValidationError
|
|
8
5
|
from django.db.models import Q
|
|
9
|
-
from django.utils.safestring import mark_safe
|
|
10
6
|
from timezone_field import TimeZoneFormField
|
|
11
7
|
|
|
12
8
|
from nautobot.circuits.models import Circuit, CircuitTermination, Provider
|
|
@@ -18,10 +14,6 @@ from nautobot.core.forms import (
|
|
|
18
14
|
BulkEditNullBooleanSelect,
|
|
19
15
|
ColorSelect,
|
|
20
16
|
CommentField,
|
|
21
|
-
CSVChoiceField,
|
|
22
|
-
CSVContentTypeField,
|
|
23
|
-
CSVModelChoiceField,
|
|
24
|
-
CSVMultipleContentTypeField,
|
|
25
17
|
DynamicModelChoiceField,
|
|
26
18
|
DynamicModelMultipleChoiceField,
|
|
27
19
|
ExpandableNameField,
|
|
@@ -38,7 +30,6 @@ from nautobot.core.forms import (
|
|
|
38
30
|
from nautobot.core.forms.constants import BOOLEAN_WITH_BLANK_CHOICES
|
|
39
31
|
from nautobot.dcim.form_mixins import (
|
|
40
32
|
LocatableModelBulkEditFormMixin,
|
|
41
|
-
LocatableModelCSVFormMixin,
|
|
42
33
|
LocatableModelFilterFormMixin,
|
|
43
34
|
LocatableModelFormMixin,
|
|
44
35
|
)
|
|
@@ -52,17 +43,14 @@ from nautobot.extras.forms import (
|
|
|
52
43
|
LocalContextModelForm,
|
|
53
44
|
LocalContextModelBulkEditForm,
|
|
54
45
|
RoleModelBulkEditFormMixin,
|
|
55
|
-
RoleModelCSVFormMixin,
|
|
56
46
|
RoleModelFilterFormMixin,
|
|
57
|
-
RoleRequiredRoleModelCSVFormMixin,
|
|
58
47
|
StatusModelBulkEditFormMixin,
|
|
59
|
-
StatusModelCSVFormMixin,
|
|
60
48
|
StatusModelFilterFormMixin,
|
|
61
49
|
TagsBulkEditFormMixin,
|
|
62
50
|
)
|
|
63
51
|
from nautobot.extras.models import SecretsGroup, Status
|
|
64
52
|
from nautobot.ipam.constants import BGP_ASN_MAX, BGP_ASN_MIN
|
|
65
|
-
from nautobot.ipam.models import IPAddress, IPAddressToInterface, VLAN
|
|
53
|
+
from nautobot.ipam.models import IPAddress, IPAddressToInterface, VLAN, VRF
|
|
66
54
|
from nautobot.tenancy.forms import TenancyFilterForm, TenancyForm
|
|
67
55
|
from nautobot.tenancy.models import Tenant, TenantGroup
|
|
68
56
|
from nautobot.virtualization.models import Cluster, ClusterGroup
|
|
@@ -87,10 +75,8 @@ from .choices import (
|
|
|
87
75
|
SubdeviceRoleChoices,
|
|
88
76
|
)
|
|
89
77
|
from .constants import (
|
|
90
|
-
CABLE_TERMINATION_MODELS,
|
|
91
78
|
INTERFACE_MTU_MAX,
|
|
92
79
|
INTERFACE_MTU_MIN,
|
|
93
|
-
NONCONNECTABLE_IFACE_TYPES,
|
|
94
80
|
REARPORT_POSITIONS_MAX,
|
|
95
81
|
REARPORT_POSITIONS_MIN,
|
|
96
82
|
)
|
|
@@ -258,29 +244,6 @@ class LocationTypeForm(NautobotModelForm):
|
|
|
258
244
|
fields = ("parent", "name", "slug", "description", "nestable", "content_types")
|
|
259
245
|
|
|
260
246
|
|
|
261
|
-
class LocationTypeCSVForm(CustomFieldModelCSVForm):
|
|
262
|
-
parent = CSVModelChoiceField(
|
|
263
|
-
queryset=LocationType.objects.all(),
|
|
264
|
-
required=False,
|
|
265
|
-
to_field_name="name",
|
|
266
|
-
help_text="Name of parent location type",
|
|
267
|
-
)
|
|
268
|
-
content_types = CSVMultipleContentTypeField(
|
|
269
|
-
feature="locations",
|
|
270
|
-
required=False,
|
|
271
|
-
choices_as_strings=True,
|
|
272
|
-
help_text=mark_safe(
|
|
273
|
-
"The object types to which this status applies. Multiple values "
|
|
274
|
-
"must be comma-separated and wrapped in double quotes. (e.g. "
|
|
275
|
-
'<code>"dcim.device,dcim.rack"</code>)'
|
|
276
|
-
),
|
|
277
|
-
)
|
|
278
|
-
|
|
279
|
-
class Meta:
|
|
280
|
-
model = LocationType
|
|
281
|
-
fields = LocationType.csv_headers
|
|
282
|
-
|
|
283
|
-
|
|
284
247
|
class LocationTypeFilterForm(NautobotFilterForm):
|
|
285
248
|
model = LocationType
|
|
286
249
|
q = forms.CharField(required=False, label="Search")
|
|
@@ -378,35 +341,6 @@ class LocationBulkEditForm(TagsBulkEditFormMixin, StatusModelBulkEditFormMixin,
|
|
|
378
341
|
]
|
|
379
342
|
|
|
380
343
|
|
|
381
|
-
class LocationCSVForm(StatusModelCSVFormMixin, CustomFieldModelCSVForm):
|
|
382
|
-
location_type = CSVModelChoiceField(
|
|
383
|
-
queryset=LocationType.objects.all(),
|
|
384
|
-
to_field_name="name",
|
|
385
|
-
help_text="Location type",
|
|
386
|
-
)
|
|
387
|
-
parent = CSVModelChoiceField(
|
|
388
|
-
queryset=Location.objects.all(),
|
|
389
|
-
required=False,
|
|
390
|
-
to_field_name="name",
|
|
391
|
-
help_text="Parent location",
|
|
392
|
-
)
|
|
393
|
-
tenant = CSVModelChoiceField(
|
|
394
|
-
queryset=Tenant.objects.all(),
|
|
395
|
-
required=False,
|
|
396
|
-
to_field_name="name",
|
|
397
|
-
help_text="Assigned tenant",
|
|
398
|
-
)
|
|
399
|
-
|
|
400
|
-
class Meta:
|
|
401
|
-
model = Location
|
|
402
|
-
fields = Location.csv_headers
|
|
403
|
-
help_texts = {
|
|
404
|
-
"time_zone": mark_safe(
|
|
405
|
-
'Time zone (<a href="https://en.wikipedia.org/wiki/List_of_tz_database_time_zones">available options</a>)'
|
|
406
|
-
)
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
|
|
410
344
|
class LocationFilterForm(NautobotFilterForm, StatusModelFilterFormMixin, TenancyFilterForm):
|
|
411
345
|
model = Location
|
|
412
346
|
field_order = ["q", "location_type", "parent", "subtree", "status", "tenant_group", "tenant", "tag"]
|
|
@@ -444,22 +378,6 @@ class RackGroupForm(LocatableModelFormMixin, NautobotModelForm):
|
|
|
444
378
|
)
|
|
445
379
|
|
|
446
380
|
|
|
447
|
-
class RackGroupCSVForm(LocatableModelCSVFormMixin, CustomFieldModelCSVForm):
|
|
448
|
-
parent = CSVModelChoiceField(
|
|
449
|
-
queryset=RackGroup.objects.all(),
|
|
450
|
-
required=False,
|
|
451
|
-
to_field_name="name",
|
|
452
|
-
help_text="Parent rack group",
|
|
453
|
-
error_messages={
|
|
454
|
-
"invalid_choice": "Rack group not found.",
|
|
455
|
-
},
|
|
456
|
-
)
|
|
457
|
-
|
|
458
|
-
class Meta:
|
|
459
|
-
model = RackGroup
|
|
460
|
-
fields = RackGroup.csv_headers
|
|
461
|
-
|
|
462
|
-
|
|
463
381
|
class RackGroupFilterForm(NautobotFilterForm, LocatableModelFilterFormMixin):
|
|
464
382
|
model = RackGroup
|
|
465
383
|
parent = DynamicModelMultipleChoiceField(
|
|
@@ -519,36 +437,6 @@ class RackForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm):
|
|
|
519
437
|
}
|
|
520
438
|
|
|
521
439
|
|
|
522
|
-
class RackCSVForm(LocatableModelCSVFormMixin, StatusModelCSVFormMixin, RoleModelCSVFormMixin, CustomFieldModelCSVForm):
|
|
523
|
-
rack_group = CSVModelChoiceField(queryset=RackGroup.objects.all(), required=False, to_field_name="name")
|
|
524
|
-
tenant = CSVModelChoiceField(
|
|
525
|
-
queryset=Tenant.objects.all(),
|
|
526
|
-
required=False,
|
|
527
|
-
to_field_name="name",
|
|
528
|
-
help_text="Name of assigned tenant",
|
|
529
|
-
)
|
|
530
|
-
type = CSVChoiceField(choices=RackTypeChoices, required=False, help_text="Rack type")
|
|
531
|
-
width = forms.ChoiceField(choices=RackWidthChoices, help_text="Rail-to-rail width (in inches)")
|
|
532
|
-
outer_unit = CSVChoiceField(
|
|
533
|
-
choices=RackDimensionUnitChoices,
|
|
534
|
-
required=False,
|
|
535
|
-
help_text="Unit for outer dimensions",
|
|
536
|
-
)
|
|
537
|
-
|
|
538
|
-
class Meta:
|
|
539
|
-
model = Rack
|
|
540
|
-
fields = Rack.csv_headers
|
|
541
|
-
|
|
542
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
543
|
-
super().__init__(data, *args, **kwargs)
|
|
544
|
-
|
|
545
|
-
if data:
|
|
546
|
-
|
|
547
|
-
# Limit rack_group queryset by assigned location
|
|
548
|
-
params = {f"location__{self.fields['location'].to_field_name}": data.get("location")}
|
|
549
|
-
self.fields["rack_group"].queryset = self.fields["rack_group"].queryset.filter(**params)
|
|
550
|
-
|
|
551
|
-
|
|
552
440
|
class RackBulkEditForm(
|
|
553
441
|
TagsBulkEditFormMixin,
|
|
554
442
|
LocatableModelBulkEditFormMixin,
|
|
@@ -695,48 +583,6 @@ class RackReservationForm(NautobotModelForm, TenancyForm):
|
|
|
695
583
|
]
|
|
696
584
|
|
|
697
585
|
|
|
698
|
-
class RackReservationCSVForm(CustomFieldModelCSVForm):
|
|
699
|
-
location = CSVModelChoiceField(queryset=Location.objects.all(), to_field_name="name", help_text="Parent location")
|
|
700
|
-
rack_group = CSVModelChoiceField(
|
|
701
|
-
queryset=RackGroup.objects.all(),
|
|
702
|
-
to_field_name="name",
|
|
703
|
-
required=False,
|
|
704
|
-
help_text="Rack's group (if any)",
|
|
705
|
-
)
|
|
706
|
-
rack = CSVModelChoiceField(queryset=Rack.objects.all(), to_field_name="name", help_text="Rack")
|
|
707
|
-
units = SimpleArrayField(
|
|
708
|
-
base_field=forms.IntegerField(),
|
|
709
|
-
required=True,
|
|
710
|
-
help_text="Comma-separated list of individual unit numbers",
|
|
711
|
-
)
|
|
712
|
-
tenant = CSVModelChoiceField(
|
|
713
|
-
queryset=Tenant.objects.all(),
|
|
714
|
-
required=False,
|
|
715
|
-
to_field_name="name",
|
|
716
|
-
help_text="Assigned tenant",
|
|
717
|
-
)
|
|
718
|
-
|
|
719
|
-
class Meta:
|
|
720
|
-
model = RackReservation
|
|
721
|
-
fields = ("location", "rack_group", "rack", "units", "tenant", "description")
|
|
722
|
-
|
|
723
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
724
|
-
super().__init__(data, *args, **kwargs)
|
|
725
|
-
|
|
726
|
-
if data:
|
|
727
|
-
|
|
728
|
-
# Limit rack_group queryset by assigned location
|
|
729
|
-
params = {f"location__{self.fields['location'].to_field_name}": data.get("location")}
|
|
730
|
-
self.fields["rack_group"].queryset = self.fields["rack_group"].queryset.filter(**params)
|
|
731
|
-
|
|
732
|
-
# Limit rack queryset by assigned location and group
|
|
733
|
-
params = {
|
|
734
|
-
f"location__{self.fields['location'].to_field_name}": data.get("location"),
|
|
735
|
-
f"rack_group__{self.fields['rack_group'].to_field_name}": data.get("rack_group"),
|
|
736
|
-
}
|
|
737
|
-
self.fields["rack"].queryset = self.fields["rack"].queryset.filter(**params)
|
|
738
|
-
|
|
739
|
-
|
|
740
586
|
class RackReservationBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
741
587
|
pk = forms.ModelMultipleChoiceField(queryset=RackReservation.objects.all(), widget=forms.MultipleHiddenInput())
|
|
742
588
|
user = forms.ModelChoiceField(
|
|
@@ -785,23 +631,14 @@ class RackReservationFilterForm(NautobotFilterForm, TenancyFilterForm):
|
|
|
785
631
|
|
|
786
632
|
|
|
787
633
|
class ManufacturerForm(NautobotModelForm):
|
|
788
|
-
slug = SlugField()
|
|
789
|
-
|
|
790
634
|
class Meta:
|
|
791
635
|
model = Manufacturer
|
|
792
636
|
fields = [
|
|
793
637
|
"name",
|
|
794
|
-
"slug",
|
|
795
638
|
"description",
|
|
796
639
|
]
|
|
797
640
|
|
|
798
641
|
|
|
799
|
-
class ManufacturerCSVForm(CustomFieldModelCSVForm):
|
|
800
|
-
class Meta:
|
|
801
|
-
model = Manufacturer
|
|
802
|
-
fields = Manufacturer.csv_headers
|
|
803
|
-
|
|
804
|
-
|
|
805
642
|
#
|
|
806
643
|
# Device types
|
|
807
644
|
#
|
|
@@ -840,6 +677,14 @@ class DeviceTypeForm(NautobotModelForm):
|
|
|
840
677
|
|
|
841
678
|
|
|
842
679
|
class DeviceTypeImportForm(BootstrapMixin, forms.ModelForm):
|
|
680
|
+
"""
|
|
681
|
+
Form for JSON/YAML import of DeviceType objects.
|
|
682
|
+
|
|
683
|
+
TODO: at some point we'll want to add general-purpose YAML serialization/deserialization,
|
|
684
|
+
similar to what we've done for CSV in 2.0, but for the moment we're leaving this as-is so that we can remain
|
|
685
|
+
at least nominally compatible with the netbox-community/devicetype-library repo.
|
|
686
|
+
"""
|
|
687
|
+
|
|
843
688
|
manufacturer = forms.ModelChoiceField(queryset=Manufacturer.objects.all(), to_field_name="name")
|
|
844
689
|
|
|
845
690
|
class Meta:
|
|
@@ -1088,7 +933,6 @@ class PowerOutletTemplateForm(NautobotModelForm):
|
|
|
1088
933
|
}
|
|
1089
934
|
|
|
1090
935
|
def __init__(self, *args, **kwargs):
|
|
1091
|
-
|
|
1092
936
|
super().__init__(*args, **kwargs)
|
|
1093
937
|
|
|
1094
938
|
# Limit power_port_template choices to current DeviceType
|
|
@@ -1226,7 +1070,6 @@ class FrontPortTemplateForm(NautobotModelForm):
|
|
|
1226
1070
|
}
|
|
1227
1071
|
|
|
1228
1072
|
def __init__(self, *args, **kwargs):
|
|
1229
|
-
|
|
1230
1073
|
super().__init__(*args, **kwargs)
|
|
1231
1074
|
|
|
1232
1075
|
# Limit rear_port_template choices to current DeviceType
|
|
@@ -1295,7 +1138,6 @@ class FrontPortTemplateCreateForm(ComponentTemplateCreateForm):
|
|
|
1295
1138
|
)
|
|
1296
1139
|
|
|
1297
1140
|
def get_iterative_data(self, iteration):
|
|
1298
|
-
|
|
1299
1141
|
# Assign rear port and position from selected set
|
|
1300
1142
|
rear_port_template, position = self.cleaned_data["rear_port_template_set"][iteration].split(":")
|
|
1301
1143
|
|
|
@@ -1411,8 +1253,15 @@ class DeviceBayTemplateBulkEditForm(NautobotBulkEditForm):
|
|
|
1411
1253
|
|
|
1412
1254
|
|
|
1413
1255
|
class ComponentTemplateImportForm(BootstrapMixin, CustomFieldModelCSVForm):
|
|
1414
|
-
|
|
1256
|
+
"""
|
|
1257
|
+
Base form class for JSON/YAML import of device component templates as a part of the DeviceType import form/view.
|
|
1258
|
+
|
|
1259
|
+
TODO: at some point we'll want to switch to general-purpose YAML import support, similar to what we've done for
|
|
1260
|
+
CSV in 2.0, but for now we're keeping this as-is for nominal compatibility with the
|
|
1261
|
+
netbox-community/devicetype-library repository.
|
|
1262
|
+
"""
|
|
1415
1263
|
|
|
1264
|
+
def __init__(self, device_type, data=None, *args, **kwargs):
|
|
1416
1265
|
# Must pass the parent DeviceType on form initialization
|
|
1417
1266
|
data.update(
|
|
1418
1267
|
{
|
|
@@ -1423,7 +1272,6 @@ class ComponentTemplateImportForm(BootstrapMixin, CustomFieldModelCSVForm):
|
|
|
1423
1272
|
super().__init__(data, *args, **kwargs)
|
|
1424
1273
|
|
|
1425
1274
|
def clean_device_type(self):
|
|
1426
|
-
|
|
1427
1275
|
data = self.cleaned_data["device_type"]
|
|
1428
1276
|
|
|
1429
1277
|
# Limit fields referencing other components to the parent DeviceType
|
|
@@ -1568,13 +1416,11 @@ class DeviceBayTemplateImportForm(ComponentTemplateImportForm):
|
|
|
1568
1416
|
|
|
1569
1417
|
class PlatformForm(NautobotModelForm):
|
|
1570
1418
|
manufacturer = DynamicModelChoiceField(queryset=Manufacturer.objects.all(), required=False)
|
|
1571
|
-
slug = SlugField(max_length=64)
|
|
1572
1419
|
|
|
1573
1420
|
class Meta:
|
|
1574
1421
|
model = Platform
|
|
1575
1422
|
fields = [
|
|
1576
1423
|
"name",
|
|
1577
|
-
"slug",
|
|
1578
1424
|
"manufacturer",
|
|
1579
1425
|
"napalm_driver",
|
|
1580
1426
|
"napalm_args",
|
|
@@ -1585,19 +1431,6 @@ class PlatformForm(NautobotModelForm):
|
|
|
1585
1431
|
}
|
|
1586
1432
|
|
|
1587
1433
|
|
|
1588
|
-
class PlatformCSVForm(CustomFieldModelCSVForm):
|
|
1589
|
-
manufacturer = CSVModelChoiceField(
|
|
1590
|
-
queryset=Manufacturer.objects.all(),
|
|
1591
|
-
required=False,
|
|
1592
|
-
to_field_name="name",
|
|
1593
|
-
help_text="Limit platform assignments to this manufacturer",
|
|
1594
|
-
)
|
|
1595
|
-
|
|
1596
|
-
class Meta:
|
|
1597
|
-
model = Platform
|
|
1598
|
-
fields = Platform.csv_headers
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
1434
|
#
|
|
1602
1435
|
# Devices
|
|
1603
1436
|
#
|
|
@@ -1656,6 +1489,11 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1656
1489
|
required=False,
|
|
1657
1490
|
query_params={"group_id": "$cluster_group"},
|
|
1658
1491
|
)
|
|
1492
|
+
vrfs = DynamicModelMultipleChoiceField(
|
|
1493
|
+
queryset=VRF.objects.all(),
|
|
1494
|
+
required=False,
|
|
1495
|
+
label="VRFs",
|
|
1496
|
+
)
|
|
1659
1497
|
comments = CommentField()
|
|
1660
1498
|
|
|
1661
1499
|
class Meta:
|
|
@@ -1681,6 +1519,7 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1681
1519
|
"cluster",
|
|
1682
1520
|
"tenant_group",
|
|
1683
1521
|
"tenant",
|
|
1522
|
+
"vrfs",
|
|
1684
1523
|
"comments",
|
|
1685
1524
|
"tags",
|
|
1686
1525
|
"local_config_context_data",
|
|
@@ -1702,9 +1541,8 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1702
1541
|
super().__init__(*args, **kwargs)
|
|
1703
1542
|
|
|
1704
1543
|
if self.instance.present_in_database:
|
|
1705
|
-
|
|
1706
1544
|
# Compile list of choices for primary IPv4 and IPv6 addresses
|
|
1707
|
-
for
|
|
1545
|
+
for ip_version in [4, 6]:
|
|
1708
1546
|
ip_choices = [(None, "---------")]
|
|
1709
1547
|
|
|
1710
1548
|
# Gather PKs of all interfaces belonging to this Device or a peer VirtualChassis member
|
|
@@ -1721,7 +1559,7 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1721
1559
|
f"{assignment.ip_address.address} ({assignment.interface})",
|
|
1722
1560
|
)
|
|
1723
1561
|
for assignment in interface_ip_assignments
|
|
1724
|
-
if assignment.ip_address.
|
|
1562
|
+
if assignment.ip_address.ip_version == ip_version
|
|
1725
1563
|
]
|
|
1726
1564
|
ip_choices.append(("Interface IPs", ip_list))
|
|
1727
1565
|
|
|
@@ -1734,11 +1572,11 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1734
1572
|
[
|
|
1735
1573
|
(ip.id, f"{ip.address} (NAT)")
|
|
1736
1574
|
for ip in ip_assignment.ip_address.nat_outside_list.all()
|
|
1737
|
-
if ip.
|
|
1575
|
+
if ip.ip_version == ip_version
|
|
1738
1576
|
]
|
|
1739
1577
|
)
|
|
1740
1578
|
ip_choices.append(("NAT IPs", nat_ips))
|
|
1741
|
-
self.fields[f"primary_ip{
|
|
1579
|
+
self.fields[f"primary_ip{ip_version}"].choices = ip_choices
|
|
1742
1580
|
|
|
1743
1581
|
# If editing an existing device, exclude it from the list of occupied rack units. This ensures that a device
|
|
1744
1582
|
# can be flipped from one face to another.
|
|
@@ -1755,8 +1593,9 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1755
1593
|
self.initial["location"] = self.instance.parent_bay.device.location_id
|
|
1756
1594
|
self.initial["rack"] = self.instance.parent_bay.device.rack_id
|
|
1757
1595
|
|
|
1758
|
-
|
|
1596
|
+
self.initial["vrfs"] = self.instance.vrfs.values_list("id", flat=True)
|
|
1759
1597
|
|
|
1598
|
+
else:
|
|
1760
1599
|
# An object that doesn't exist yet can't have any IPs assigned to it
|
|
1761
1600
|
self.fields["primary_ip4"].choices = []
|
|
1762
1601
|
self.fields["primary_ip4"].widget.attrs["readonly"] = True
|
|
@@ -1768,166 +1607,10 @@ class DeviceForm(LocatableModelFormMixin, NautobotModelForm, TenancyForm, LocalC
|
|
|
1768
1607
|
if position:
|
|
1769
1608
|
self.fields["position"].widget.choices = [(position, f"U{position}")]
|
|
1770
1609
|
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
required=False,
|
|
1776
|
-
to_field_name="name",
|
|
1777
|
-
help_text="Assigned tenant",
|
|
1778
|
-
)
|
|
1779
|
-
manufacturer = CSVModelChoiceField(
|
|
1780
|
-
queryset=Manufacturer.objects.all(),
|
|
1781
|
-
to_field_name="name",
|
|
1782
|
-
help_text="Device type manufacturer",
|
|
1783
|
-
)
|
|
1784
|
-
device_type = CSVModelChoiceField(
|
|
1785
|
-
queryset=DeviceType.objects.all(),
|
|
1786
|
-
to_field_name="model",
|
|
1787
|
-
help_text="Device type model",
|
|
1788
|
-
)
|
|
1789
|
-
platform = CSVModelChoiceField(
|
|
1790
|
-
queryset=Platform.objects.all(),
|
|
1791
|
-
required=False,
|
|
1792
|
-
to_field_name="name",
|
|
1793
|
-
help_text="Assigned platform",
|
|
1794
|
-
)
|
|
1795
|
-
cluster = CSVModelChoiceField(
|
|
1796
|
-
queryset=Cluster.objects.all(),
|
|
1797
|
-
to_field_name="name",
|
|
1798
|
-
required=False,
|
|
1799
|
-
help_text="Virtualization cluster",
|
|
1800
|
-
)
|
|
1801
|
-
secrets_group = CSVModelChoiceField(
|
|
1802
|
-
queryset=SecretsGroup.objects.all(),
|
|
1803
|
-
required=False,
|
|
1804
|
-
to_field_name="name",
|
|
1805
|
-
help_text="Secrets group",
|
|
1806
|
-
)
|
|
1807
|
-
|
|
1808
|
-
class Meta:
|
|
1809
|
-
fields = []
|
|
1810
|
-
model = Device
|
|
1811
|
-
|
|
1812
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
1813
|
-
super().__init__(data, *args, **kwargs)
|
|
1814
|
-
|
|
1815
|
-
if data:
|
|
1816
|
-
|
|
1817
|
-
# Limit device type queryset by manufacturer
|
|
1818
|
-
params = {f"manufacturer__{self.fields['manufacturer'].to_field_name}": data.get("manufacturer")}
|
|
1819
|
-
self.fields["device_type"].queryset = self.fields["device_type"].queryset.filter(**params)
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
class DeviceCSVForm(LocatableModelCSVFormMixin, BaseDeviceCSVForm, RoleRequiredRoleModelCSVFormMixin):
|
|
1823
|
-
rack_group = CSVModelChoiceField(
|
|
1824
|
-
queryset=RackGroup.objects.all(),
|
|
1825
|
-
to_field_name="name",
|
|
1826
|
-
required=False,
|
|
1827
|
-
help_text="Rack's group (if any)",
|
|
1828
|
-
)
|
|
1829
|
-
rack = CSVModelChoiceField(
|
|
1830
|
-
queryset=Rack.objects.all(),
|
|
1831
|
-
to_field_name="name",
|
|
1832
|
-
required=False,
|
|
1833
|
-
help_text="Assigned rack",
|
|
1834
|
-
)
|
|
1835
|
-
face = CSVChoiceField(choices=DeviceFaceChoices, required=False, help_text="Mounted rack face")
|
|
1836
|
-
device_redundancy_group = CSVModelChoiceField(
|
|
1837
|
-
queryset=DeviceRedundancyGroup.objects.all(),
|
|
1838
|
-
to_field_name="slug",
|
|
1839
|
-
required=False,
|
|
1840
|
-
help_text="Associated device redundancy group (slug)",
|
|
1841
|
-
)
|
|
1842
|
-
|
|
1843
|
-
class Meta(BaseDeviceCSVForm.Meta):
|
|
1844
|
-
fields = [
|
|
1845
|
-
"name",
|
|
1846
|
-
"role",
|
|
1847
|
-
"tenant",
|
|
1848
|
-
"manufacturer",
|
|
1849
|
-
"device_type",
|
|
1850
|
-
"platform",
|
|
1851
|
-
"serial",
|
|
1852
|
-
"asset_tag",
|
|
1853
|
-
"status",
|
|
1854
|
-
"location",
|
|
1855
|
-
"rack_group",
|
|
1856
|
-
"rack",
|
|
1857
|
-
"position",
|
|
1858
|
-
"face",
|
|
1859
|
-
"device_redundancy_group",
|
|
1860
|
-
"device_redundancy_group_priority",
|
|
1861
|
-
"cluster",
|
|
1862
|
-
"comments",
|
|
1863
|
-
]
|
|
1864
|
-
|
|
1865
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
1866
|
-
super().__init__(data, *args, **kwargs)
|
|
1867
|
-
|
|
1868
|
-
if data:
|
|
1869
|
-
|
|
1870
|
-
# Limit rack_group queryset by assigned location
|
|
1871
|
-
params = {f"location__{self.fields['location'].to_field_name}": data.get("location")}
|
|
1872
|
-
self.fields["rack_group"].queryset = self.fields["rack_group"].queryset.filter(**params)
|
|
1873
|
-
|
|
1874
|
-
# Limit rack queryset by assigned location and group
|
|
1875
|
-
params = {
|
|
1876
|
-
f"location__{self.fields['location'].to_field_name}": data.get("location"),
|
|
1877
|
-
f"rack_group__{self.fields['rack_group'].to_field_name}": data.get("rack_group"),
|
|
1878
|
-
}
|
|
1879
|
-
self.fields["rack"].queryset = self.fields["rack"].queryset.filter(**params)
|
|
1880
|
-
|
|
1881
|
-
# 2.0 TODO: limit location queryset by assigned location
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
class ChildDeviceCSVForm(BaseDeviceCSVForm):
|
|
1885
|
-
parent = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name", help_text="Parent device")
|
|
1886
|
-
device_bay = CSVModelChoiceField(
|
|
1887
|
-
queryset=DeviceBay.objects.all(),
|
|
1888
|
-
to_field_name="name",
|
|
1889
|
-
help_text="Device bay in which this device is installed",
|
|
1890
|
-
)
|
|
1891
|
-
|
|
1892
|
-
class Meta(BaseDeviceCSVForm.Meta):
|
|
1893
|
-
fields = [
|
|
1894
|
-
"name",
|
|
1895
|
-
"role",
|
|
1896
|
-
"tenant",
|
|
1897
|
-
"manufacturer",
|
|
1898
|
-
"device_type",
|
|
1899
|
-
"platform",
|
|
1900
|
-
"serial",
|
|
1901
|
-
"asset_tag",
|
|
1902
|
-
"status",
|
|
1903
|
-
"parent",
|
|
1904
|
-
"device_bay",
|
|
1905
|
-
"cluster",
|
|
1906
|
-
"comments",
|
|
1907
|
-
]
|
|
1908
|
-
|
|
1909
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
1910
|
-
super().__init__(data, *args, **kwargs)
|
|
1911
|
-
|
|
1912
|
-
if data:
|
|
1913
|
-
|
|
1914
|
-
# Limit device bay queryset by parent device
|
|
1915
|
-
params = {f"device__{self.fields['parent'].to_field_name}": data.get("parent")}
|
|
1916
|
-
self.fields["device_bay"].queryset = self.fields["device_bay"].queryset.filter(**params)
|
|
1917
|
-
|
|
1918
|
-
def clean(self):
|
|
1919
|
-
super().clean()
|
|
1920
|
-
|
|
1921
|
-
# Set parent_bay reverse relationship
|
|
1922
|
-
device_bay = self.cleaned_data.get("device_bay")
|
|
1923
|
-
if device_bay:
|
|
1924
|
-
self.instance.parent_bay = device_bay
|
|
1925
|
-
|
|
1926
|
-
# Inherit location and rack from parent device
|
|
1927
|
-
parent = self.cleaned_data.get("parent")
|
|
1928
|
-
if parent:
|
|
1929
|
-
self.instance.location = parent.location
|
|
1930
|
-
self.instance.rack = parent.rack
|
|
1610
|
+
def save(self, *args, **kwargs):
|
|
1611
|
+
instance = super().save(*args, **kwargs)
|
|
1612
|
+
instance.vrfs.set(self.cleaned_data["vrfs"])
|
|
1613
|
+
return instance
|
|
1931
1614
|
|
|
1932
1615
|
|
|
1933
1616
|
class DeviceBulkEditForm(
|
|
@@ -2025,7 +1708,7 @@ class DeviceFilterForm(
|
|
|
2025
1708
|
)
|
|
2026
1709
|
manufacturer = DynamicModelMultipleChoiceField(
|
|
2027
1710
|
queryset=Manufacturer.objects.all(),
|
|
2028
|
-
to_field_name="
|
|
1711
|
+
to_field_name="name",
|
|
2029
1712
|
required=False,
|
|
2030
1713
|
label="Manufacturer",
|
|
2031
1714
|
)
|
|
@@ -2037,14 +1720,14 @@ class DeviceFilterForm(
|
|
|
2037
1720
|
)
|
|
2038
1721
|
platform = DynamicModelMultipleChoiceField(
|
|
2039
1722
|
queryset=Platform.objects.all(),
|
|
2040
|
-
to_field_name="
|
|
1723
|
+
to_field_name="name",
|
|
2041
1724
|
required=False,
|
|
2042
1725
|
null_option="None",
|
|
2043
1726
|
)
|
|
2044
1727
|
mac_address = forms.CharField(required=False, label="MAC address")
|
|
2045
1728
|
device_redundancy_group = DynamicModelMultipleChoiceField(
|
|
2046
1729
|
queryset=DeviceRedundancyGroup.objects.all(),
|
|
2047
|
-
to_field_name="
|
|
1730
|
+
to_field_name="name",
|
|
2048
1731
|
required=False,
|
|
2049
1732
|
null_option="None",
|
|
2050
1733
|
)
|
|
@@ -2177,15 +1860,6 @@ class ConsolePortBulkEditForm(
|
|
|
2177
1860
|
nullable_fields = ["label", "description"]
|
|
2178
1861
|
|
|
2179
1862
|
|
|
2180
|
-
class ConsolePortCSVForm(CustomFieldModelCSVForm):
|
|
2181
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
2182
|
-
type = CSVChoiceField(choices=ConsolePortTypeChoices, required=False, help_text="Port type")
|
|
2183
|
-
|
|
2184
|
-
class Meta:
|
|
2185
|
-
model = ConsolePort
|
|
2186
|
-
fields = ConsolePort.csv_headers
|
|
2187
|
-
|
|
2188
|
-
|
|
2189
1863
|
#
|
|
2190
1864
|
# Console server ports
|
|
2191
1865
|
#
|
|
@@ -2244,15 +1918,6 @@ class ConsoleServerPortBulkEditForm(
|
|
|
2244
1918
|
nullable_fields = ["label", "description"]
|
|
2245
1919
|
|
|
2246
1920
|
|
|
2247
|
-
class ConsoleServerPortCSVForm(CustomFieldModelCSVForm):
|
|
2248
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
2249
|
-
type = CSVChoiceField(choices=ConsolePortTypeChoices, required=False, help_text="Port type")
|
|
2250
|
-
|
|
2251
|
-
class Meta:
|
|
2252
|
-
model = ConsoleServerPort
|
|
2253
|
-
fields = ConsoleServerPort.csv_headers
|
|
2254
|
-
|
|
2255
|
-
|
|
2256
1921
|
#
|
|
2257
1922
|
# Power ports
|
|
2258
1923
|
#
|
|
@@ -2328,15 +1993,6 @@ class PowerPortBulkEditForm(
|
|
|
2328
1993
|
nullable_fields = ["label", "description"]
|
|
2329
1994
|
|
|
2330
1995
|
|
|
2331
|
-
class PowerPortCSVForm(CustomFieldModelCSVForm):
|
|
2332
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
2333
|
-
type = CSVChoiceField(choices=PowerPortTypeChoices, required=False, help_text="Port type")
|
|
2334
|
-
|
|
2335
|
-
class Meta:
|
|
2336
|
-
model = PowerPort
|
|
2337
|
-
fields = PowerPort.csv_headers
|
|
2338
|
-
|
|
2339
|
-
|
|
2340
1996
|
#
|
|
2341
1997
|
# Power outlets
|
|
2342
1998
|
#
|
|
@@ -2441,46 +2097,6 @@ class PowerOutletBulkEditForm(
|
|
|
2441
2097
|
self.fields["power_port"].widget.attrs["disabled"] = True
|
|
2442
2098
|
|
|
2443
2099
|
|
|
2444
|
-
class PowerOutletCSVForm(CustomFieldModelCSVForm):
|
|
2445
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
2446
|
-
type = CSVChoiceField(choices=PowerOutletTypeChoices, required=False, help_text="Outlet type")
|
|
2447
|
-
power_port = CSVModelChoiceField(
|
|
2448
|
-
queryset=PowerPort.objects.all(),
|
|
2449
|
-
required=False,
|
|
2450
|
-
to_field_name="name",
|
|
2451
|
-
help_text="Local power port which feeds this outlet",
|
|
2452
|
-
)
|
|
2453
|
-
feed_leg = CSVChoiceField(
|
|
2454
|
-
choices=PowerOutletFeedLegChoices,
|
|
2455
|
-
required=False,
|
|
2456
|
-
help_text="Electrical phase (for three-phase circuits)",
|
|
2457
|
-
)
|
|
2458
|
-
|
|
2459
|
-
class Meta:
|
|
2460
|
-
model = PowerOutlet
|
|
2461
|
-
fields = PowerOutlet.csv_headers
|
|
2462
|
-
|
|
2463
|
-
def __init__(self, *args, **kwargs):
|
|
2464
|
-
super().__init__(*args, **kwargs)
|
|
2465
|
-
|
|
2466
|
-
# Limit PowerPort choices to those belonging to this device (or VC master)
|
|
2467
|
-
if self.is_bound:
|
|
2468
|
-
try:
|
|
2469
|
-
device = self.fields["device"].to_python(self.data["device"])
|
|
2470
|
-
except forms.ValidationError:
|
|
2471
|
-
device = None
|
|
2472
|
-
else:
|
|
2473
|
-
try:
|
|
2474
|
-
device = self.instance.device
|
|
2475
|
-
except Device.DoesNotExist:
|
|
2476
|
-
device = None
|
|
2477
|
-
|
|
2478
|
-
if device:
|
|
2479
|
-
self.fields["power_port"].queryset = PowerPort.objects.filter(device__in=[device, device.get_vc_master()])
|
|
2480
|
-
else:
|
|
2481
|
-
self.fields["power_port"].queryset = PowerPort.objects.none()
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
2100
|
#
|
|
2485
2101
|
# Interfaces
|
|
2486
2102
|
#
|
|
@@ -2524,7 +2140,6 @@ class InterfaceForm(InterfaceCommonForm, NautobotModelForm):
|
|
|
2524
2140
|
queryset=VLAN.objects.all(),
|
|
2525
2141
|
required=False,
|
|
2526
2142
|
label="Untagged VLAN",
|
|
2527
|
-
brief_mode=False,
|
|
2528
2143
|
query_params={
|
|
2529
2144
|
"location": "null",
|
|
2530
2145
|
},
|
|
@@ -2533,7 +2148,6 @@ class InterfaceForm(InterfaceCommonForm, NautobotModelForm):
|
|
|
2533
2148
|
queryset=VLAN.objects.all(),
|
|
2534
2149
|
required=False,
|
|
2535
2150
|
label="Tagged VLANs",
|
|
2536
|
-
brief_mode=False,
|
|
2537
2151
|
query_params={
|
|
2538
2152
|
"location": "null",
|
|
2539
2153
|
},
|
|
@@ -2542,7 +2156,6 @@ class InterfaceForm(InterfaceCommonForm, NautobotModelForm):
|
|
|
2542
2156
|
queryset=IPAddress.objects.all(),
|
|
2543
2157
|
required=False,
|
|
2544
2158
|
label="IP Addresses",
|
|
2545
|
-
brief_mode=False,
|
|
2546
2159
|
)
|
|
2547
2160
|
|
|
2548
2161
|
class Meta:
|
|
@@ -2559,6 +2172,7 @@ class InterfaceForm(InterfaceCommonForm, NautobotModelForm):
|
|
|
2559
2172
|
"mac_address",
|
|
2560
2173
|
"ip_addresses",
|
|
2561
2174
|
"mtu",
|
|
2175
|
+
"vrf",
|
|
2562
2176
|
"mgmt_only",
|
|
2563
2177
|
"description",
|
|
2564
2178
|
"mode",
|
|
@@ -2571,9 +2185,11 @@ class InterfaceForm(InterfaceCommonForm, NautobotModelForm):
|
|
|
2571
2185
|
"device": forms.HiddenInput(),
|
|
2572
2186
|
"type": StaticSelect2(),
|
|
2573
2187
|
"mode": StaticSelect2(),
|
|
2188
|
+
"vrf": StaticSelect2(),
|
|
2574
2189
|
}
|
|
2575
2190
|
labels = {
|
|
2576
2191
|
"mode": "802.1Q Mode",
|
|
2192
|
+
"vrf": "VRF",
|
|
2577
2193
|
}
|
|
2578
2194
|
help_texts = {
|
|
2579
2195
|
"mode": INTERFACE_MODE_HELP_TEXT,
|
|
@@ -2641,6 +2257,14 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
2641
2257
|
max_value=INTERFACE_MTU_MAX,
|
|
2642
2258
|
label="MTU",
|
|
2643
2259
|
)
|
|
2260
|
+
vrf = DynamicModelChoiceField(
|
|
2261
|
+
queryset=VRF.objects.all(),
|
|
2262
|
+
label="VRF",
|
|
2263
|
+
required=False,
|
|
2264
|
+
query_params={
|
|
2265
|
+
"device": "$device",
|
|
2266
|
+
},
|
|
2267
|
+
)
|
|
2644
2268
|
mac_address = forms.CharField(required=False, label="MAC Address")
|
|
2645
2269
|
mgmt_only = forms.BooleanField(
|
|
2646
2270
|
required=False,
|
|
@@ -2655,7 +2279,6 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
2655
2279
|
untagged_vlan = DynamicModelChoiceField(
|
|
2656
2280
|
queryset=VLAN.objects.all(),
|
|
2657
2281
|
required=False,
|
|
2658
|
-
brief_mode=False,
|
|
2659
2282
|
query_params={
|
|
2660
2283
|
"available_on_device": "$device",
|
|
2661
2284
|
},
|
|
@@ -2663,7 +2286,6 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
2663
2286
|
tagged_vlans = DynamicModelMultipleChoiceField(
|
|
2664
2287
|
queryset=VLAN.objects.all(),
|
|
2665
2288
|
required=False,
|
|
2666
|
-
brief_mode=False,
|
|
2667
2289
|
query_params={"available_on_device": "$device"},
|
|
2668
2290
|
)
|
|
2669
2291
|
field_order = (
|
|
@@ -2677,6 +2299,7 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
2677
2299
|
"bridge",
|
|
2678
2300
|
"lag",
|
|
2679
2301
|
"mtu",
|
|
2302
|
+
"vrf",
|
|
2680
2303
|
"mac_address",
|
|
2681
2304
|
"description",
|
|
2682
2305
|
"mgmt_only",
|
|
@@ -2688,7 +2311,7 @@ class InterfaceCreateForm(ComponentCreateForm, InterfaceCommonForm):
|
|
|
2688
2311
|
|
|
2689
2312
|
|
|
2690
2313
|
class InterfaceBulkCreateForm(
|
|
2691
|
-
form_from_model(Interface, ["enabled", "mtu", "mgmt_only", "mode", "tags"]),
|
|
2314
|
+
form_from_model(Interface, ["enabled", "mtu", "vrf", "mgmt_only", "mode", "tags"]),
|
|
2692
2315
|
DeviceBulkAddComponentForm,
|
|
2693
2316
|
):
|
|
2694
2317
|
type = forms.ChoiceField(
|
|
@@ -2708,6 +2331,7 @@ class InterfaceBulkCreateForm(
|
|
|
2708
2331
|
"type",
|
|
2709
2332
|
"enabled",
|
|
2710
2333
|
"mtu",
|
|
2334
|
+
"vrf",
|
|
2711
2335
|
"mgmt_only",
|
|
2712
2336
|
"description",
|
|
2713
2337
|
"mode",
|
|
@@ -2753,7 +2377,6 @@ class InterfaceBulkEditForm(
|
|
|
2753
2377
|
untagged_vlan = DynamicModelChoiceField(
|
|
2754
2378
|
queryset=VLAN.objects.all(),
|
|
2755
2379
|
required=False,
|
|
2756
|
-
brief_mode=False,
|
|
2757
2380
|
query_params={
|
|
2758
2381
|
"location": "null",
|
|
2759
2382
|
},
|
|
@@ -2761,7 +2384,6 @@ class InterfaceBulkEditForm(
|
|
|
2761
2384
|
tagged_vlans = DynamicModelMultipleChoiceField(
|
|
2762
2385
|
queryset=VLAN.objects.all(),
|
|
2763
2386
|
required=False,
|
|
2764
|
-
brief_mode=False,
|
|
2765
2387
|
query_params={
|
|
2766
2388
|
"location": "null",
|
|
2767
2389
|
},
|
|
@@ -2834,67 +2456,6 @@ class InterfaceBulkEditForm(
|
|
|
2834
2456
|
self.cleaned_data["tagged_vlans"] = []
|
|
2835
2457
|
|
|
2836
2458
|
|
|
2837
|
-
class InterfaceCSVForm(CustomFieldModelCSVForm, StatusModelCSVFormMixin):
|
|
2838
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
2839
|
-
parent_interface = CSVModelChoiceField(
|
|
2840
|
-
queryset=Interface.objects.all(), required=False, to_field_name="name", help_text="Parent interface"
|
|
2841
|
-
)
|
|
2842
|
-
bridge = CSVModelChoiceField(
|
|
2843
|
-
queryset=Interface.objects.all(), required=False, to_field_name="name", help_text="Bridge interface"
|
|
2844
|
-
)
|
|
2845
|
-
lag = CSVModelChoiceField(
|
|
2846
|
-
queryset=Interface.objects.all(),
|
|
2847
|
-
required=False,
|
|
2848
|
-
to_field_name="name",
|
|
2849
|
-
help_text="Parent LAG interface",
|
|
2850
|
-
)
|
|
2851
|
-
type = CSVChoiceField(choices=InterfaceTypeChoices, help_text="Physical medium")
|
|
2852
|
-
mode = CSVChoiceField(
|
|
2853
|
-
choices=InterfaceModeChoices,
|
|
2854
|
-
required=False,
|
|
2855
|
-
help_text="IEEE 802.1Q operational mode (for L2 interfaces)",
|
|
2856
|
-
)
|
|
2857
|
-
|
|
2858
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
2859
|
-
super().__init__(data, *args, **kwargs)
|
|
2860
|
-
|
|
2861
|
-
if data:
|
|
2862
|
-
# Limit choices for parent, bridge, and LAG interfaces to the assigned device (or VC)
|
|
2863
|
-
device_name = data.get("device")
|
|
2864
|
-
if device_name is not None:
|
|
2865
|
-
device = Device.objects.filter(name=device_name).first()
|
|
2866
|
-
|
|
2867
|
-
filter_by = Q(device=device)
|
|
2868
|
-
|
|
2869
|
-
if device and device.virtual_chassis:
|
|
2870
|
-
filter_by |= Q(device__virtual_chassis=device.virtual_chassis)
|
|
2871
|
-
|
|
2872
|
-
self.fields["parent_interface"].queryset = (
|
|
2873
|
-
self.fields["parent_interface"]
|
|
2874
|
-
.queryset.filter(Q(filter_by))
|
|
2875
|
-
.exclude(type__in=NONCONNECTABLE_IFACE_TYPES)
|
|
2876
|
-
)
|
|
2877
|
-
self.fields["bridge"].queryset = self.fields["bridge"].queryset.filter(filter_by)
|
|
2878
|
-
|
|
2879
|
-
filter_by &= Q(type=InterfaceTypeChoices.TYPE_LAG)
|
|
2880
|
-
self.fields["lag"].queryset = self.fields["lag"].queryset.filter(filter_by)
|
|
2881
|
-
else:
|
|
2882
|
-
self.fields["parent_interface"].queryset = self.fields["parent_interface"].queryset.none()
|
|
2883
|
-
self.fields["bridge"].queryset = self.fields["bridge"].queryset.none()
|
|
2884
|
-
self.fields["lag"].queryset = self.fields["lag"].queryset.none()
|
|
2885
|
-
|
|
2886
|
-
class Meta:
|
|
2887
|
-
model = Interface
|
|
2888
|
-
fields = Interface.csv_headers
|
|
2889
|
-
|
|
2890
|
-
def clean_enabled(self):
|
|
2891
|
-
# Make sure enabled is True when it's not included in the uploaded data
|
|
2892
|
-
if "enabled" not in self.data:
|
|
2893
|
-
return True
|
|
2894
|
-
else:
|
|
2895
|
-
return self.cleaned_data["enabled"]
|
|
2896
|
-
|
|
2897
|
-
|
|
2898
2459
|
#
|
|
2899
2460
|
# Front pass-through ports
|
|
2900
2461
|
#
|
|
@@ -2996,7 +2557,6 @@ class FrontPortCreateForm(ComponentCreateForm):
|
|
|
2996
2557
|
)
|
|
2997
2558
|
|
|
2998
2559
|
def get_iterative_data(self, iteration):
|
|
2999
|
-
|
|
3000
2560
|
# Assign rear port and position from selected set
|
|
3001
2561
|
rear_port, position = self.cleaned_data["rear_port_set"][iteration].split(":")
|
|
3002
2562
|
|
|
@@ -3024,43 +2584,6 @@ class FrontPortBulkEditForm(
|
|
|
3024
2584
|
nullable_fields = ["label", "description"]
|
|
3025
2585
|
|
|
3026
2586
|
|
|
3027
|
-
class FrontPortCSVForm(CustomFieldModelCSVForm):
|
|
3028
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
3029
|
-
rear_port = CSVModelChoiceField(
|
|
3030
|
-
queryset=RearPort.objects.all(),
|
|
3031
|
-
to_field_name="name",
|
|
3032
|
-
help_text="Corresponding rear port",
|
|
3033
|
-
)
|
|
3034
|
-
type = CSVChoiceField(choices=PortTypeChoices, help_text="Physical medium classification")
|
|
3035
|
-
|
|
3036
|
-
class Meta:
|
|
3037
|
-
model = FrontPort
|
|
3038
|
-
fields = FrontPort.csv_headers
|
|
3039
|
-
help_texts = {
|
|
3040
|
-
"rear_port_position": "Mapped position on corresponding rear port",
|
|
3041
|
-
}
|
|
3042
|
-
|
|
3043
|
-
def __init__(self, *args, **kwargs):
|
|
3044
|
-
super().__init__(*args, **kwargs)
|
|
3045
|
-
|
|
3046
|
-
# Limit RearPort choices to those belonging to this device (or VC master)
|
|
3047
|
-
if self.is_bound:
|
|
3048
|
-
try:
|
|
3049
|
-
device = self.fields["device"].to_python(self.data["device"])
|
|
3050
|
-
except forms.ValidationError:
|
|
3051
|
-
device = None
|
|
3052
|
-
else:
|
|
3053
|
-
try:
|
|
3054
|
-
device = self.instance.device
|
|
3055
|
-
except Device.DoesNotExist:
|
|
3056
|
-
device = None
|
|
3057
|
-
|
|
3058
|
-
if device:
|
|
3059
|
-
self.fields["rear_port"].queryset = RearPort.objects.filter(device__in=[device, device.get_vc_master()])
|
|
3060
|
-
else:
|
|
3061
|
-
self.fields["rear_port"].queryset = RearPort.objects.none()
|
|
3062
|
-
|
|
3063
|
-
|
|
3064
2587
|
#
|
|
3065
2588
|
# Rear pass-through ports
|
|
3066
2589
|
#
|
|
@@ -3134,19 +2657,6 @@ class RearPortBulkEditForm(
|
|
|
3134
2657
|
nullable_fields = ["label", "description"]
|
|
3135
2658
|
|
|
3136
2659
|
|
|
3137
|
-
class RearPortCSVForm(CustomFieldModelCSVForm):
|
|
3138
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
3139
|
-
type = CSVChoiceField(
|
|
3140
|
-
help_text="Physical medium classification",
|
|
3141
|
-
choices=PortTypeChoices,
|
|
3142
|
-
)
|
|
3143
|
-
|
|
3144
|
-
class Meta:
|
|
3145
|
-
model = RearPort
|
|
3146
|
-
fields = RearPort.csv_headers
|
|
3147
|
-
help_texts = {"positions": "Number of front ports which may be mapped"}
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
2660
|
#
|
|
3151
2661
|
# Device bays
|
|
3152
2662
|
#
|
|
@@ -3185,7 +2695,6 @@ class PopulateDeviceBayForm(BootstrapMixin, forms.Form):
|
|
|
3185
2695
|
)
|
|
3186
2696
|
|
|
3187
2697
|
def __init__(self, device_bay, *args, **kwargs):
|
|
3188
|
-
|
|
3189
2698
|
super().__init__(*args, **kwargs)
|
|
3190
2699
|
|
|
3191
2700
|
self.fields["installed_device"].queryset = Device.objects.filter(
|
|
@@ -3212,49 +2721,6 @@ class DeviceBayBulkEditForm(
|
|
|
3212
2721
|
nullable_fields = ["label", "description"]
|
|
3213
2722
|
|
|
3214
2723
|
|
|
3215
|
-
class DeviceBayCSVForm(CustomFieldModelCSVForm):
|
|
3216
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
3217
|
-
installed_device = CSVModelChoiceField(
|
|
3218
|
-
queryset=Device.objects.all(),
|
|
3219
|
-
required=False,
|
|
3220
|
-
to_field_name="name",
|
|
3221
|
-
help_text="Child device installed within this bay",
|
|
3222
|
-
error_messages={
|
|
3223
|
-
"invalid_choice": "Child device not found.",
|
|
3224
|
-
},
|
|
3225
|
-
)
|
|
3226
|
-
|
|
3227
|
-
class Meta:
|
|
3228
|
-
model = DeviceBay
|
|
3229
|
-
fields = DeviceBay.csv_headers
|
|
3230
|
-
|
|
3231
|
-
def __init__(self, *args, **kwargs):
|
|
3232
|
-
super().__init__(*args, **kwargs)
|
|
3233
|
-
|
|
3234
|
-
# Limit installed device choices to devices of the correct type and location
|
|
3235
|
-
if self.is_bound:
|
|
3236
|
-
try:
|
|
3237
|
-
device = self.fields["device"].to_python(self.data["device"])
|
|
3238
|
-
except forms.ValidationError:
|
|
3239
|
-
device = None
|
|
3240
|
-
else:
|
|
3241
|
-
try:
|
|
3242
|
-
device = self.instance.device
|
|
3243
|
-
except Device.DoesNotExist:
|
|
3244
|
-
device = None
|
|
3245
|
-
|
|
3246
|
-
if device:
|
|
3247
|
-
self.fields["installed_device"].queryset = Device.objects.filter(
|
|
3248
|
-
location=device.location,
|
|
3249
|
-
rack=device.rack,
|
|
3250
|
-
parent_bay__isnull=True,
|
|
3251
|
-
device_type__u_height=0,
|
|
3252
|
-
device_type__subdevice_role=SubdeviceRoleChoices.ROLE_CHILD,
|
|
3253
|
-
).exclude(pk=device.pk)
|
|
3254
|
-
else:
|
|
3255
|
-
self.fields["installed_device"].queryset = Interface.objects.none()
|
|
3256
|
-
|
|
3257
|
-
|
|
3258
2724
|
#
|
|
3259
2725
|
# Inventory items
|
|
3260
2726
|
#
|
|
@@ -3315,15 +2781,6 @@ class InventoryItemCreateForm(ComponentCreateForm):
|
|
|
3315
2781
|
)
|
|
3316
2782
|
|
|
3317
2783
|
|
|
3318
|
-
class InventoryItemCSVForm(CustomFieldModelCSVForm):
|
|
3319
|
-
device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name")
|
|
3320
|
-
manufacturer = CSVModelChoiceField(queryset=Manufacturer.objects.all(), to_field_name="name", required=False)
|
|
3321
|
-
|
|
3322
|
-
class Meta:
|
|
3323
|
-
model = InventoryItem
|
|
3324
|
-
fields = InventoryItem.csv_headers
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
2784
|
class InventoryItemBulkCreateForm(
|
|
3328
2785
|
form_from_model(InventoryItem, ["manufacturer", "part_id", "serial", "asset_tag", "discovered", "tags"]),
|
|
3329
2786
|
DeviceBulkAddComponentForm,
|
|
@@ -3356,7 +2813,7 @@ class InventoryItemBulkEditForm(
|
|
|
3356
2813
|
class InventoryItemFilterForm(DeviceComponentFilterForm):
|
|
3357
2814
|
model = InventoryItem
|
|
3358
2815
|
manufacturer = DynamicModelMultipleChoiceField(
|
|
3359
|
-
queryset=Manufacturer.objects.all(), to_field_name="
|
|
2816
|
+
queryset=Manufacturer.objects.all(), to_field_name="name", required=False
|
|
3360
2817
|
)
|
|
3361
2818
|
serial = forms.CharField(required=False)
|
|
3362
2819
|
asset_tag = forms.CharField(required=False)
|
|
@@ -3600,109 +3057,6 @@ class CableForm(NautobotModelForm):
|
|
|
3600
3057
|
error_messages = {"length": {"max_value": "Maximum length is 32767 (any unit)"}}
|
|
3601
3058
|
|
|
3602
3059
|
|
|
3603
|
-
class CableCSVForm(StatusModelCSVFormMixin, CustomFieldModelCSVForm):
|
|
3604
|
-
# Termination A
|
|
3605
|
-
side_a_device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name", help_text="Side A device")
|
|
3606
|
-
side_a_type = CSVContentTypeField(
|
|
3607
|
-
queryset=ContentType.objects.all(),
|
|
3608
|
-
limit_choices_to=CABLE_TERMINATION_MODELS,
|
|
3609
|
-
help_text="Side A type",
|
|
3610
|
-
)
|
|
3611
|
-
side_a_name = forms.CharField(help_text="Side A component name")
|
|
3612
|
-
|
|
3613
|
-
# Termination B
|
|
3614
|
-
side_b_device = CSVModelChoiceField(queryset=Device.objects.all(), to_field_name="name", help_text="Side B device")
|
|
3615
|
-
side_b_type = CSVContentTypeField(
|
|
3616
|
-
queryset=ContentType.objects.all(),
|
|
3617
|
-
limit_choices_to=CABLE_TERMINATION_MODELS,
|
|
3618
|
-
help_text="Side B type",
|
|
3619
|
-
)
|
|
3620
|
-
side_b_name = forms.CharField(help_text="Side B component name")
|
|
3621
|
-
|
|
3622
|
-
# Cable attributes
|
|
3623
|
-
type = CSVChoiceField(
|
|
3624
|
-
choices=CableTypeChoices,
|
|
3625
|
-
required=False,
|
|
3626
|
-
help_text="Physical medium classification",
|
|
3627
|
-
)
|
|
3628
|
-
length_unit = CSVChoiceField(choices=CableLengthUnitChoices, required=False, help_text="Length unit")
|
|
3629
|
-
|
|
3630
|
-
class Meta:
|
|
3631
|
-
model = Cable
|
|
3632
|
-
fields = [
|
|
3633
|
-
"side_a_device",
|
|
3634
|
-
"side_a_type",
|
|
3635
|
-
"side_a_name",
|
|
3636
|
-
"side_b_device",
|
|
3637
|
-
"side_b_type",
|
|
3638
|
-
"side_b_name",
|
|
3639
|
-
"type",
|
|
3640
|
-
"status",
|
|
3641
|
-
"label",
|
|
3642
|
-
"color",
|
|
3643
|
-
"length",
|
|
3644
|
-
"length_unit",
|
|
3645
|
-
]
|
|
3646
|
-
help_texts = {
|
|
3647
|
-
"color": mark_safe("RGB color in hexadecimal (e.g. <code>00ff00</code>)"),
|
|
3648
|
-
"status": "Connection status",
|
|
3649
|
-
}
|
|
3650
|
-
|
|
3651
|
-
def _clean_side(self, side):
|
|
3652
|
-
"""
|
|
3653
|
-
Derive a Cable's A/B termination objects.
|
|
3654
|
-
|
|
3655
|
-
:param side: 'a' or 'b'
|
|
3656
|
-
"""
|
|
3657
|
-
assert side in "ab", f"Invalid side designation: {side}"
|
|
3658
|
-
|
|
3659
|
-
device = self.cleaned_data.get(f"side_{side}_device")
|
|
3660
|
-
content_type = self.cleaned_data.get(f"side_{side}_type")
|
|
3661
|
-
name = self.cleaned_data.get(f"side_{side}_name")
|
|
3662
|
-
if not device or not content_type or not name:
|
|
3663
|
-
return None
|
|
3664
|
-
|
|
3665
|
-
model = content_type.model_class()
|
|
3666
|
-
try:
|
|
3667
|
-
termination_object = model.objects.get(device=device, name=name)
|
|
3668
|
-
if termination_object.cable is not None:
|
|
3669
|
-
raise forms.ValidationError(f"Side {side.upper()}: {device} {termination_object} is already connected")
|
|
3670
|
-
except ObjectDoesNotExist:
|
|
3671
|
-
raise forms.ValidationError(f"{side.upper()} side termination not found: {device} {name}")
|
|
3672
|
-
|
|
3673
|
-
setattr(self.instance, f"termination_{side}", termination_object)
|
|
3674
|
-
return termination_object
|
|
3675
|
-
|
|
3676
|
-
def clean_side_a_name(self):
|
|
3677
|
-
return self._clean_side("a")
|
|
3678
|
-
|
|
3679
|
-
def clean_side_b_name(self):
|
|
3680
|
-
return self._clean_side("b")
|
|
3681
|
-
|
|
3682
|
-
def clean_length_unit(self):
|
|
3683
|
-
# Avoid trying to save as NULL
|
|
3684
|
-
length_unit = self.cleaned_data.get("length_unit", None)
|
|
3685
|
-
return length_unit if length_unit is not None else ""
|
|
3686
|
-
|
|
3687
|
-
def add_error(self, field, error):
|
|
3688
|
-
# Edge Case: some fields in error are not properties in this instance
|
|
3689
|
-
# e.g: termination_a_id not an property in CableCSVForm, This would raise a ValueError Exception
|
|
3690
|
-
# Solution: convert those fields to its equivalent in CableCSVForm
|
|
3691
|
-
# e.g: termination_a_id > side_a_name
|
|
3692
|
-
|
|
3693
|
-
final_error = error
|
|
3694
|
-
if hasattr(error, "error_dict"):
|
|
3695
|
-
error_dict = error.error_dict
|
|
3696
|
-
termination_keys = [key for key in error_dict.keys() if key.startswith("termination")]
|
|
3697
|
-
for error_field in termination_keys:
|
|
3698
|
-
side_value = error_field.split("_")[1]
|
|
3699
|
-
error_msg = error_dict.pop(error_field)
|
|
3700
|
-
error_dict[f"side_{side_value}_name"] = error_msg
|
|
3701
|
-
|
|
3702
|
-
final_error = ValidationError(error_dict)
|
|
3703
|
-
super().add_error(field, final_error)
|
|
3704
|
-
|
|
3705
|
-
|
|
3706
3060
|
class CableBulkEditForm(TagsBulkEditFormMixin, StatusModelBulkEditFormMixin, NautobotBulkEditForm):
|
|
3707
3061
|
pk = forms.ModelMultipleChoiceField(queryset=Cable.objects.all(), widget=forms.MultipleHiddenInput)
|
|
3708
3062
|
type = forms.ChoiceField(
|
|
@@ -3744,7 +3098,7 @@ class CableFilterForm(BootstrapMixin, StatusModelFilterFormMixin, forms.Form):
|
|
|
3744
3098
|
model = Cable
|
|
3745
3099
|
q = forms.CharField(required=False, label="Search")
|
|
3746
3100
|
location = DynamicModelMultipleChoiceField(queryset=Location.objects.all(), to_field_name="slug", required=False)
|
|
3747
|
-
tenant = DynamicModelMultipleChoiceField(queryset=Tenant.objects.all(), to_field_name="
|
|
3101
|
+
tenant = DynamicModelMultipleChoiceField(queryset=Tenant.objects.all(), to_field_name="name", required=False)
|
|
3748
3102
|
rack = DynamicModelMultipleChoiceField(
|
|
3749
3103
|
queryset=Rack.objects.all(),
|
|
3750
3104
|
required=False,
|
|
@@ -3782,6 +3136,7 @@ class ConsoleConnectionFilterForm(BootstrapMixin, forms.Form):
|
|
|
3782
3136
|
queryset=Device.objects.all(),
|
|
3783
3137
|
required=False,
|
|
3784
3138
|
label="Device",
|
|
3139
|
+
to_field_name="name",
|
|
3785
3140
|
query_params={"location": "$location"},
|
|
3786
3141
|
)
|
|
3787
3142
|
|
|
@@ -3792,6 +3147,7 @@ class PowerConnectionFilterForm(BootstrapMixin, forms.Form):
|
|
|
3792
3147
|
queryset=Device.objects.all(),
|
|
3793
3148
|
required=False,
|
|
3794
3149
|
label="Device",
|
|
3150
|
+
to_field_name="name",
|
|
3795
3151
|
query_params={"location": "$location"},
|
|
3796
3152
|
)
|
|
3797
3153
|
|
|
@@ -3802,6 +3158,7 @@ class InterfaceConnectionFilterForm(BootstrapMixin, forms.Form):
|
|
|
3802
3158
|
queryset=Device.objects.all(),
|
|
3803
3159
|
required=False,
|
|
3804
3160
|
label="Device",
|
|
3161
|
+
to_field_name="name",
|
|
3805
3162
|
query_params={"location": "$location"},
|
|
3806
3163
|
)
|
|
3807
3164
|
|
|
@@ -3969,32 +3326,19 @@ class VirtualChassisBulkEditForm(TagsBulkEditFormMixin, NautobotBulkEditForm):
|
|
|
3969
3326
|
nullable_fields = ["domain"]
|
|
3970
3327
|
|
|
3971
3328
|
|
|
3972
|
-
class VirtualChassisCSVForm(CustomFieldModelCSVForm):
|
|
3973
|
-
master = CSVModelChoiceField(
|
|
3974
|
-
queryset=Device.objects.all(),
|
|
3975
|
-
to_field_name="name",
|
|
3976
|
-
required=False,
|
|
3977
|
-
help_text="Master device",
|
|
3978
|
-
)
|
|
3979
|
-
|
|
3980
|
-
class Meta:
|
|
3981
|
-
model = VirtualChassis
|
|
3982
|
-
fields = VirtualChassis.csv_headers
|
|
3983
|
-
|
|
3984
|
-
|
|
3985
3329
|
class VirtualChassisFilterForm(NautobotFilterForm):
|
|
3986
3330
|
model = VirtualChassis
|
|
3987
3331
|
q = forms.CharField(required=False, label="Search")
|
|
3988
3332
|
location = DynamicModelMultipleChoiceField(queryset=Location.objects.all(), to_field_name="slug", required=False)
|
|
3989
3333
|
tenant_group = DynamicModelMultipleChoiceField(
|
|
3990
3334
|
queryset=TenantGroup.objects.all(),
|
|
3991
|
-
to_field_name="
|
|
3335
|
+
to_field_name="name",
|
|
3992
3336
|
required=False,
|
|
3993
3337
|
null_option="None",
|
|
3994
3338
|
)
|
|
3995
3339
|
tenant = DynamicModelMultipleChoiceField(
|
|
3996
3340
|
queryset=Tenant.objects.all(),
|
|
3997
|
-
to_field_name="
|
|
3341
|
+
to_field_name="name",
|
|
3998
3342
|
required=False,
|
|
3999
3343
|
null_option="None",
|
|
4000
3344
|
query_params={"tenant_group": "$tenant_group"},
|
|
@@ -4024,23 +3368,6 @@ class PowerPanelForm(LocatableModelFormMixin, NautobotModelForm):
|
|
|
4024
3368
|
]
|
|
4025
3369
|
|
|
4026
3370
|
|
|
4027
|
-
class PowerPanelCSVForm(LocatableModelCSVFormMixin, CustomFieldModelCSVForm):
|
|
4028
|
-
rack_group = CSVModelChoiceField(queryset=RackGroup.objects.all(), required=False, to_field_name="name")
|
|
4029
|
-
|
|
4030
|
-
class Meta:
|
|
4031
|
-
model = PowerPanel
|
|
4032
|
-
fields = PowerPanel.csv_headers
|
|
4033
|
-
|
|
4034
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
4035
|
-
super().__init__(data, *args, **kwargs)
|
|
4036
|
-
|
|
4037
|
-
if data:
|
|
4038
|
-
|
|
4039
|
-
# Limit rack_group queryset by assigned location
|
|
4040
|
-
params = {f"location__{self.fields['location'].to_field_name}": data.get("location")}
|
|
4041
|
-
self.fields["rack_group"].queryset = self.fields["rack_group"].queryset.filter(**params)
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
3371
|
class PowerPanelBulkEditForm(
|
|
4045
3372
|
TagsBulkEditFormMixin,
|
|
4046
3373
|
LocatableModelBulkEditFormMixin,
|
|
@@ -4114,54 +3441,6 @@ class PowerFeedForm(NautobotModelForm):
|
|
|
4114
3441
|
}
|
|
4115
3442
|
|
|
4116
3443
|
|
|
4117
|
-
class PowerFeedCSVForm(StatusModelCSVFormMixin, CustomFieldModelCSVForm):
|
|
4118
|
-
location = CSVModelChoiceField(queryset=Location.objects.all(), to_field_name="name", help_text="Assigned location")
|
|
4119
|
-
power_panel = CSVModelChoiceField(
|
|
4120
|
-
queryset=PowerPanel.objects.all(),
|
|
4121
|
-
to_field_name="name",
|
|
4122
|
-
help_text="Upstream power panel",
|
|
4123
|
-
)
|
|
4124
|
-
rack_group = CSVModelChoiceField(
|
|
4125
|
-
queryset=RackGroup.objects.all(),
|
|
4126
|
-
to_field_name="name",
|
|
4127
|
-
required=False,
|
|
4128
|
-
help_text="Rack's group (if any)",
|
|
4129
|
-
)
|
|
4130
|
-
rack = CSVModelChoiceField(
|
|
4131
|
-
queryset=Rack.objects.all(),
|
|
4132
|
-
to_field_name="name",
|
|
4133
|
-
required=False,
|
|
4134
|
-
help_text="Rack",
|
|
4135
|
-
)
|
|
4136
|
-
type = CSVChoiceField(choices=PowerFeedTypeChoices, required=False, help_text="Primary or redundant")
|
|
4137
|
-
supply = CSVChoiceField(choices=PowerFeedSupplyChoices, required=False, help_text="Supply type (AC/DC)")
|
|
4138
|
-
phase = CSVChoiceField(choices=PowerFeedPhaseChoices, required=False, help_text="Single or three-phase")
|
|
4139
|
-
|
|
4140
|
-
class Meta:
|
|
4141
|
-
model = PowerFeed
|
|
4142
|
-
fields = PowerFeed.csv_headers
|
|
4143
|
-
|
|
4144
|
-
def __init__(self, data=None, *args, **kwargs):
|
|
4145
|
-
super().__init__(data, *args, **kwargs)
|
|
4146
|
-
|
|
4147
|
-
if data:
|
|
4148
|
-
|
|
4149
|
-
# Limit power_panel queryset by location
|
|
4150
|
-
params = {f"location__{self.fields['location'].to_field_name}": data.get("location")}
|
|
4151
|
-
self.fields["power_panel"].queryset = self.fields["power_panel"].queryset.filter(**params)
|
|
4152
|
-
|
|
4153
|
-
# Limit rack_group queryset by location
|
|
4154
|
-
params = {f"location__{self.fields['location'].to_field_name}": data.get("location")}
|
|
4155
|
-
self.fields["rack_group"].queryset = self.fields["rack_group"].queryset.filter(**params)
|
|
4156
|
-
|
|
4157
|
-
# Limit rack queryset by location and group
|
|
4158
|
-
params = {
|
|
4159
|
-
f"location__{self.fields['location'].to_field_name}": data.get("location"),
|
|
4160
|
-
f"rack_group__{self.fields['rack_group'].to_field_name}": data.get("rack_group"),
|
|
4161
|
-
}
|
|
4162
|
-
self.fields["rack"].queryset = self.fields["rack"].queryset.filter(**params)
|
|
4163
|
-
|
|
4164
|
-
|
|
4165
3444
|
class PowerFeedBulkEditForm(TagsBulkEditFormMixin, StatusModelBulkEditFormMixin, NautobotBulkEditForm):
|
|
4166
3445
|
pk = forms.ModelMultipleChoiceField(queryset=PowerFeed.objects.all(), widget=forms.MultipleHiddenInput)
|
|
4167
3446
|
power_panel = DynamicModelChoiceField(queryset=PowerPanel.objects.all(), required=False)
|
|
@@ -4237,7 +3516,6 @@ class PowerFeedFilterForm(NautobotFilterForm, StatusModelFilterFormMixin):
|
|
|
4237
3516
|
class DeviceRedundancyGroupForm(NautobotModelForm):
|
|
4238
3517
|
secrets_group = DynamicModelChoiceField(queryset=SecretsGroup.objects.all(), required=False)
|
|
4239
3518
|
comments = CommentField()
|
|
4240
|
-
slug = SlugField()
|
|
4241
3519
|
|
|
4242
3520
|
class Meta:
|
|
4243
3521
|
model = DeviceRedundancyGroup
|
|
@@ -4255,7 +3533,7 @@ class DeviceRedundancyGroupFilterForm(NautobotFilterForm, StatusModelFilterFormM
|
|
|
4255
3533
|
widget=StaticSelect2(),
|
|
4256
3534
|
)
|
|
4257
3535
|
secrets_group = DynamicModelMultipleChoiceField(
|
|
4258
|
-
queryset=SecretsGroup.objects.all(), to_field_name="
|
|
3536
|
+
queryset=SecretsGroup.objects.all(), to_field_name="name", required=False
|
|
4259
3537
|
)
|
|
4260
3538
|
|
|
4261
3539
|
tag = TagFilterField(model)
|
|
@@ -4279,20 +3557,3 @@ class DeviceRedundancyGroupBulkEditForm(
|
|
|
4279
3557
|
"failover_strategy",
|
|
4280
3558
|
"secrets_group",
|
|
4281
3559
|
]
|
|
4282
|
-
|
|
4283
|
-
|
|
4284
|
-
class DeviceRedundancyGroupCSVForm(StatusModelCSVFormMixin, CustomFieldModelCSVForm):
|
|
4285
|
-
failover_strategy = CSVChoiceField(
|
|
4286
|
-
choices=DeviceRedundancyGroupFailoverStrategyChoices, required=False, help_text="Failover Strategy"
|
|
4287
|
-
)
|
|
4288
|
-
|
|
4289
|
-
secrets_group = CSVModelChoiceField(
|
|
4290
|
-
queryset=SecretsGroup.objects.all(),
|
|
4291
|
-
required=False,
|
|
4292
|
-
to_field_name="name",
|
|
4293
|
-
help_text="Secrets group",
|
|
4294
|
-
)
|
|
4295
|
-
|
|
4296
|
-
class Meta:
|
|
4297
|
-
model = DeviceRedundancyGroup
|
|
4298
|
-
fields = DeviceRedundancyGroup.csv_headers
|