nautobot 3.0.0a2__py3-none-any.whl → 3.0.0a3__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/apps/choices.py +0 -2
- nautobot/apps/filters.py +7 -9
- nautobot/apps/models.py +2 -2
- nautobot/apps/ui.py +9 -1
- nautobot/circuits/filters.py +3 -2
- nautobot/circuits/navigation.py +3 -2
- nautobot/circuits/templates/circuits/circuit.html +1 -1
- nautobot/circuits/templates/circuits/circuit_create.html +3 -3
- nautobot/circuits/templates/circuits/circuittermination.html +1 -1
- nautobot/circuits/templates/circuits/circuittermination_create.html +9 -24
- nautobot/circuits/templates/circuits/circuittype.html +1 -1
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +6 -6
- nautobot/circuits/templates/circuits/inc/speed_widget.html +12 -12
- nautobot/circuits/templates/circuits/providernetwork.html +1 -1
- nautobot/circuits/tests/integration/test_circuit.py +10 -13
- nautobot/cloud/filters.py +1 -1
- nautobot/cloud/navigation.py +3 -2
- nautobot/core/api/schema.py +1 -1
- nautobot/core/api/serializers.py +6 -1
- nautobot/core/api/urls.py +1 -0
- nautobot/core/api/views.py +8 -0
- nautobot/core/apps/__init__.py +11 -10
- nautobot/core/celery/__init__.py +3 -5
- nautobot/core/checks.py +46 -0
- nautobot/core/cli/bootstrap_v3_to_v5.py +70 -1
- nautobot/core/cli/migrate_deprecated_templates.py +200 -0
- nautobot/core/constants.py +3 -0
- nautobot/core/context_processors.py +9 -1
- nautobot/core/forms/forms.py +1 -1
- nautobot/core/jobs/__init__.py +6 -3
- nautobot/core/jobs/groups.py +31 -1
- nautobot/core/management/commands/generate_test_data.py +28 -9
- nautobot/core/models/generics.py +9 -1
- nautobot/core/models/tree_queries.py +10 -5
- nautobot/core/settings.py +18 -12
- nautobot/core/settings.yaml +13 -7
- nautobot/core/signals.py +12 -1
- nautobot/core/tables.py +13 -6
- nautobot/core/templates/40x.html +1 -1
- nautobot/core/templates/500.html +2 -2
- nautobot/core/templates/admin/config/config.html +12 -12
- nautobot/core/templates/admin/index.html +3 -3
- nautobot/core/templates/buttons/export.html +1 -1
- nautobot/core/templates/components/button/dropdown.html +5 -3
- nautobot/core/templates/components/panel/body_wrapper_generic_table.html +1 -1
- nautobot/core/templates/components/panel/panel.html +3 -3
- nautobot/core/templates/components/tab/content_wrapper.html +2 -3
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +1 -1
- nautobot/core/templates/echarts/echarts.html +1 -1
- nautobot/core/templates/generic/object_bulk_add_component.html +2 -1
- nautobot/core/templates/generic/object_bulk_create.html +4 -3
- nautobot/core/templates/generic/object_bulk_destroy.html +3 -3
- nautobot/core/templates/generic/object_bulk_remove.html +2 -2
- nautobot/core/templates/generic/object_bulk_update.html +5 -4
- nautobot/core/templates/generic/object_create.html +5 -4
- nautobot/core/templates/generic/object_import.html +2 -1
- nautobot/core/templates/generic/object_list.html +12 -4
- nautobot/core/templates/generic/object_notes.html +5 -3
- nautobot/core/templates/generic/object_retrieve.html +2 -3
- nautobot/core/templates/graphene/graphiql.html +7 -7
- nautobot/core/templates/home.html +1 -1
- nautobot/core/templates/import_success.html +2 -1
- nautobot/core/templates/inc/computed_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/created_updated.html +7 -3
- nautobot/core/templates/inc/custom_fields/panel_data.html +1 -1
- nautobot/core/templates/inc/form_static_field.html +6 -0
- nautobot/core/templates/inc/header.html +1 -1
- nautobot/core/templates/inc/image_attachments.html +2 -1
- nautobot/core/templates/inc/nav_menu.html +2 -1
- nautobot/core/templates/inc/search_panel.html +4 -4
- nautobot/core/templates/login.html +4 -2
- nautobot/core/templates/nautobot_config.py.j2 +6 -5
- nautobot/core/templates/redoc_ui.html +7 -0
- nautobot/core/templates/search.html +1 -1
- nautobot/core/templates/swagger_ui.html +17 -3
- nautobot/core/templates/system_jobs/import_objects.html +1 -2
- nautobot/core/templates/utilities/confirmation_form.html +2 -2
- nautobot/core/templates/utilities/obj_table.html +10 -2
- nautobot/core/templates/utilities/render_field.html +7 -7
- nautobot/core/templates/utilities/render_jinja2.html +2 -2
- nautobot/core/templates/utilities/templatetags/filter_form_drawer.html +4 -4
- nautobot/core/templates/utilities/theme_preview.html +16 -3
- nautobot/core/templates/widgets/selectwithdisabled_option.html +3 -1
- nautobot/core/templatetags/helpers.py +52 -6
- nautobot/core/testing/api.py +68 -9
- nautobot/core/testing/filters.py +0 -23
- nautobot/core/testing/integration.py +23 -10
- nautobot/core/testing/mixins.py +2 -0
- nautobot/core/testing/views.py +4 -0
- nautobot/core/tests/integration/test_app_home.py +34 -30
- nautobot/core/tests/integration/test_app_navbar.py +3 -0
- nautobot/core/tests/nautobot_config_without_example_apps.py +4 -0
- nautobot/core/tests/runner.py +9 -1
- nautobot/core/tests/test_api.py +5 -3
- nautobot/core/tests/test_breadcrumbs.py +6 -7
- nautobot/core/tests/test_checks.py +28 -0
- nautobot/core/tests/test_cli.py +40 -0
- nautobot/core/tests/test_config.py +2 -1
- nautobot/core/tests/test_forms.py +55 -13
- nautobot/core/tests/test_jobs.py +75 -1
- nautobot/core/tests/test_nautobot_server.py +2 -0
- nautobot/core/tests/test_navigations.py +76 -1
- nautobot/core/tests/test_patch_social_django.py +42 -0
- nautobot/core/tests/test_tables.py +3 -1
- nautobot/core/tests/test_templatetags_helpers.py +53 -13
- nautobot/core/tests/test_templatetags_ui_framework.py +4 -4
- nautobot/core/tests/test_tree_queries.py +14 -1
- nautobot/core/tests/test_ui.py +1 -1
- nautobot/core/tests/test_utils.py +31 -4
- nautobot/core/tests/test_views.py +159 -31
- nautobot/core/ui/breadcrumbs.py +2 -12
- nautobot/core/ui/choices.py +142 -10
- nautobot/core/ui/constants.py +76 -12
- nautobot/core/ui/object_detail.py +92 -12
- nautobot/core/urls.py +12 -1
- nautobot/core/utils/cache.py +2 -1
- nautobot/core/utils/filtering.py +17 -17
- nautobot/core/utils/lookup.py +3 -8
- nautobot/core/utils/module_loading.py +21 -0
- nautobot/core/utils/patch_social_django.py +128 -0
- nautobot/core/views/__init__.py +38 -1
- nautobot/core/views/generic.py +3 -3
- nautobot/core/views/mixins.py +15 -3
- nautobot/core/views/renderers.py +2 -0
- nautobot/core/views/viewsets.py +2 -1
- nautobot/data_validation/apps.py +1 -5
- nautobot/data_validation/custom_validators.py +4 -4
- nautobot/data_validation/filters.py +1 -1
- nautobot/data_validation/forms.py +40 -0
- nautobot/data_validation/migrations/0001_initial.py +0 -7
- nautobot/data_validation/migrations/0002_data_migration_from_app.py +0 -12
- nautobot/data_validation/models.py +16 -7
- nautobot/data_validation/navigation.py +8 -1
- nautobot/data_validation/tables.py +12 -5
- nautobot/data_validation/templates/data_validation/datacompliance_tab.html +1 -0
- nautobot/data_validation/templates/data_validation/device_constraints.html +61 -0
- nautobot/data_validation/tests/__init__.py +2 -2
- nautobot/data_validation/tests/migrations/test_migrations.py +83 -3
- nautobot/data_validation/tests/test_data_compliance_rules.py +12 -7
- nautobot/data_validation/tests/test_filters.py +8 -6
- nautobot/data_validation/tests/test_models.py +15 -0
- nautobot/data_validation/tests/test_views.py +190 -32
- nautobot/data_validation/urls.py +2 -5
- nautobot/data_validation/views.py +73 -40
- nautobot/dcim/api/serializers.py +0 -13
- nautobot/dcim/apps.py +4 -0
- nautobot/dcim/choices.py +16 -0
- nautobot/dcim/custom_validators.py +84 -0
- nautobot/dcim/filter_mixins.py +353 -4
- nautobot/dcim/{filters/__init__.py → filters.py} +2 -35
- nautobot/dcim/forms.py +1 -1
- nautobot/dcim/migrations/0078_remove_device_location_tenant_name_uniqueness.py +16 -0
- nautobot/dcim/migrations/0079_device_name_data_migration.py +59 -0
- nautobot/dcim/models/device_components.py +81 -68
- nautobot/dcim/models/devices.py +13 -16
- nautobot/dcim/navigation.py +7 -6
- nautobot/dcim/tables/devices.py +3 -0
- nautobot/dcim/tables/template_code.py +14 -14
- nautobot/dcim/templates/dcim/cable.html +2 -61
- nautobot/dcim/templates/dcim/cable_connect.html +28 -112
- nautobot/dcim/templates/dcim/cable_edit.html +2 -5
- nautobot/dcim/templates/dcim/cable_retrieve.html +61 -0
- nautobot/dcim/templates/dcim/cable_trace.html +1 -3
- nautobot/dcim/templates/dcim/cable_update.html +5 -0
- nautobot/dcim/templates/dcim/consoleport.html +6 -5
- nautobot/dcim/templates/dcim/consoleserverport.html +6 -5
- nautobot/dcim/templates/dcim/device/config.html +2 -2
- nautobot/dcim/templates/dcim/device/consoleports.html +1 -1
- nautobot/dcim/templates/dcim/device/consoleserverports.html +1 -1
- nautobot/dcim/templates/dcim/device/devicebays.html +1 -1
- nautobot/dcim/templates/dcim/device/frontports.html +1 -1
- nautobot/dcim/templates/dcim/device/interfaces.html +1 -1
- nautobot/dcim/templates/dcim/device/inventory.html +1 -1
- nautobot/dcim/templates/dcim/device/lldp_neighbors.html +1 -1
- nautobot/dcim/templates/dcim/device/modulebays.html +1 -1
- nautobot/dcim/templates/dcim/device/poweroutlets.html +1 -1
- nautobot/dcim/templates/dcim/device/powerports.html +1 -1
- nautobot/dcim/templates/dcim/device/rearports.html +1 -1
- nautobot/dcim/templates/dcim/device/status.html +8 -8
- nautobot/dcim/templates/dcim/device/wireless.html +1 -1
- nautobot/dcim/templates/dcim/device.html +1 -1
- nautobot/dcim/templates/dcim/device_component_add.html +2 -2
- nautobot/dcim/templates/dcim/device_create.html +5 -3
- nautobot/dcim/templates/dcim/device_interface_delete.html +1 -1
- nautobot/dcim/templates/dcim/device_list.html +73 -10
- nautobot/dcim/templates/dcim/devicebay_populate.html +2 -2
- nautobot/dcim/templates/dcim/devicetype.html +1 -1
- nautobot/dcim/templates/dcim/devicetype_component_add.html +2 -2
- nautobot/dcim/templates/dcim/footer_convert_to_contact_or_team_record.html +14 -0
- nautobot/dcim/templates/dcim/frontport.html +9 -8
- nautobot/dcim/templates/dcim/inc/edit_form_softwareversion_js.html +2 -2
- nautobot/dcim/templates/dcim/interface.html +26 -6
- nautobot/dcim/templates/dcim/interface_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_add.html +3 -1
- nautobot/dcim/templates/dcim/inventoryitem_bulk_delete.html +1 -1
- nautobot/dcim/templates/dcim/inventoryitem_edit.html +3 -1
- nautobot/dcim/templates/dcim/location_retrieve.html +1 -242
- nautobot/dcim/templates/dcim/module/base.html +49 -9
- nautobot/dcim/templates/dcim/module_list.html +57 -8
- nautobot/dcim/templates/dcim/modulefamily_retrieve.html +1 -1
- nautobot/dcim/templates/dcim/moduletype_retrieve.html +49 -9
- nautobot/dcim/templates/dcim/platform_create.html +1 -1
- nautobot/dcim/templates/dcim/powerfeed.html +1 -1
- nautobot/dcim/templates/dcim/powerpanel.html +1 -1
- nautobot/dcim/templates/dcim/powerport.html +5 -4
- nautobot/dcim/templates/dcim/rack_elevation_list.html +16 -4
- nautobot/dcim/templates/dcim/rack_retrieve.html +33 -15
- nautobot/dcim/templates/dcim/rearport.html +7 -6
- nautobot/dcim/templates/dcim/virtualchassis.html +1 -1
- nautobot/dcim/templates/dcim/virtualchassis_add_member.html +16 -14
- nautobot/dcim/templates/dcim/virtualchassis_update.html +14 -6
- nautobot/dcim/tests/integration/test_controller.py +1 -0
- nautobot/dcim/tests/test_api.py +8 -0
- nautobot/dcim/tests/test_custom_validators.py +229 -0
- nautobot/dcim/tests/test_filters.py +12 -6
- nautobot/dcim/tests/test_models.py +63 -4
- nautobot/dcim/tests/test_views.py +63 -22
- nautobot/dcim/urls.py +64 -21
- nautobot/dcim/utils.py +3 -3
- nautobot/dcim/views.py +547 -273
- nautobot/extras/api/views.py +9 -1
- nautobot/extras/choices.py +2 -13
- nautobot/extras/{filters/mixins.py → filter_mixins.py} +1 -1
- nautobot/extras/{filters/customfields.py → filter_mixins_customfields.py} +42 -6
- nautobot/extras/{filters/__init__.py → filters.py} +14 -46
- nautobot/extras/forms/forms.py +5 -13
- nautobot/extras/forms/mixins.py +0 -41
- nautobot/extras/management/__init__.py +9 -0
- nautobot/extras/migrations/0127_approval_workflow_models.py +6 -6
- nautobot/extras/migrations/0129_jobresult_debug_log_count_jobresult_error_log_count_and_more.py +37 -0
- nautobot/extras/migrations/0130_jobresult_generate_log_entry_counts.py +42 -0
- nautobot/extras/models/__init__.py +1 -2
- nautobot/extras/models/approvals.py +22 -13
- nautobot/extras/models/contacts.py +2 -0
- nautobot/extras/models/groups.py +44 -5
- nautobot/extras/models/jobs.py +59 -1
- nautobot/extras/models/mixins.py +28 -0
- nautobot/extras/models/models.py +13 -0
- nautobot/extras/models/secrets.py +1 -0
- nautobot/extras/models/statuses.py +0 -15
- nautobot/extras/navigation.py +13 -9
- nautobot/extras/plugins/__init__.py +33 -55
- nautobot/extras/plugins/tables.py +3 -3
- nautobot/extras/plugins/urls.py +2 -21
- nautobot/extras/plugins/utils.py +1 -33
- nautobot/extras/plugins/views.py +0 -4
- nautobot/extras/signals.py +20 -19
- nautobot/extras/tables.py +52 -68
- nautobot/extras/templates/extras/approval_dashboard.html +7 -5
- nautobot/extras/templates/extras/approvalworkflowdefinition_update.html +4 -2
- nautobot/extras/templates/extras/approvalworkflowstage_retrieve.html +20 -12
- nautobot/extras/templates/extras/computedfield.html +1 -1
- nautobot/extras/templates/extras/configcontext.html +1 -1
- nautobot/extras/templates/extras/configcontextschema_validation.html +2 -2
- nautobot/extras/templates/extras/customfield.html +1 -1
- nautobot/extras/templates/extras/dynamicgroup_retrieve.html +11 -5
- nautobot/extras/templates/extras/dynamicgroup_update.html +1 -1
- nautobot/extras/templates/extras/gitrepository_result.html +0 -2
- nautobot/extras/templates/extras/graphqlquery_retrieve.html +1 -96
- nautobot/extras/templates/extras/inc/approval_buttons_column.html +20 -6
- nautobot/extras/templates/extras/inc/bulk_edit_overridable_field.html +8 -7
- nautobot/extras/templates/extras/inc/configcontext_format.html +10 -3
- nautobot/extras/templates/extras/inc/graphqlquery_execute.html +71 -0
- nautobot/extras/templates/extras/inc/job_tiles.html +15 -3
- nautobot/extras/templates/extras/inc/json_format.html +10 -3
- nautobot/extras/templates/extras/inc/overridable_field.html +13 -12
- nautobot/extras/templates/extras/job.html +29 -12
- nautobot/extras/templates/extras/job_bulk_edit.html +18 -0
- nautobot/extras/templates/extras/job_edit.html +52 -46
- nautobot/extras/templates/extras/job_list.html +29 -25
- nautobot/extras/templates/extras/marketplace.html +5 -9
- nautobot/extras/templates/extras/object_configcontext.html +1 -1
- nautobot/extras/templates/extras/object_dynamicgroups.html +2 -2
- nautobot/extras/templates/extras/objectchange_retrieve.html +19 -37
- nautobot/extras/templates/extras/plugin_detail.html +26 -21
- nautobot/extras/templates/extras/plugins_list.html +16 -26
- nautobot/extras/templates/extras/role_retrieve.html +64 -0
- nautobot/extras/templates/extras/scheduledjob.html +4 -2
- nautobot/extras/templates/extras/secretsgroup.html +1 -1
- nautobot/extras/templates/extras/tag.html +1 -1
- nautobot/extras/templatetags/custom_links.py +12 -12
- nautobot/extras/templatetags/job_buttons.py +14 -12
- nautobot/extras/test_jobs/invalid_import.py +9 -0
- nautobot/extras/test_jobs/log_counts_by_level.py +23 -0
- nautobot/extras/test_jobs/missing_import.py +11 -0
- nautobot/extras/tests/integration/test_configcontextschema.py +27 -26
- nautobot/extras/tests/integration/test_customfields.py +8 -7
- nautobot/extras/tests/integration/test_dynamicgroups.py +5 -1
- nautobot/extras/tests/integration/test_plugin_banner.py +3 -0
- nautobot/extras/tests/integration/test_plugins.py +18 -6
- nautobot/extras/tests/test_api.py +27 -18
- nautobot/extras/tests/test_approvals.py +38 -38
- nautobot/extras/tests/test_changelog.py +35 -3
- nautobot/extras/tests/test_customfields.py +22 -13
- nautobot/extras/tests/test_customfields_filters.py +479 -0
- nautobot/extras/tests/test_dynamicgroups.py +39 -1
- nautobot/extras/tests/test_filters.py +21 -19
- nautobot/extras/tests/test_forms.py +18 -21
- nautobot/extras/tests/test_jobs.py +25 -4
- nautobot/extras/tests/test_migrations.py +1 -0
- nautobot/extras/tests/test_models.py +13 -31
- nautobot/extras/tests/test_plugins.py +36 -10
- nautobot/extras/tests/test_views.py +31 -30
- nautobot/extras/views.py +81 -19
- nautobot/ipam/factory.py +7 -0
- nautobot/ipam/filter_mixins.py +38 -0
- nautobot/ipam/filters.py +27 -38
- nautobot/ipam/formfields.py +1 -1
- nautobot/ipam/forms.py +6 -3
- nautobot/ipam/migrations/0030_ipam__namespaces.py +13 -0
- nautobot/ipam/migrations/0031_ipam___data_migrations.py +4 -1
- nautobot/ipam/migrations/0054_namespace_tenant.py +25 -0
- nautobot/ipam/models.py +29 -2
- nautobot/ipam/navigation.py +3 -2
- nautobot/ipam/signals.py +71 -0
- nautobot/ipam/tables.py +13 -6
- nautobot/ipam/templates/ipam/inc/toggle_available.html +10 -10
- nautobot/ipam/templates/ipam/inc/vlangroup_header.html +1 -0
- nautobot/ipam/templates/ipam/ipaddress.html +14 -0
- nautobot/ipam/templates/ipam/ipaddress_merge.html +3 -3
- nautobot/ipam/templates/ipam/ipaddresstointerface_retrieve.html +1 -0
- nautobot/ipam/templates/ipam/namespace_update.html +15 -0
- nautobot/ipam/templates/ipam/prefix_delete.html +1 -1
- nautobot/ipam/templates/ipam/prefix_list.html +14 -13
- nautobot/ipam/templates/ipam/service.html +1 -1
- nautobot/ipam/templates/ipam/vlan.html +1 -1
- nautobot/ipam/templates/ipam/vlan_interfaces.html +1 -1
- nautobot/ipam/templates/ipam/vlan_vminterfaces.html +1 -1
- nautobot/ipam/tests/migration/test_migrations.py +89 -0
- nautobot/ipam/tests/test_api.py +13 -6
- nautobot/ipam/tests/test_filters.py +10 -0
- nautobot/ipam/tests/test_forms.py +1 -1
- nautobot/ipam/tests/test_models.py +43 -1
- nautobot/ipam/tests/test_tables.py +1 -2
- nautobot/ipam/tests/test_utils.py +1 -1
- nautobot/ipam/tests/test_views.py +13 -14
- nautobot/ipam/ui.py +0 -17
- nautobot/ipam/utils/migrations.py +16 -2
- nautobot/ipam/utils/testing.py +9 -3
- nautobot/ipam/views.py +46 -6
- nautobot/project-static/dist/css/nautobot.css +1 -1
- nautobot/project-static/dist/css/nautobot.css.map +1 -1
- nautobot/project-static/dist/js/nautobot.js +1 -1
- nautobot/project-static/dist/js/nautobot.js.map +1 -1
- nautobot/project-static/js/cabletrace.js +1 -1
- nautobot/project-static/js/interface_filtering.js +20 -16
- nautobot/project-static/nautobot-icons/battery-3.svg +3 -0
- nautobot/project-static/nautobot-icons/cloud.svg +1 -1
- nautobot/project-static/nautobot-icons/control-panel.svg +1 -1
- nautobot/project-static/nautobot-icons/device-lifecycle.svg +1 -1
- nautobot/project-static/nautobot-icons/elements.svg +1 -1
- nautobot/project-static/nautobot-icons/extensibility.svg +3 -0
- nautobot/project-static/nautobot-icons/hammer.svg +1 -1
- nautobot/project-static/nautobot-icons/organization.svg +3 -0
- nautobot/project-static/nautobot-icons/secrets.svg +1 -1
- nautobot/project-static/nautobot-icons/security.svg +3 -0
- nautobot/project-static/nautobot-icons/server.svg +1 -1
- nautobot/project-static/nautobot-icons/star-filled.svg +1 -1
- nautobot/project-static/nautobot-icons/star.svg +1 -1
- nautobot/tenancy/api/serializers.py +1 -0
- nautobot/tenancy/api/views.py +2 -1
- nautobot/tenancy/{filters/__init__.py → filters.py} +2 -10
- nautobot/tenancy/navigation.py +3 -1
- nautobot/tenancy/tests/test_filters.py +0 -2
- nautobot/tenancy/views.py +2 -1
- nautobot/ui/src/js/collapse.js +3 -3
- nautobot/ui/src/js/nautobot.js +16 -0
- nautobot/ui/src/scss/colors.scss +1 -1
- nautobot/ui/src/scss/nautobot.scss +61 -28
- nautobot/users/templates/users/profile.html +45 -12
- nautobot/users/templates/users/sessionkey_delete.html +1 -1
- nautobot/users/tests/test_api.py +4 -0
- nautobot/users/views.py +4 -2
- nautobot/virtualization/models.py +1 -68
- nautobot/virtualization/navigation.py +3 -2
- nautobot/virtualization/templates/virtualization/virtual_machine_vminterface_delete.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_list.html +2 -2
- nautobot/virtualization/templates/virtualization/virtualmachine_update.html +3 -1
- nautobot/virtualization/tests/test_api.py +3 -0
- nautobot/virtualization/tests/test_models.py +44 -4
- nautobot/vpn/__init__.py +0 -0
- nautobot/vpn/api/serializers.py +113 -0
- nautobot/vpn/api/urls.py +19 -0
- nautobot/vpn/api/views.py +70 -0
- nautobot/vpn/apps.py +8 -0
- nautobot/vpn/choices.py +171 -0
- nautobot/vpn/factory.py +209 -0
- nautobot/vpn/filters.py +233 -0
- nautobot/vpn/forms.py +486 -0
- nautobot/vpn/homepage.py +19 -0
- nautobot/vpn/migrations/0001_initial.py +541 -0
- nautobot/vpn/migrations/0002_populate_defaults.py +199 -0
- nautobot/vpn/migrations/__init__.py +0 -0
- nautobot/vpn/models.py +527 -0
- nautobot/vpn/navigation.py +98 -0
- nautobot/vpn/tables.py +380 -0
- nautobot/vpn/templates/vpn/vpnprofile.html +2 -0
- nautobot/vpn/templates/vpn/vpnprofile_create.html +150 -0
- nautobot/vpn/tests/__init__.py +0 -0
- nautobot/vpn/tests/test_api.py +341 -0
- nautobot/vpn/tests/test_filters.py +139 -0
- nautobot/vpn/tests/test_forms.py +294 -0
- nautobot/vpn/tests/test_models.py +97 -0
- nautobot/vpn/tests/test_views.py +281 -0
- nautobot/vpn/urls.py +16 -0
- nautobot/vpn/views.py +437 -0
- nautobot/wireless/navigation.py +3 -2
- nautobot/wireless/tests/integration/test_radio_profile.py +1 -5
- nautobot/wireless/tests/test_api.py +1 -1
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/METADATA +14 -14
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/RECORD +417 -366
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/entry_points.txt +1 -0
- nautobot/data_validation/template_content.py +0 -42
- nautobot/dcim/filters/mixins.py +0 -354
- nautobot/ipam/templates/ipam/inc/prefix_header_extra_content_table.html +0 -4
- /nautobot/tenancy/{filters/mixins.py → filter_mixins.py} +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/LICENSE.txt +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/NOTICE +0 -0
- {nautobot-3.0.0a2.dist-info → nautobot-3.0.0a3.dist-info}/WHEEL +0 -0
nautobot/dcim/filter_mixins.py
CHANGED
|
@@ -1,5 +1,354 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
from nautobot.dcim.filters.mixins import LocatableModelFilterSetMixin
|
|
1
|
+
from django.db.models import Q
|
|
2
|
+
import django_filters
|
|
4
3
|
|
|
5
|
-
|
|
4
|
+
from nautobot.core.filters import (
|
|
5
|
+
MultiValueCharFilter,
|
|
6
|
+
MultiValueMACAddressFilter,
|
|
7
|
+
MultiValueUUIDFilter,
|
|
8
|
+
NameSearchFilterSet,
|
|
9
|
+
NaturalKeyOrPKMultipleChoiceFilter,
|
|
10
|
+
RelatedMembershipBooleanFilter,
|
|
11
|
+
SearchFilter,
|
|
12
|
+
TreeNodeMultipleChoiceFilter,
|
|
13
|
+
)
|
|
14
|
+
from nautobot.core.utils.data import is_uuid
|
|
15
|
+
from nautobot.dcim.constants import MODULE_RECURSION_DEPTH_LIMIT
|
|
16
|
+
from nautobot.dcim.models import (
|
|
17
|
+
Cable,
|
|
18
|
+
ConsolePort,
|
|
19
|
+
ConsolePortTemplate,
|
|
20
|
+
ConsoleServerPort,
|
|
21
|
+
ConsoleServerPortTemplate,
|
|
22
|
+
Device,
|
|
23
|
+
DeviceType,
|
|
24
|
+
FrontPort,
|
|
25
|
+
FrontPortTemplate,
|
|
26
|
+
Interface,
|
|
27
|
+
InterfaceTemplate,
|
|
28
|
+
Location,
|
|
29
|
+
Manufacturer,
|
|
30
|
+
Module,
|
|
31
|
+
ModuleBay,
|
|
32
|
+
ModuleBayTemplate,
|
|
33
|
+
ModuleType,
|
|
34
|
+
PowerOutlet,
|
|
35
|
+
PowerOutletTemplate,
|
|
36
|
+
PowerPort,
|
|
37
|
+
PowerPortTemplate,
|
|
38
|
+
RearPort,
|
|
39
|
+
RearPortTemplate,
|
|
40
|
+
)
|
|
41
|
+
from nautobot.extras.filter_mixins import CustomFieldModelFilterSetMixin, RelationshipModelFilterSetMixin
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CableTerminationModelFilterSetMixin(django_filters.FilterSet):
|
|
45
|
+
has_cable = RelatedMembershipBooleanFilter(
|
|
46
|
+
field_name="cable",
|
|
47
|
+
label="Has cable",
|
|
48
|
+
)
|
|
49
|
+
cable = django_filters.ModelMultipleChoiceFilter(
|
|
50
|
+
queryset=Cable.objects.all(),
|
|
51
|
+
label="Cable",
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
class DeviceComponentTemplateModelFilterSetMixin(NameSearchFilterSet, CustomFieldModelFilterSetMixin):
|
|
56
|
+
device_type = NaturalKeyOrPKMultipleChoiceFilter(
|
|
57
|
+
queryset=DeviceType.objects.all(),
|
|
58
|
+
to_field_name="model",
|
|
59
|
+
label="Device type (model or ID)",
|
|
60
|
+
)
|
|
61
|
+
label = MultiValueCharFilter(label="Label")
|
|
62
|
+
description = MultiValueCharFilter(label="Description")
|
|
63
|
+
id = MultiValueUUIDFilter(label="ID")
|
|
64
|
+
name = MultiValueCharFilter(label="Name")
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
class ModularDeviceComponentTemplateModelFilterSetMixin(DeviceComponentTemplateModelFilterSetMixin):
|
|
68
|
+
has_device_type = RelatedMembershipBooleanFilter(
|
|
69
|
+
field_name="device_type",
|
|
70
|
+
label="Has device type",
|
|
71
|
+
)
|
|
72
|
+
module_type = NaturalKeyOrPKMultipleChoiceFilter(
|
|
73
|
+
queryset=ModuleType.objects.all(),
|
|
74
|
+
to_field_name="model",
|
|
75
|
+
label="Module type (model or ID)",
|
|
76
|
+
)
|
|
77
|
+
has_module_type = RelatedMembershipBooleanFilter(
|
|
78
|
+
field_name="module_type",
|
|
79
|
+
label="Has module type",
|
|
80
|
+
)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
class DeviceComponentModelFilterSetMixin(CustomFieldModelFilterSetMixin):
|
|
84
|
+
q = SearchFilter(
|
|
85
|
+
filter_predicates={
|
|
86
|
+
"name": "icontains",
|
|
87
|
+
"label": "icontains",
|
|
88
|
+
"description": "icontains",
|
|
89
|
+
},
|
|
90
|
+
)
|
|
91
|
+
location = NaturalKeyOrPKMultipleChoiceFilter(
|
|
92
|
+
field_name="device__location",
|
|
93
|
+
queryset=Location.objects.all(),
|
|
94
|
+
to_field_name="name",
|
|
95
|
+
label="Location (name or ID)",
|
|
96
|
+
)
|
|
97
|
+
device = NaturalKeyOrPKMultipleChoiceFilter(
|
|
98
|
+
queryset=Device.objects.all(),
|
|
99
|
+
to_field_name="name",
|
|
100
|
+
label="Device (name or ID)",
|
|
101
|
+
)
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class ModularDeviceComponentModelFilterSetMixin(DeviceComponentModelFilterSetMixin, RelationshipModelFilterSetMixin):
|
|
105
|
+
module = NaturalKeyOrPKMultipleChoiceFilter(
|
|
106
|
+
queryset=Module.objects.all(),
|
|
107
|
+
to_field_name="module_type__model",
|
|
108
|
+
label="Module (model or ID)",
|
|
109
|
+
)
|
|
110
|
+
device = NaturalKeyOrPKMultipleChoiceFilter(
|
|
111
|
+
queryset=Device.objects.all(),
|
|
112
|
+
to_field_name="name",
|
|
113
|
+
label="Device (name or ID)",
|
|
114
|
+
method="filter_device",
|
|
115
|
+
)
|
|
116
|
+
|
|
117
|
+
def _construct_device_filter_recursively(self, field_name, value):
|
|
118
|
+
recursion_depth = MODULE_RECURSION_DEPTH_LIMIT - 1
|
|
119
|
+
query = Q(**{f"device__{field_name}__in": value})
|
|
120
|
+
for level in range(recursion_depth):
|
|
121
|
+
recursive_query = "module__parent_module_bay__" + "parent_module__parent_module_bay__" * level
|
|
122
|
+
query = query | Q(**{f"{recursive_query}parent_device__{field_name}__in": value})
|
|
123
|
+
return query
|
|
124
|
+
|
|
125
|
+
def generate_query_filter_device(self, value):
|
|
126
|
+
if not hasattr(value, "__iter__") or isinstance(value, str):
|
|
127
|
+
value = [value]
|
|
128
|
+
|
|
129
|
+
device_ids = set(str(item) for item in value if is_uuid(item))
|
|
130
|
+
device_names = set(str(item) for item in value if not is_uuid(item))
|
|
131
|
+
query = self._construct_device_filter_recursively("name", device_names)
|
|
132
|
+
query |= self._construct_device_filter_recursively("id", device_ids)
|
|
133
|
+
return query
|
|
134
|
+
|
|
135
|
+
def filter_device(self, queryset, name, value):
|
|
136
|
+
if not value:
|
|
137
|
+
return queryset
|
|
138
|
+
params = self.generate_query_filter_device(value)
|
|
139
|
+
return queryset.filter(params)
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
class LocatableModelFilterSetMixin(django_filters.FilterSet):
|
|
143
|
+
"""Mixin to add `location` filter fields to a FilterSet.
|
|
144
|
+
|
|
145
|
+
The expectation is that the linked model has `location` FK fields.
|
|
146
|
+
"""
|
|
147
|
+
|
|
148
|
+
location = TreeNodeMultipleChoiceFilter(
|
|
149
|
+
prefers_id=True,
|
|
150
|
+
queryset=Location.objects.all(),
|
|
151
|
+
to_field_name="name",
|
|
152
|
+
label="Location (name or ID)",
|
|
153
|
+
)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
class PathEndpointModelFilterSetMixin(django_filters.FilterSet):
|
|
157
|
+
connected = django_filters.BooleanFilter(method="filter_connected", label="Connected status (bool)")
|
|
158
|
+
|
|
159
|
+
def filter_connected(self, queryset, name, value):
|
|
160
|
+
if value:
|
|
161
|
+
return queryset.filter(_path__is_active=True)
|
|
162
|
+
else:
|
|
163
|
+
return queryset.filter(Q(_path__isnull=True) | Q(_path__is_active=False))
|
|
164
|
+
|
|
165
|
+
|
|
166
|
+
class DeviceModuleCommonFiltersMixin(django_filters.FilterSet):
|
|
167
|
+
mac_address = MultiValueMACAddressFilter(
|
|
168
|
+
field_name="interfaces__mac_address",
|
|
169
|
+
label="MAC address",
|
|
170
|
+
)
|
|
171
|
+
has_console_ports = RelatedMembershipBooleanFilter(
|
|
172
|
+
field_name="console_ports",
|
|
173
|
+
label="Has console ports",
|
|
174
|
+
)
|
|
175
|
+
console_ports = NaturalKeyOrPKMultipleChoiceFilter(
|
|
176
|
+
queryset=ConsolePort.objects.all(),
|
|
177
|
+
to_field_name="name",
|
|
178
|
+
label="Console Ports (name or ID)",
|
|
179
|
+
)
|
|
180
|
+
has_console_server_ports = RelatedMembershipBooleanFilter(
|
|
181
|
+
field_name="console_server_ports",
|
|
182
|
+
label="Has console server ports",
|
|
183
|
+
)
|
|
184
|
+
console_server_ports = NaturalKeyOrPKMultipleChoiceFilter(
|
|
185
|
+
queryset=ConsoleServerPort.objects.all(),
|
|
186
|
+
to_field_name="name",
|
|
187
|
+
label="Console Server Ports (name or ID)",
|
|
188
|
+
)
|
|
189
|
+
has_power_ports = RelatedMembershipBooleanFilter(
|
|
190
|
+
field_name="power_ports",
|
|
191
|
+
label="Has power ports",
|
|
192
|
+
)
|
|
193
|
+
power_ports = NaturalKeyOrPKMultipleChoiceFilter(
|
|
194
|
+
queryset=PowerPort.objects.all(),
|
|
195
|
+
to_field_name="name",
|
|
196
|
+
label="Power Ports (name or ID)",
|
|
197
|
+
)
|
|
198
|
+
has_power_outlets = RelatedMembershipBooleanFilter(
|
|
199
|
+
field_name="power_outlets",
|
|
200
|
+
label="Has power outlets",
|
|
201
|
+
)
|
|
202
|
+
power_outlets = NaturalKeyOrPKMultipleChoiceFilter(
|
|
203
|
+
queryset=PowerOutlet.objects.all(),
|
|
204
|
+
to_field_name="name",
|
|
205
|
+
label="Power Outlets (name or ID)",
|
|
206
|
+
)
|
|
207
|
+
has_interfaces = RelatedMembershipBooleanFilter(
|
|
208
|
+
field_name="interfaces",
|
|
209
|
+
label="Has interfaces",
|
|
210
|
+
)
|
|
211
|
+
interfaces = NaturalKeyOrPKMultipleChoiceFilter(
|
|
212
|
+
queryset=Interface.objects.all(),
|
|
213
|
+
to_field_name="name",
|
|
214
|
+
label="Interfaces (name or ID)",
|
|
215
|
+
)
|
|
216
|
+
has_front_ports = RelatedMembershipBooleanFilter(
|
|
217
|
+
field_name="front_ports",
|
|
218
|
+
label="Has front ports",
|
|
219
|
+
)
|
|
220
|
+
front_ports = NaturalKeyOrPKMultipleChoiceFilter(
|
|
221
|
+
queryset=FrontPort.objects.all(),
|
|
222
|
+
to_field_name="name",
|
|
223
|
+
label="Front Ports (name or ID)",
|
|
224
|
+
)
|
|
225
|
+
has_rear_ports = RelatedMembershipBooleanFilter(
|
|
226
|
+
field_name="rear_ports",
|
|
227
|
+
label="Has rear ports",
|
|
228
|
+
)
|
|
229
|
+
rear_ports = NaturalKeyOrPKMultipleChoiceFilter(
|
|
230
|
+
queryset=RearPort.objects.all(),
|
|
231
|
+
to_field_name="name",
|
|
232
|
+
label="Rear Ports (name or ID)",
|
|
233
|
+
)
|
|
234
|
+
has_module_bays = RelatedMembershipBooleanFilter(
|
|
235
|
+
field_name="module_bays",
|
|
236
|
+
label="Has module bays",
|
|
237
|
+
)
|
|
238
|
+
has_empty_module_bays = django_filters.BooleanFilter(
|
|
239
|
+
method="filter_has_empty_module_bays",
|
|
240
|
+
label="Has empty module bays",
|
|
241
|
+
)
|
|
242
|
+
module_bays = django_filters.ModelMultipleChoiceFilter(
|
|
243
|
+
queryset=ModuleBay.objects.all(),
|
|
244
|
+
label="Module Bays",
|
|
245
|
+
)
|
|
246
|
+
has_modules = RelatedMembershipBooleanFilter(
|
|
247
|
+
field_name="module_bays__installed_module",
|
|
248
|
+
label="Has modules",
|
|
249
|
+
)
|
|
250
|
+
|
|
251
|
+
def generate_query_filter_has_empty_module_bays(self, value):
|
|
252
|
+
if value is True:
|
|
253
|
+
query = Q(module_bays__isnull=False, module_bays__installed_module__isnull=True)
|
|
254
|
+
else:
|
|
255
|
+
query = Q(module_bays__isnull=True) | ~Q(module_bays__installed_module__isnull=True)
|
|
256
|
+
return query
|
|
257
|
+
|
|
258
|
+
def filter_has_empty_module_bays(self, queryset, name, value):
|
|
259
|
+
if value is None:
|
|
260
|
+
return queryset.none
|
|
261
|
+
params = self.generate_query_filter_has_empty_module_bays(value)
|
|
262
|
+
return queryset.filter(params)
|
|
263
|
+
|
|
264
|
+
|
|
265
|
+
class DeviceTypeModuleTypeCommonFiltersMixin(django_filters.FilterSet):
|
|
266
|
+
manufacturer = NaturalKeyOrPKMultipleChoiceFilter(
|
|
267
|
+
queryset=Manufacturer.objects.all(),
|
|
268
|
+
to_field_name="name",
|
|
269
|
+
label="Manufacturer (name or ID)",
|
|
270
|
+
)
|
|
271
|
+
# TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
|
|
272
|
+
console_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
|
|
273
|
+
prefers_id=True,
|
|
274
|
+
to_field_name="name",
|
|
275
|
+
queryset=ConsolePortTemplate.objects.all(),
|
|
276
|
+
label="Console port templates (name or ID)",
|
|
277
|
+
)
|
|
278
|
+
has_console_port_templates = RelatedMembershipBooleanFilter(
|
|
279
|
+
field_name="console_port_templates",
|
|
280
|
+
label="Has console port templates",
|
|
281
|
+
)
|
|
282
|
+
# TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
|
|
283
|
+
console_server_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
|
|
284
|
+
prefers_id=True,
|
|
285
|
+
to_field_name="name",
|
|
286
|
+
queryset=ConsoleServerPortTemplate.objects.all(),
|
|
287
|
+
label="Console server port templates (name or ID)",
|
|
288
|
+
)
|
|
289
|
+
has_console_server_port_templates = RelatedMembershipBooleanFilter(
|
|
290
|
+
field_name="console_server_port_templates",
|
|
291
|
+
label="Has console server port templates",
|
|
292
|
+
)
|
|
293
|
+
# TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
|
|
294
|
+
power_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
|
|
295
|
+
prefers_id=True,
|
|
296
|
+
to_field_name="name",
|
|
297
|
+
queryset=PowerPortTemplate.objects.all(),
|
|
298
|
+
label="Power port templates (name or ID)",
|
|
299
|
+
)
|
|
300
|
+
has_power_port_templates = RelatedMembershipBooleanFilter(
|
|
301
|
+
field_name="power_port_templates",
|
|
302
|
+
label="Has power port templates",
|
|
303
|
+
)
|
|
304
|
+
# TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
|
|
305
|
+
power_outlet_templates = NaturalKeyOrPKMultipleChoiceFilter(
|
|
306
|
+
prefers_id=True,
|
|
307
|
+
to_field_name="name",
|
|
308
|
+
queryset=PowerOutletTemplate.objects.all(),
|
|
309
|
+
label="Power outlet templates (name or ID)",
|
|
310
|
+
)
|
|
311
|
+
has_power_outlet_templates = RelatedMembershipBooleanFilter(
|
|
312
|
+
field_name="power_outlet_templates",
|
|
313
|
+
label="Has power outlet templates",
|
|
314
|
+
)
|
|
315
|
+
# TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
|
|
316
|
+
interface_templates = NaturalKeyOrPKMultipleChoiceFilter(
|
|
317
|
+
prefers_id=True,
|
|
318
|
+
to_field_name="name",
|
|
319
|
+
queryset=InterfaceTemplate.objects.all(),
|
|
320
|
+
label="Interface templates (name or ID)",
|
|
321
|
+
)
|
|
322
|
+
has_interface_templates = RelatedMembershipBooleanFilter(
|
|
323
|
+
field_name="interface_templates",
|
|
324
|
+
label="Has interface templates",
|
|
325
|
+
)
|
|
326
|
+
# TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
|
|
327
|
+
front_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
|
|
328
|
+
prefers_id=True,
|
|
329
|
+
to_field_name="name",
|
|
330
|
+
queryset=FrontPortTemplate.objects.all(),
|
|
331
|
+
label="Front port templates (name or ID)",
|
|
332
|
+
)
|
|
333
|
+
has_front_port_templates = RelatedMembershipBooleanFilter(
|
|
334
|
+
field_name="front_port_templates",
|
|
335
|
+
label="Has front port templates",
|
|
336
|
+
)
|
|
337
|
+
# TODO: solve https://github.com/nautobot/nautobot/issues/2875 to use this filter correctly
|
|
338
|
+
rear_port_templates = NaturalKeyOrPKMultipleChoiceFilter(
|
|
339
|
+
prefers_id=True,
|
|
340
|
+
to_field_name="name",
|
|
341
|
+
queryset=RearPortTemplate.objects.all(),
|
|
342
|
+
label="Rear port templates (name or ID)",
|
|
343
|
+
)
|
|
344
|
+
has_rear_port_templates = RelatedMembershipBooleanFilter(
|
|
345
|
+
field_name="rear_port_templates",
|
|
346
|
+
label="Has rear port templates",
|
|
347
|
+
)
|
|
348
|
+
module_bay_templates = django_filters.ModelMultipleChoiceFilter(
|
|
349
|
+
queryset=ModuleBayTemplate.objects.all(),
|
|
350
|
+
)
|
|
351
|
+
has_module_bay_templates = RelatedMembershipBooleanFilter(
|
|
352
|
+
field_name="module_bay_templates",
|
|
353
|
+
label="Has module bay templates",
|
|
354
|
+
)
|
|
@@ -18,7 +18,6 @@ from nautobot.core.filters import (
|
|
|
18
18
|
TreeNodeMultipleChoiceFilter,
|
|
19
19
|
)
|
|
20
20
|
from nautobot.core.utils.data import is_uuid
|
|
21
|
-
from nautobot.core.utils.deprecation import class_deprecated_in_favor_of
|
|
22
21
|
from nautobot.dcim.choices import (
|
|
23
22
|
CableTypeChoices,
|
|
24
23
|
ConsolePortTypeChoices,
|
|
@@ -35,7 +34,7 @@ from nautobot.dcim.constants import (
|
|
|
35
34
|
VIRTUAL_IFACE_TYPES,
|
|
36
35
|
WIRELESS_IFACE_TYPES,
|
|
37
36
|
)
|
|
38
|
-
from nautobot.dcim.
|
|
37
|
+
from nautobot.dcim.filter_mixins import (
|
|
39
38
|
CableTerminationModelFilterSetMixin,
|
|
40
39
|
DeviceComponentModelFilterSetMixin,
|
|
41
40
|
DeviceComponentTemplateModelFilterSetMixin,
|
|
@@ -104,14 +103,13 @@ from nautobot.extras.filters import (
|
|
|
104
103
|
from nautobot.extras.models import ExternalIntegration, SecretsGroup
|
|
105
104
|
from nautobot.extras.utils import FeatureQuery
|
|
106
105
|
from nautobot.ipam.models import IPAddress, VLAN, VLANGroup
|
|
107
|
-
from nautobot.tenancy.
|
|
106
|
+
from nautobot.tenancy.filter_mixins import TenancyModelFilterSetMixin
|
|
108
107
|
from nautobot.tenancy.models import Tenant
|
|
109
108
|
from nautobot.virtualization.models import Cluster, VirtualMachine
|
|
110
109
|
from nautobot.wireless.models import RadioProfile, WirelessNetwork
|
|
111
110
|
|
|
112
111
|
__all__ = (
|
|
113
112
|
"CableFilterSet",
|
|
114
|
-
"CableTerminationFilterSet",
|
|
115
113
|
"CableTerminationModelFilterSetMixin",
|
|
116
114
|
"ConsoleConnectionFilterSet",
|
|
117
115
|
"ConsolePortFilterSet",
|
|
@@ -145,7 +143,6 @@ __all__ = (
|
|
|
145
143
|
"ModuleFamilyFilterSet",
|
|
146
144
|
"ModuleFilterSet",
|
|
147
145
|
"ModuleTypeFilterSet",
|
|
148
|
-
"PathEndpointFilterSet",
|
|
149
146
|
"PathEndpointModelFilterSetMixin",
|
|
150
147
|
"PlatformFilterSet",
|
|
151
148
|
"PowerConnectionFilterSet",
|
|
@@ -667,12 +664,6 @@ class DeviceTypeFilterSet(DeviceTypeModuleTypeCommonFiltersMixin, NautobotFilter
|
|
|
667
664
|
return queryset.exclude(device_bay_templates__isnull=value)
|
|
668
665
|
|
|
669
666
|
|
|
670
|
-
# TODO: remove in 2.2
|
|
671
|
-
@class_deprecated_in_favor_of(DeviceComponentTemplateModelFilterSetMixin)
|
|
672
|
-
class DeviceTypeComponentFilterSet(DeviceComponentTemplateModelFilterSetMixin):
|
|
673
|
-
pass
|
|
674
|
-
|
|
675
|
-
|
|
676
667
|
class ConsolePortTemplateFilterSet(ModularDeviceComponentTemplateModelFilterSetMixin, BaseFilterSet):
|
|
677
668
|
class Meta:
|
|
678
669
|
model = ConsolePortTemplate
|
|
@@ -978,24 +969,6 @@ class DeviceFilterSet(
|
|
|
978
969
|
return queryset.filter(params)
|
|
979
970
|
|
|
980
971
|
|
|
981
|
-
# TODO: remove in 2.2
|
|
982
|
-
@class_deprecated_in_favor_of(DeviceComponentModelFilterSetMixin)
|
|
983
|
-
class DeviceComponentFilterSet(DeviceComponentModelFilterSetMixin):
|
|
984
|
-
pass
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
# TODO: remove in 2.2
|
|
988
|
-
@class_deprecated_in_favor_of(CableTerminationModelFilterSetMixin)
|
|
989
|
-
class CableTerminationFilterSet(CableTerminationModelFilterSetMixin):
|
|
990
|
-
pass
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
# TODO: remove in 2.2
|
|
994
|
-
@class_deprecated_in_favor_of(PathEndpointModelFilterSetMixin)
|
|
995
|
-
class PathEndpointFilterSet(PathEndpointModelFilterSetMixin):
|
|
996
|
-
pass
|
|
997
|
-
|
|
998
|
-
|
|
999
972
|
class ConsolePortFilterSet(
|
|
1000
973
|
ModularDeviceComponentModelFilterSetMixin,
|
|
1001
974
|
CableTerminationModelFilterSetMixin,
|
|
@@ -1524,12 +1497,6 @@ class ConnectionFilterSetMixin:
|
|
|
1524
1497
|
return queryset.filter(**{f"{name}__in": value})
|
|
1525
1498
|
|
|
1526
1499
|
|
|
1527
|
-
# TODO: remove in 2.2
|
|
1528
|
-
@class_deprecated_in_favor_of(ConnectionFilterSetMixin)
|
|
1529
|
-
class ConnectionFilterSet(ConnectionFilterSetMixin):
|
|
1530
|
-
pass
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
1500
|
class ConsoleConnectionFilterSet(ConnectionFilterSetMixin, BaseFilterSet):
|
|
1534
1501
|
location = django_filters.CharFilter(
|
|
1535
1502
|
method="filter_location",
|
nautobot/dcim/forms.py
CHANGED
|
@@ -4577,7 +4577,7 @@ class BaseVCMemberFormSet(forms.BaseModelFormSet):
|
|
|
4577
4577
|
vc_position_list.append(vc_position)
|
|
4578
4578
|
|
|
4579
4579
|
|
|
4580
|
-
class DeviceVCMembershipForm(forms.ModelForm):
|
|
4580
|
+
class DeviceVCMembershipForm(BootstrapMixin, forms.ModelForm):
|
|
4581
4581
|
class Meta:
|
|
4582
4582
|
model = Device
|
|
4583
4583
|
fields = [
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# Generated by Django 4.2.24 on 2025-10-07 07:18
|
|
2
|
+
|
|
3
|
+
from django.db import migrations
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Migration(migrations.Migration):
|
|
7
|
+
dependencies = [
|
|
8
|
+
("dcim", "0077_remove_device_cluster"),
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
operations = [
|
|
12
|
+
migrations.AlterUniqueTogether(
|
|
13
|
+
name="device",
|
|
14
|
+
unique_together={("rack", "position", "face"), ("virtual_chassis", "vc_position")},
|
|
15
|
+
),
|
|
16
|
+
]
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Generated by Django 4.2.24 on 2025-10-07 07:18
|
|
2
|
+
|
|
3
|
+
from constance.models import Constance
|
|
4
|
+
from django.db import migrations
|
|
5
|
+
|
|
6
|
+
from nautobot.core.utils.config import get_settings_or_config
|
|
7
|
+
from nautobot.dcim.choices import DeviceUniquenessChoices
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def migrate_device_uniqueness_setting(apps, schema_editor):
|
|
11
|
+
"""
|
|
12
|
+
Migrate deprecated DEVICE_NAME_AS_NATURAL_KEY setting to DEVICE_UNIQUENESS and DEVICE_NAME_REQUIRED.
|
|
13
|
+
"""
|
|
14
|
+
try:
|
|
15
|
+
old_value = get_settings_or_config("DEVICE_NAME_AS_NATURAL_KEY")
|
|
16
|
+
except AttributeError:
|
|
17
|
+
old_value = False
|
|
18
|
+
new_value = DeviceUniquenessChoices.NAME if old_value else DeviceUniquenessChoices.LOCATION_TENANT_NAME
|
|
19
|
+
|
|
20
|
+
# Update or create DEVICE_UNIQUENESS in Constance
|
|
21
|
+
Constance.objects.update_or_create(
|
|
22
|
+
key="DEVICE_UNIQUENESS",
|
|
23
|
+
defaults={"value": new_value},
|
|
24
|
+
)
|
|
25
|
+
|
|
26
|
+
# cleanup: remove deprecated setting entry if it exists
|
|
27
|
+
Constance.objects.filter(key="DEVICE_NAME_AS_NATURAL_KEY").delete()
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
def reverse_migrate_device_uniqueness_setting(apps, schema_editor):
|
|
31
|
+
"""
|
|
32
|
+
Reverse migration set DEVICE_NAME_AS_NATURAL_KEY based on DEVICE_UNIQUENESS.
|
|
33
|
+
"""
|
|
34
|
+
try:
|
|
35
|
+
device_uniqueness = Constance.objects.get(key="DEVICE_UNIQUENESS").value
|
|
36
|
+
except Constance.DoesNotExist:
|
|
37
|
+
return
|
|
38
|
+
|
|
39
|
+
if device_uniqueness == DeviceUniquenessChoices.NAME:
|
|
40
|
+
Constance.objects.update_or_create(key="DEVICE_NAME_AS_NATURAL_KEY", defaults={"value": True})
|
|
41
|
+
else:
|
|
42
|
+
Constance.objects.update_or_create(key="DEVICE_NAME_AS_NATURAL_KEY", defaults={"value": False})
|
|
43
|
+
|
|
44
|
+
# cleanup: remove DEVICE_UNIQUENESS setting entry if it exists
|
|
45
|
+
Constance.objects.filter(key="DEVICE_UNIQUENESS").delete()
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
class Migration(migrations.Migration):
|
|
49
|
+
dependencies = [
|
|
50
|
+
("dcim", "0078_remove_device_location_tenant_name_uniqueness"),
|
|
51
|
+
("constance", "0003_drop_pickle"),
|
|
52
|
+
]
|
|
53
|
+
|
|
54
|
+
operations = [
|
|
55
|
+
migrations.RunPython(
|
|
56
|
+
migrate_device_uniqueness_setting,
|
|
57
|
+
reverse_migrate_device_uniqueness_setting,
|
|
58
|
+
),
|
|
59
|
+
]
|