nautobot 2.0.0a3__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/apps/api.py +6 -8
- nautobot/apps/forms.py +0 -2
- nautobot/apps/ui.py +0 -8
- nautobot/circuits/api/serializers.py +9 -117
- nautobot/circuits/api/urls.py +1 -1
- nautobot/circuits/api/views.py +0 -1
- nautobot/circuits/forms.py +0 -65
- nautobot/circuits/migrations/0014_related_name_changes.py +1 -1
- 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 -87
- nautobot/circuits/navigation.py +14 -69
- nautobot/circuits/signals.py +0 -2
- nautobot/circuits/tables.py +39 -1
- nautobot/circuits/tests/integration/test_relationships.py +9 -9
- nautobot/circuits/tests/test_api.py +4 -8
- nautobot/circuits/tests/test_filters.py +10 -4
- nautobot/circuits/tests/test_models.py +5 -1
- nautobot/circuits/tests/test_views.py +27 -5
- nautobot/circuits/views.py +18 -10
- nautobot/core/api/__init__.py +8 -2
- 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 +4 -0
- nautobot/core/api/parsers.py +154 -0
- nautobot/core/api/renderers.py +153 -2
- nautobot/core/api/schema.py +46 -2
- nautobot/core/api/serializers.py +377 -35
- 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 -72
- nautobot/core/apps/__init__.py +138 -220
- nautobot/core/celery/__init__.py +112 -41
- nautobot/core/celery/backends.py +19 -12
- 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 +0 -113
- nautobot/core/{cli.py → cli/__init__.py} +1 -1
- nautobot/core/cli/__main__.py +3 -0
- nautobot/core/constants.py +0 -24
- 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 +38 -65
- nautobot/core/forms/forms.py +4 -1
- nautobot/core/forms/utils.py +0 -52
- 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/generate_test_data.py +3 -2
- nautobot/core/management/commands/post_upgrade.py +24 -24
- nautobot/core/models/__init__.py +26 -1
- nautobot/core/models/fields.py +24 -5
- nautobot/core/models/generics.py +2 -42
- nautobot/core/models/managers.py +5 -0
- nautobot/core/models/name_color_content_types.py +0 -14
- nautobot/core/models/tree_queries.py +14 -4
- nautobot/core/models/utils.py +5 -6
- nautobot/core/models/validators.py +17 -8
- nautobot/core/releases.py +8 -10
- nautobot/core/settings.py +80 -42
- 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 +3 -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 -20
- 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 -28
- nautobot/core/testing/__init__.py +47 -44
- nautobot/core/testing/api.py +362 -47
- nautobot/core/testing/filters.py +1 -1
- nautobot/core/testing/migrations.py +2 -0
- nautobot/core/testing/mixins.py +22 -9
- nautobot/core/testing/schema.py +2 -1
- nautobot/core/testing/views.py +21 -46
- 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/test_api.py +290 -21
- nautobot/core/tests/test_checks.py +0 -7
- nautobot/core/tests/test_filters.py +107 -59
- nautobot/core/tests/test_forms.py +26 -92
- nautobot/core/tests/test_graphql.py +110 -77
- nautobot/core/tests/test_logging.py +4 -0
- nautobot/core/tests/test_managers.py +3 -1
- nautobot/core/tests/test_models.py +2 -0
- nautobot/core/tests/test_paginator.py +3 -1
- nautobot/core/tests/test_releases.py +12 -12
- nautobot/core/tests/test_templatetags_helpers.py +4 -4
- nautobot/core/tests/test_utils.py +32 -68
- nautobot/core/tests/test_views.py +12 -15
- nautobot/core/utils/data.py +17 -0
- nautobot/core/utils/deprecation.py +9 -6
- nautobot/core/utils/filtering.py +8 -3
- nautobot/core/utils/git.py +12 -4
- nautobot/core/utils/lookup.py +3 -1
- nautobot/core/utils/requests.py +1 -104
- nautobot/core/views/__init__.py +1 -0
- nautobot/core/views/generic.py +75 -110
- nautobot/core/views/mixins.py +52 -61
- nautobot/core/views/renderers.py +6 -7
- nautobot/core/views/utils.py +80 -0
- nautobot/dcim/api/serializers.py +160 -667
- nautobot/dcim/api/urls.py +1 -1
- nautobot/dcim/api/views.py +7 -44
- nautobot/dcim/choices.py +2 -0
- nautobot/dcim/filters/__init__.py +21 -0
- nautobot/dcim/form_mixins.py +1 -27
- nautobot/dcim/forms.py +19 -765
- nautobot/dcim/migrations/0024_alter_device_and_rack_role_add_new_role.py +2 -1
- nautobot/dcim/migrations/0025_device_and_rack_roles_data_migrations.py +19 -13
- nautobot/dcim/migrations/0027_remove_device_role_and_rack_role.py +1 -1
- nautobot/dcim/migrations/0028_rename_foreignkey_fields.py +1 -1
- nautobot/dcim/migrations/0030_migrate_region_and_site_data_to_locations.py +2 -2
- nautobot/dcim/migrations/0035_related_name_changes.py +1 -1
- nautobot/dcim/migrations/0036_remove_region_and_site.py +1 -1
- nautobot/dcim/migrations/0040_tagsfield.py +109 -0
- nautobot/dcim/migrations/{0040_ipam__namespaces.py → 0041_ipam__namespaces.py} +1 -1
- nautobot/dcim/migrations/0042_fixup_null_statuses.py +51 -0
- nautobot/dcim/migrations/0043_status_nonnullable.py +72 -0
- nautobot/dcim/models/cables.py +3 -33
- nautobot/dcim/models/device_component_templates.py +6 -0
- nautobot/dcim/models/device_components.py +12 -198
- nautobot/dcim/models/devices.py +30 -143
- nautobot/dcim/models/locations.py +3 -64
- nautobot/dcim/models/power.py +3 -50
- nautobot/dcim/models/racks.py +7 -84
- nautobot/dcim/navigation.py +141 -467
- nautobot/dcim/signals.py +0 -2
- nautobot/dcim/tables/locations.py +2 -2
- nautobot/dcim/tables/power.py +1 -2
- nautobot/dcim/templates/dcim/console_port_connection_list.html +7 -0
- nautobot/dcim/templates/dcim/devicetype.html +2 -2
- nautobot/dcim/templates/dcim/interface_connection_list.html +7 -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/test_api.py +166 -81
- nautobot/dcim/tests/test_cablepaths.py +41 -35
- nautobot/dcim/tests/test_filters.py +67 -23
- nautobot/dcim/tests/test_forms.py +5 -205
- nautobot/dcim/tests/test_graphql.py +7 -2
- nautobot/dcim/tests/test_migrations.py +6 -11
- nautobot/dcim/tests/test_models.py +182 -110
- nautobot/dcim/tests/test_natural_ordering.py +11 -8
- nautobot/dcim/tests/test_signals.py +6 -3
- nautobot/dcim/tests/test_views.py +197 -175
- nautobot/dcim/urls.py +11 -16
- nautobot/dcim/views.py +7 -134
- 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 +177 -195
- nautobot/docs/administration/nautobot-server.md +6 -21
- nautobot/docs/administration/replicating-nautobot.md +0 -10
- nautobot/docs/configuration/optional-settings.md +32 -41
- nautobot/docs/configuration/required-settings.md +11 -52
- nautobot/docs/development/application-registry.md +2 -13
- nautobot/docs/development/extending-models.md +15 -17
- nautobot/docs/development/generic-views.md +0 -2
- nautobot/docs/development/getting-started.md +55 -5
- nautobot/docs/development/navigation-menu.md +22 -93
- nautobot/docs/development/react-ui.md +105 -0
- nautobot/docs/development/role-internals.md +1 -3
- nautobot/docs/development/style-guide.md +6 -4
- nautobot/docs/index.md +3 -2
- nautobot/docs/installation/migrating-from-netbox.md +11 -42
- 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 +170 -747
- 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/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/virtualization/virtualmachine.md +3 -0
- nautobot/docs/plugins/development.md +83 -21
- nautobot/docs/release-notes/version-1.5.md +53 -0
- nautobot/docs/release-notes/version-2.0.md +180 -0
- nautobot/docs/requirements.txt +1 -0
- 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 -158
- nautobot/extras/api/serializers.py +165 -700
- nautobot/extras/api/urls.py +1 -1
- nautobot/extras/api/views.py +294 -280
- nautobot/extras/apps.py +4 -7
- nautobot/extras/choices.py +11 -9
- 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/filters/__init__.py +20 -19
- nautobot/extras/filters/mixins.py +4 -4
- nautobot/extras/forms/forms.py +63 -127
- nautobot/extras/forms/mixins.py +23 -51
- nautobot/extras/health_checks.py +0 -33
- nautobot/extras/jobs.py +387 -565
- nautobot/extras/management/commands/runjob.py +24 -62
- nautobot/extras/managers.py +30 -7
- 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 -1
- nautobot/extras/migrations/{0059_alter_joblogentry_scheduledjob_webhook_fields.py → 0060_alter_joblogentry_scheduledjob_webhook_fields.py} +1 -1
- nautobot/extras/migrations/{0060_role_and_alter_status.py → 0061_role_and_alter_status.py} +1 -7
- nautobot/extras/migrations/{0061_collect_roles_from_related_apps_roles.py → 0062_collect_roles_from_related_apps_roles.py} +33 -32
- nautobot/extras/migrations/{0062_alter_role_options.py → 0063_alter_role_options.py} +1 -1
- nautobot/extras/migrations/{0063_alter_configcontext_and_add_new_role.py → 0064_alter_configcontext_and_add_new_role.py} +1 -1
- nautobot/extras/migrations/0065_configcontext_data_migrations.py +44 -0
- nautobot/extras/migrations/{0065_rename_configcontext_role.py → 0066_rename_configcontext_role.py} +1 -1
- nautobot/extras/migrations/{0066_jobresult__add_celery_fields.py → 0067_jobresult__add_celery_fields.py} +36 -2
- nautobot/extras/migrations/{0067_created_datetime.py → 0068_created_datetime.py} +1 -1
- nautobot/extras/migrations/{0068_remove_site_and_region_attributes_from_config_context.py → 0069_remove_site_and_region_attributes_from_config_context.py} +1 -1
- 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 -1
- 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 -9
- nautobot/extras/migrations/{0073_remove_gitrepository_fields.py → 0074_remove_gitrepository_fields.py} +1 -1
- 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/{0077_remove_slug.py → 0078_remove_slug.py} +1 -5
- 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 -6
- nautobot/extras/models/jobs.py +189 -321
- nautobot/extras/models/mixins.py +0 -71
- nautobot/extras/models/models.py +0 -19
- nautobot/extras/models/relationships.py +19 -13
- nautobot/extras/models/roles.py +0 -34
- nautobot/extras/models/secrets.py +2 -26
- 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 -120
- nautobot/extras/plugins/utils.py +0 -3
- nautobot/extras/plugins/validators.py +5 -4
- nautobot/extras/plugins/views.py +16 -3
- nautobot/extras/querysets.py +1 -7
- nautobot/extras/registry.py +3 -0
- nautobot/extras/signals.py +26 -60
- nautobot/extras/tables.py +34 -40
- 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/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 +15 -17
- nautobot/extras/templates/extras/jobresult.html +24 -6
- nautobot/extras/templates/extras/scheduledjob.html +2 -2
- nautobot/extras/templates/extras/secret.html +28 -0
- nautobot/extras/templatetags/job_buttons.py +1 -0
- 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/test_computedfields.py +1 -1
- nautobot/extras/tests/integration/test_configcontextschema.py +5 -3
- nautobot/extras/tests/integration/test_customfields.py +4 -2
- nautobot/extras/tests/integration/test_dynamicgroups.py +1 -1
- nautobot/extras/tests/integration/test_jobs.py +25 -27
- nautobot/extras/tests/integration/test_notes.py +8 -4
- nautobot/extras/tests/integration/test_relationships.py +2 -2
- nautobot/extras/tests/test_api.py +649 -642
- nautobot/extras/tests/test_changelog.py +3 -3
- nautobot/extras/tests/test_context_managers.py +5 -3
- nautobot/extras/tests/test_customfields.py +92 -50
- nautobot/extras/tests/test_datasources.py +189 -112
- nautobot/extras/tests/test_dynamicgroups.py +7 -8
- nautobot/extras/tests/test_filters.py +137 -89
- nautobot/extras/tests/test_forms.py +73 -75
- nautobot/extras/tests/{test_scripts.py → test_job_variables.py} +43 -49
- nautobot/extras/tests/test_jobs.py +262 -263
- nautobot/extras/tests/test_migrations.py +4 -3
- nautobot/extras/tests/test_models.py +116 -161
- nautobot/extras/tests/test_plugins.py +38 -60
- nautobot/extras/tests/test_relationships.py +167 -120
- nautobot/extras/tests/test_tags.py +6 -11
- nautobot/extras/tests/test_utils.py +31 -1
- nautobot/extras/tests/test_views.py +201 -145
- nautobot/extras/tests/test_webhooks.py +6 -2
- nautobot/extras/urls.py +42 -42
- nautobot/extras/utils.py +137 -163
- nautobot/extras/views.py +78 -152
- nautobot/ipam/api/fields.py +17 -0
- nautobot/ipam/api/serializers.py +58 -164
- nautobot/ipam/api/urls.py +1 -1
- nautobot/ipam/api/views.py +3 -2
- nautobot/ipam/apps.py +1 -2
- nautobot/ipam/filters.py +1 -10
- nautobot/ipam/forms.py +4 -177
- nautobot/ipam/lookups.py +1 -0
- nautobot/ipam/management/commands/__init__.py +0 -0
- nautobot/ipam/management/commands/fix_prefix_broadcast.py +17 -0
- nautobot/ipam/migrations/0010_alter_ipam_role_add_new_role.py +1 -1
- nautobot/ipam/migrations/0011_migrate_ipam_role_data.py +32 -38
- nautobot/ipam/migrations/0020_related_name_changes.py +1 -1
- nautobot/ipam/migrations/0022_aggregate_to_prefix_data_migration.py +2 -2
- nautobot/ipam/migrations/0028_tagsfield.py +44 -0
- nautobot/ipam/migrations/0029_ip_address_to_interface_uniqueness_constraints.py +18 -0
- nautobot/ipam/migrations/{0028_ipam__namespaces.py → 0030_ipam__namespaces.py} +77 -28
- 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 +100 -236
- nautobot/ipam/navigation.py +36 -181
- nautobot/ipam/querysets.py +20 -25
- nautobot/ipam/signals.py +49 -6
- nautobot/ipam/tables.py +10 -3
- 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 +17 -4
- nautobot/ipam/templates/ipam/namespace_vrfs.html +11 -0
- nautobot/ipam/templates/ipam/prefix.html +1 -1
- nautobot/ipam/templates/ipam/vlangroup.html +0 -13
- nautobot/ipam/templates/ipam/vrf_edit.html +6 -0
- nautobot/ipam/tests/integration/test_prefixes.py +3 -26
- nautobot/ipam/tests/test_api.py +22 -19
- nautobot/ipam/tests/test_filters.py +59 -23
- nautobot/ipam/tests/test_migrations.py +6 -10
- nautobot/ipam/tests/test_models.py +323 -198
- nautobot/ipam/tests/test_ordering.py +2 -2
- nautobot/ipam/tests/test_querysets.py +44 -24
- nautobot/ipam/tests/test_views.py +73 -26
- nautobot/ipam/urls.py +16 -0
- nautobot/ipam/{utils.py → utils/__init__.py} +2 -2
- nautobot/ipam/utils/migrations.py +713 -0
- nautobot/ipam/views.py +137 -20
- nautobot/project-static/docs/404.html +1178 -10
- nautobot/project-static/docs/additional-features/caching.html +1224 -159
- nautobot/project-static/docs/additional-features/change-logging.html +1180 -12
- nautobot/project-static/docs/additional-features/config-contexts.html +1180 -12
- nautobot/project-static/docs/additional-features/graphql.html +1179 -11
- nautobot/project-static/docs/additional-features/healthcheck.html +1180 -12
- nautobot/project-static/docs/additional-features/job-scheduling-and-approvals.html +1184 -12
- nautobot/project-static/docs/additional-features/jobs.html +1514 -328
- nautobot/project-static/docs/additional-features/napalm.html +1180 -12
- nautobot/project-static/docs/additional-features/prometheus-metrics.html +1180 -12
- nautobot/project-static/docs/additional-features/template-filters.html +1180 -12
- nautobot/project-static/docs/administration/celery-queues.html +1178 -10
- nautobot/project-static/docs/administration/nautobot-server.html +1451 -304
- nautobot/project-static/docs/administration/nautobot-shell.html +1178 -10
- nautobot/project-static/docs/administration/permissions.html +1178 -10
- nautobot/project-static/docs/administration/replicating-nautobot.html +1262 -113
- nautobot/project-static/docs/apps/index.html +1178 -10
- nautobot/project-static/docs/apps/nautobot-apps.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +1580 -426
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +3481 -1838
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +1185 -11
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +1719 -551
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +2062 -930
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +1946 -659
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +1180 -12
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +1189 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +9283 -6218
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +2734 -2122
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +1178 -10
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +2337 -1300
- nautobot/project-static/docs/configuration/authentication/ldap.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/remote.html +1178 -10
- nautobot/project-static/docs/configuration/authentication/sso.html +1178 -10
- nautobot/project-static/docs/configuration/index.html +1178 -10
- nautobot/project-static/docs/configuration/optional-settings.html +1311 -160
- nautobot/project-static/docs/configuration/required-settings.html +1312 -211
- nautobot/project-static/docs/core-functionality/circuits.html +1178 -10
- nautobot/project-static/docs/core-functionality/device-types.html +1178 -10
- nautobot/project-static/docs/core-functionality/devices.html +1182 -10
- nautobot/project-static/docs/core-functionality/ipam.html +1182 -10
- nautobot/project-static/docs/core-functionality/power.html +1178 -10
- nautobot/project-static/docs/core-functionality/secrets.html +1178 -10
- nautobot/project-static/docs/core-functionality/services.html +1178 -10
- nautobot/project-static/docs/core-functionality/sites-and-racks.html +1178 -10
- nautobot/project-static/docs/core-functionality/tenancy.html +1178 -10
- nautobot/project-static/docs/core-functionality/virtualization.html +1182 -10
- nautobot/project-static/docs/core-functionality/vlans.html +1179 -11
- nautobot/project-static/docs/development/application-registry.html +1190 -42
- nautobot/project-static/docs/development/best-practices.html +1178 -10
- nautobot/project-static/docs/development/docker-compose-advanced-use-cases.html +1178 -10
- nautobot/project-static/docs/development/extending-models.html +1238 -83
- nautobot/project-static/docs/development/generic-views.html +1180 -14
- nautobot/project-static/docs/development/getting-started.html +1365 -90
- nautobot/project-static/docs/development/homepage.html +1178 -10
- nautobot/project-static/docs/development/index.html +1178 -10
- nautobot/project-static/docs/development/model-features.html +1178 -10
- nautobot/project-static/docs/development/natural-keys.html +1178 -10
- nautobot/project-static/docs/development/navigation-menu.html +1215 -125
- nautobot/project-static/docs/development/react-ui.html +4199 -0
- nautobot/project-static/docs/development/release-checklist.html +1178 -10
- nautobot/project-static/docs/development/role-internals.html +1179 -12
- nautobot/project-static/docs/development/style-guide.html +1188 -19
- nautobot/project-static/docs/development/templates.html +1178 -10
- nautobot/project-static/docs/development/testing.html +1178 -10
- nautobot/project-static/docs/development/user-preferences.html +1178 -10
- nautobot/project-static/docs/docker/index.html +1178 -10
- nautobot/project-static/docs/index.html +1183 -12
- nautobot/project-static/docs/installation/centos.html +1178 -10
- nautobot/project-static/docs/installation/external-authentication.html +1178 -10
- nautobot/project-static/docs/installation/http-server.html +1178 -10
- nautobot/project-static/docs/installation/index.html +1178 -10
- nautobot/project-static/docs/installation/migrating-from-netbox.html +1305 -189
- nautobot/project-static/docs/installation/migrating-from-postgresql.html +1178 -10
- nautobot/project-static/docs/installation/nautobot.html +1179 -11
- nautobot/project-static/docs/installation/region-and-site-data-migration-guide.html +1178 -10
- nautobot/project-static/docs/installation/selinux-troubleshooting.html +1178 -10
- nautobot/project-static/docs/installation/services.html +1178 -10
- 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 +1178 -10
- nautobot/project-static/docs/installation/upgrading-from-nautobot-v1.html +3823 -2152
- nautobot/project-static/docs/installation/upgrading.html +1178 -10
- nautobot/project-static/docs/models/circuits/circuit.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittermination.html +1293 -103
- nautobot/project-static/docs/models/circuits/circuittype.html +1293 -103
- nautobot/project-static/docs/models/circuits/provider.html +1293 -103
- nautobot/project-static/docs/models/circuits/providernetwork.html +1293 -103
- nautobot/project-static/docs/models/dcim/cable.html +1324 -103
- nautobot/project-static/docs/models/dcim/consoleport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverport.html +1293 -103
- nautobot/project-static/docs/models/dcim/consoleserverporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/device.html +1326 -132
- nautobot/project-static/docs/models/dcim/devicebay.html +1293 -103
- nautobot/project-static/docs/models/dcim/devicebaytemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/deviceredundancygroup.html +1379 -97
- nautobot/project-static/docs/models/dcim/devicetype.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontport.html +1293 -103
- nautobot/project-static/docs/models/dcim/frontporttemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/interface.html +1293 -103
- nautobot/project-static/docs/models/dcim/interfacetemplate.html +1293 -103
- nautobot/project-static/docs/models/dcim/inventoryitem.html +1293 -103
- nautobot/project-static/docs/models/dcim/location.html +1293 -103
- nautobot/project-static/docs/models/dcim/locationtype.html +1293 -103
- nautobot/project-static/docs/models/dcim/manufacturer.html +1292 -102
- nautobot/project-static/docs/models/dcim/platform.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerfeed.html +1270 -80
- nautobot/project-static/docs/models/dcim/poweroutlet.html +1272 -82
- nautobot/project-static/docs/models/dcim/poweroutlettemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerpanel.html +1270 -80
- nautobot/project-static/docs/models/dcim/powerport.html +1272 -82
- nautobot/project-static/docs/models/dcim/powerporttemplate.html +1272 -82
- nautobot/project-static/docs/models/dcim/rack.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackgroup.html +1272 -82
- nautobot/project-static/docs/models/dcim/rackreservation.html +1272 -82
- nautobot/project-static/docs/models/dcim/rearport.html +1286 -96
- nautobot/project-static/docs/models/dcim/rearporttemplate.html +1286 -96
- nautobot/project-static/docs/models/dcim/region.html +1178 -10
- nautobot/project-static/docs/models/dcim/site.html +1178 -10
- nautobot/project-static/docs/models/dcim/virtualchassis.html +1284 -94
- nautobot/project-static/docs/models/extras/computedfield.html +1184 -16
- nautobot/project-static/docs/models/extras/configcontext.html +1314 -86
- nautobot/project-static/docs/models/extras/configcontextschema.html +1276 -86
- nautobot/project-static/docs/models/extras/customfield.html +1180 -12
- nautobot/project-static/docs/models/extras/customlink.html +1180 -12
- nautobot/project-static/docs/models/extras/dynamicgroup.html +1180 -12
- nautobot/project-static/docs/models/extras/exporttemplate.html +1180 -12
- nautobot/project-static/docs/models/extras/gitrepository.html +1184 -12
- nautobot/project-static/docs/models/extras/graphqlquery.html +1321 -86
- nautobot/project-static/docs/models/extras/imageattachment.html +1276 -86
- nautobot/project-static/docs/models/extras/job.html +1277 -86
- nautobot/project-static/docs/models/extras/jobbutton.html +1201 -29
- nautobot/project-static/docs/models/extras/jobhook.html +1188 -16
- nautobot/project-static/docs/models/extras/joblogentry.html +1274 -84
- nautobot/project-static/docs/models/extras/jobresult.html +1364 -169
- nautobot/project-static/docs/models/extras/note.html +1180 -12
- nautobot/project-static/docs/models/extras/relationship.html +1182 -14
- nautobot/project-static/docs/models/extras/role.html +1320 -86
- nautobot/project-static/docs/models/extras/secret.html +1314 -86
- nautobot/project-static/docs/models/extras/secretsgroup.html +1276 -86
- nautobot/project-static/docs/models/extras/status.html +1188 -59
- nautobot/project-static/docs/models/extras/tag.html +1180 -12
- nautobot/project-static/docs/models/extras/webhook.html +1180 -12
- nautobot/project-static/docs/models/ipam/ipaddress.html +1327 -102
- nautobot/project-static/docs/models/ipam/prefix.html +1276 -86
- nautobot/project-static/docs/models/ipam/rir.html +1276 -86
- nautobot/project-static/docs/models/ipam/routetarget.html +1276 -86
- nautobot/project-static/docs/models/ipam/service.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlan.html +1276 -86
- nautobot/project-static/docs/models/ipam/vlangroup.html +1276 -86
- nautobot/project-static/docs/models/ipam/vrf.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenant.html +1276 -86
- nautobot/project-static/docs/models/tenancy/tenantgroup.html +1276 -86
- nautobot/project-static/docs/models/users/objectpermission.html +1314 -86
- nautobot/project-static/docs/models/users/token.html +1276 -86
- nautobot/project-static/docs/models/virtualization/cluster.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustergroup.html +1276 -86
- nautobot/project-static/docs/models/virtualization/clustertype.html +1276 -86
- nautobot/project-static/docs/models/virtualization/virtualmachine.html +1321 -127
- nautobot/project-static/docs/models/virtualization/vminterface.html +1276 -86
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/plugins/development.html +1726 -495
- nautobot/project-static/docs/plugins/index.html +1178 -10
- nautobot/project-static/docs/plugins/porting-from-netbox.html +1178 -10
- nautobot/project-static/docs/release-notes/index.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.0.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.1.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.2.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.3.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.4.html +1178 -10
- nautobot/project-static/docs/release-notes/version-1.5.html +1608 -225
- nautobot/project-static/docs/release-notes/version-2.0.html +1547 -47
- nautobot/project-static/docs/requirements.txt +1 -0
- nautobot/project-static/docs/rest-api/authentication.html +1179 -11
- nautobot/project-static/docs/rest-api/filtering.html +1178 -10
- nautobot/project-static/docs/rest-api/overview.html +1841 -446
- 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 +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/creating-devices.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/index.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/interfaces.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/ipam.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/platforms.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/regions.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/search-bar.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/tenants.html +1178 -10
- nautobot/project-static/docs/user-guides/getting-started/vlans-and-vlan-groups.html +1178 -10
- nautobot/project-static/docs/user-guides/git-data-source.html +1178 -10
- nautobot/project-static/docs/user-guides/graphql.html +1178 -10
- nautobot/project-static/docs/user-guides/relationships.html +1178 -10
- nautobot/project-static/docs/user-guides/s3-django-storage.html +1178 -10
- nautobot/project-static/js/forms.js +16 -9
- nautobot/project-static/js/theme.js +5 -0
- nautobot/tenancy/api/serializers.py +4 -32
- nautobot/tenancy/api/urls.py +1 -1
- nautobot/tenancy/forms.py +0 -28
- nautobot/tenancy/migrations/0008_tagsfield.py +19 -0
- nautobot/tenancy/models.py +0 -25
- nautobot/tenancy/navigation.py +6 -39
- nautobot/tenancy/templates/tenancy/tenant.html +12 -12
- nautobot/tenancy/templates/tenancy/tenantgroup.html +1 -1
- nautobot/tenancy/tests/test_api.py +1 -3
- nautobot/tenancy/tests/test_filters.py +10 -5
- nautobot/tenancy/views.py +0 -2
- 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/tests/test_api.py +110 -25
- nautobot/virtualization/api/serializers.py +18 -130
- nautobot/virtualization/api/urls.py +1 -1
- nautobot/virtualization/api/views.py +1 -22
- nautobot/virtualization/forms.py +13 -99
- nautobot/virtualization/migrations/0012_alter_virtualmachine_role_add_new_role.py +1 -1
- nautobot/virtualization/migrations/0013_migrate_virtualmachine_role_data.py +18 -11
- nautobot/virtualization/migrations/0015_rename_foreignkey_fields.py +1 -1
- nautobot/virtualization/migrations/0018_related_name_changes.py +1 -1
- 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/{0021_ipam__namespaces.py → 0023_ipam__namespaces.py} +2 -2
- nautobot/virtualization/migrations/0024_fixup_null_statuses.py +25 -0
- nautobot/virtualization/migrations/0025_status_nonnullable.py +29 -0
- nautobot/virtualization/models.py +31 -123
- nautobot/virtualization/navigation.py +18 -99
- nautobot/virtualization/templates/virtualization/virtualmachine.html +2 -1
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +6 -0
- nautobot/virtualization/tests/test_api.py +25 -26
- nautobot/virtualization/tests/test_filters.py +41 -15
- nautobot/virtualization/tests/test_models.py +31 -7
- nautobot/virtualization/tests/test_views.py +42 -25
- nautobot/virtualization/views.py +7 -6
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/METADATA +3 -7
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/RECORD +744 -602
- {nautobot-2.0.0a3.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 -41
- nautobot/extras/migrations/0071_job__unique_name_data_migration.py +0 -46
- 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 -18
- 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 -159
- nautobot/ipam/migrations/0029_ipam__prefix__add_parent.py +0 -31
- nautobot/ipam/migrations/0030_ipam__prefix__data_migration.py +0 -13
- nautobot/ipam/migrations/0031_ipam__ipaddress__add_parent.py +0 -41
- nautobot/ipam/migrations/0032_ipam__ipaddress__data_migration.py +0 -11
- 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.0a3.dist-info → nautobot-2.0.0b1.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.0.0a3.dist-info → nautobot-2.0.0b1.dist-info}/entry_points.txt +0 -0
|
@@ -3,32 +3,33 @@ import logging
|
|
|
3
3
|
from django.conf import settings
|
|
4
4
|
from django.contrib.contenttypes.models import ContentType
|
|
5
5
|
from django.core.exceptions import ObjectDoesNotExist
|
|
6
|
-
from django.urls import NoReverseMatch
|
|
7
6
|
from drf_spectacular.utils import extend_schema_field
|
|
8
7
|
from rest_framework import serializers
|
|
9
|
-
from rest_framework.reverse import reverse
|
|
10
8
|
|
|
11
9
|
from nautobot.core.api import (
|
|
10
|
+
BaseModelSerializer,
|
|
12
11
|
ChoiceField,
|
|
13
12
|
ContentTypeField,
|
|
14
|
-
|
|
13
|
+
CustomFieldModelSerializerMixin,
|
|
14
|
+
NautobotModelSerializer,
|
|
15
|
+
NotesSerializerMixin,
|
|
16
|
+
RelationshipModelSerializerMixin,
|
|
15
17
|
ValidatedModelSerializer,
|
|
16
18
|
)
|
|
17
19
|
from nautobot.core.api.exceptions import SerializerNotFound
|
|
18
|
-
from nautobot.core.api.
|
|
19
|
-
from nautobot.core.api.
|
|
20
|
-
|
|
20
|
+
from nautobot.core.api.serializers import PolymorphicProxySerializer
|
|
21
|
+
from nautobot.core.api.utils import (
|
|
22
|
+
get_nested_serializer_depth,
|
|
23
|
+
get_serializers_for_models,
|
|
24
|
+
return_nested_serializer_data_based_on_depth,
|
|
25
|
+
)
|
|
21
26
|
from nautobot.core.models.utils import get_all_concrete_models
|
|
22
|
-
from nautobot.
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
NestedDeviceTypeSerializer,
|
|
27
|
-
NestedLocationSerializer,
|
|
28
|
-
NestedPlatformSerializer,
|
|
29
|
-
NestedRackSerializer,
|
|
27
|
+
from nautobot.dcim.api.serializers import (
|
|
28
|
+
DeviceSerializer,
|
|
29
|
+
LocationSerializer,
|
|
30
|
+
RackSerializer,
|
|
30
31
|
)
|
|
31
|
-
from nautobot.
|
|
32
|
+
from nautobot.extras import choices, models
|
|
32
33
|
from nautobot.extras.choices import (
|
|
33
34
|
CustomFieldFilterLogicChoices,
|
|
34
35
|
CustomFieldTypeChoices,
|
|
@@ -36,6 +37,9 @@ from nautobot.extras.choices import (
|
|
|
36
37
|
JobResultStatusChoices,
|
|
37
38
|
ObjectChangeActionChoices,
|
|
38
39
|
)
|
|
40
|
+
from nautobot.extras.api.mixins import (
|
|
41
|
+
TaggedModelSerializerMixin,
|
|
42
|
+
)
|
|
39
43
|
from nautobot.extras.datasources import get_datasource_content_choices
|
|
40
44
|
from nautobot.extras.models import (
|
|
41
45
|
ComputedField,
|
|
@@ -70,54 +74,8 @@ from nautobot.extras.models import (
|
|
|
70
74
|
)
|
|
71
75
|
from nautobot.extras.models.mixins import NotesMixin
|
|
72
76
|
from nautobot.extras.utils import ChangeLoggedModelsQuery, FeatureQuery, RoleModelsQuery, TaggableClassesQuery
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
NestedTenantGroupSerializer,
|
|
76
|
-
)
|
|
77
|
-
from nautobot.tenancy.models import Tenant, TenantGroup
|
|
78
|
-
from nautobot.users.api.nested_serializers import NestedUserSerializer
|
|
79
|
-
from nautobot.virtualization.api.nested_serializers import (
|
|
80
|
-
NestedClusterGroupSerializer,
|
|
81
|
-
NestedClusterSerializer,
|
|
82
|
-
)
|
|
83
|
-
from nautobot.virtualization.models import Cluster, ClusterGroup
|
|
84
|
-
|
|
85
|
-
from .customfields import CustomFieldModelSerializerMixin
|
|
86
|
-
from .fields import MultipleChoiceJSONField, RoleSerializerField, StatusSerializerField
|
|
87
|
-
from .relationships import RelationshipModelSerializerMixin
|
|
88
|
-
|
|
89
|
-
# Not all of these variable(s) are not actually used anywhere in this file, but required for the
|
|
90
|
-
# automagically replacing a Serializer with its corresponding NestedSerializer.
|
|
91
|
-
from .nested_serializers import ( # noqa: F401
|
|
92
|
-
NestedComputedFieldSerializer,
|
|
93
|
-
NestedConfigContextSchemaSerializer,
|
|
94
|
-
NestedConfigContextSerializer,
|
|
95
|
-
NestedCustomFieldChoiceSerializer,
|
|
96
|
-
NestedCustomFieldSerializer,
|
|
97
|
-
NestedCustomLinkSerializer,
|
|
98
|
-
NestedDynamicGroupSerializer,
|
|
99
|
-
NestedDynamicGroupMembershipSerializer,
|
|
100
|
-
NestedExportTemplateSerializer,
|
|
101
|
-
NestedGitRepositorySerializer,
|
|
102
|
-
NestedGraphQLQuerySerializer,
|
|
103
|
-
NestedImageAttachmentSerializer,
|
|
104
|
-
NestedJobButtonSerializer,
|
|
105
|
-
NestedJobHookSerializer,
|
|
106
|
-
NestedJobSerializer,
|
|
107
|
-
NestedJobResultSerializer,
|
|
108
|
-
NestedNoteSerializer,
|
|
109
|
-
NestedRelationshipAssociationSerializer,
|
|
110
|
-
NestedRelationshipSerializer,
|
|
111
|
-
NestedRoleSerializer,
|
|
112
|
-
NestedScheduledJobSerializer,
|
|
113
|
-
NestedScheduledJobCreationSerializer,
|
|
114
|
-
NestedSecretSerializer,
|
|
115
|
-
NestedSecretsGroupSerializer,
|
|
116
|
-
NestedSecretsGroupAssociationSerializer,
|
|
117
|
-
NestedStatusSerializer,
|
|
118
|
-
NestedTagSerializer,
|
|
119
|
-
NestedWebhookSerializer,
|
|
120
|
-
)
|
|
77
|
+
|
|
78
|
+
from .fields import MultipleChoiceJSONField
|
|
121
79
|
|
|
122
80
|
#
|
|
123
81
|
# Mixins and Base Classes
|
|
@@ -126,130 +84,19 @@ from .nested_serializers import ( # noqa: F401
|
|
|
126
84
|
logger = logging.getLogger(__name__)
|
|
127
85
|
|
|
128
86
|
|
|
129
|
-
class NotesSerializerMixin(BaseModelSerializer):
|
|
130
|
-
"""Extend Serializer with a `notes` field."""
|
|
131
|
-
|
|
132
|
-
notes_url = serializers.SerializerMethodField()
|
|
133
|
-
|
|
134
|
-
def get_field_names(self, declared_fields, info):
|
|
135
|
-
"""Ensure that fields includes "notes_url" field if applicable."""
|
|
136
|
-
fields = list(super().get_field_names(declared_fields, info))
|
|
137
|
-
if hasattr(self.Meta.model, "notes"):
|
|
138
|
-
self.extend_field_names(fields, "notes_url")
|
|
139
|
-
return fields
|
|
140
|
-
|
|
141
|
-
@extend_schema_field(serializers.URLField())
|
|
142
|
-
def get_notes_url(self, instance):
|
|
143
|
-
try:
|
|
144
|
-
notes_url = get_route_for_model(instance, "notes", api=True)
|
|
145
|
-
return reverse(notes_url, args=[instance.id], request=self.context["request"])
|
|
146
|
-
except NoReverseMatch:
|
|
147
|
-
model_name = type(instance).__name__
|
|
148
|
-
logger.warning(
|
|
149
|
-
(
|
|
150
|
-
f"Notes feature is not available for model {model_name}. "
|
|
151
|
-
"Please make sure to: "
|
|
152
|
-
f"1. Include NotesMixin from nautobot.extras.model.mixins in the {model_name} class definition "
|
|
153
|
-
f"2. Include NotesViewSetMixin from nautobot.extras.api.mixins in the {model_name}ViewSet "
|
|
154
|
-
"before including NotesSerializerMixin in the model serializer"
|
|
155
|
-
)
|
|
156
|
-
)
|
|
157
|
-
|
|
158
|
-
return None
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
class NautobotModelSerializer(
|
|
162
|
-
RelationshipModelSerializerMixin, CustomFieldModelSerializerMixin, NotesSerializerMixin, ValidatedModelSerializer
|
|
163
|
-
):
|
|
164
|
-
"""Base class to use for serializers based on OrganizationalModel or PrimaryModel.
|
|
165
|
-
|
|
166
|
-
Can also be used for models derived from BaseModel, so long as they support custom fields and relationships.
|
|
167
|
-
"""
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
class StatusModelSerializerMixin(BaseModelSerializer):
|
|
171
|
-
"""Mixin to add `status` choice field to model serializers."""
|
|
172
|
-
|
|
173
|
-
status = StatusSerializerField(required=True)
|
|
174
|
-
|
|
175
|
-
def get_field_names(self, declared_fields, info):
|
|
176
|
-
"""Ensure that "status" field is always present."""
|
|
177
|
-
fields = list(super().get_field_names(declared_fields, info))
|
|
178
|
-
self.extend_field_names(fields, "status")
|
|
179
|
-
return fields
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
class TagSerializerField(LimitQuerysetChoicesSerializerMixin, NestedTagSerializer):
|
|
183
|
-
"""NestedSerializer field for `Tag` object fields."""
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
class TaggedModelSerializerMixin(BaseModelSerializer):
|
|
187
|
-
tags = TagSerializerField(many=True, required=False)
|
|
188
|
-
|
|
189
|
-
def get_field_names(self, declared_fields, info):
|
|
190
|
-
"""Ensure that 'tags' field is always present."""
|
|
191
|
-
fields = list(super().get_field_names(declared_fields, info))
|
|
192
|
-
self.extend_field_names(fields, "tags")
|
|
193
|
-
return fields
|
|
194
|
-
|
|
195
|
-
def create(self, validated_data):
|
|
196
|
-
tags = validated_data.pop("tags", None)
|
|
197
|
-
instance = super().create(validated_data)
|
|
198
|
-
|
|
199
|
-
if tags is not None:
|
|
200
|
-
return self._save_tags(instance, tags)
|
|
201
|
-
return instance
|
|
202
|
-
|
|
203
|
-
def update(self, instance, validated_data):
|
|
204
|
-
tags = validated_data.pop("tags", None)
|
|
205
|
-
|
|
206
|
-
# Cache tags on instance for change logging
|
|
207
|
-
instance._tags = tags or []
|
|
208
|
-
|
|
209
|
-
instance = super().update(instance, validated_data)
|
|
210
|
-
|
|
211
|
-
if tags is not None:
|
|
212
|
-
return self._save_tags(instance, tags)
|
|
213
|
-
return instance
|
|
214
|
-
|
|
215
|
-
def _save_tags(self, instance, tags):
|
|
216
|
-
if tags:
|
|
217
|
-
instance.tags.set([t.name for t in tags])
|
|
218
|
-
else:
|
|
219
|
-
instance.tags.clear()
|
|
220
|
-
|
|
221
|
-
return instance
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
# TODO: remove in 2.2
|
|
225
|
-
@class_deprecated_in_favor_of(TaggedModelSerializerMixin)
|
|
226
|
-
class TaggedObjectSerializer(TaggedModelSerializerMixin):
|
|
227
|
-
pass
|
|
228
|
-
|
|
229
|
-
|
|
230
87
|
#
|
|
231
88
|
# Computed Fields
|
|
232
89
|
#
|
|
233
90
|
|
|
234
91
|
|
|
235
92
|
class ComputedFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
236
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:computedfield-detail")
|
|
237
93
|
content_type = ContentTypeField(
|
|
238
94
|
queryset=ContentType.objects.filter(FeatureQuery("custom_fields").get_query()).order_by("app_label", "model"),
|
|
239
95
|
)
|
|
240
96
|
|
|
241
97
|
class Meta:
|
|
242
98
|
model = ComputedField
|
|
243
|
-
fields =
|
|
244
|
-
"url",
|
|
245
|
-
"slug",
|
|
246
|
-
"label",
|
|
247
|
-
"description",
|
|
248
|
-
"content_type",
|
|
249
|
-
"template",
|
|
250
|
-
"fallback_value",
|
|
251
|
-
"weight",
|
|
252
|
-
)
|
|
99
|
+
fields = "__all__"
|
|
253
100
|
|
|
254
101
|
|
|
255
102
|
#
|
|
@@ -257,8 +104,7 @@ class ComputedFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
257
104
|
#
|
|
258
105
|
|
|
259
106
|
|
|
260
|
-
class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
261
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:configcontext-detail")
|
|
107
|
+
class ConfigContextSerializer(ValidatedModelSerializer, TaggedModelSerializerMixin, NotesSerializerMixin):
|
|
262
108
|
owner_content_type = ContentTypeField(
|
|
263
109
|
queryset=ContentType.objects.filter(FeatureQuery("config_context_owners").get_query()),
|
|
264
110
|
required=False,
|
|
@@ -266,63 +112,6 @@ class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
266
112
|
default=None,
|
|
267
113
|
)
|
|
268
114
|
owner = serializers.SerializerMethodField(read_only=True)
|
|
269
|
-
config_context_schema = NestedConfigContextSchemaSerializer(required=False, allow_null=True)
|
|
270
|
-
locations = SerializedPKRelatedField(
|
|
271
|
-
queryset=Location.objects.all(),
|
|
272
|
-
serializer=NestedLocationSerializer,
|
|
273
|
-
required=False,
|
|
274
|
-
many=True,
|
|
275
|
-
)
|
|
276
|
-
roles = SerializedPKRelatedField(
|
|
277
|
-
queryset=Role.objects.all(),
|
|
278
|
-
serializer=NestedRoleSerializer,
|
|
279
|
-
required=False,
|
|
280
|
-
many=True,
|
|
281
|
-
)
|
|
282
|
-
device_types = SerializedPKRelatedField(
|
|
283
|
-
queryset=DeviceType.objects.all(),
|
|
284
|
-
serializer=NestedDeviceTypeSerializer,
|
|
285
|
-
required=False,
|
|
286
|
-
many=True,
|
|
287
|
-
)
|
|
288
|
-
platforms = SerializedPKRelatedField(
|
|
289
|
-
queryset=Platform.objects.all(),
|
|
290
|
-
serializer=NestedPlatformSerializer,
|
|
291
|
-
required=False,
|
|
292
|
-
many=True,
|
|
293
|
-
)
|
|
294
|
-
cluster_groups = SerializedPKRelatedField(
|
|
295
|
-
queryset=ClusterGroup.objects.all(),
|
|
296
|
-
serializer=NestedClusterGroupSerializer,
|
|
297
|
-
required=False,
|
|
298
|
-
many=True,
|
|
299
|
-
)
|
|
300
|
-
clusters = SerializedPKRelatedField(
|
|
301
|
-
queryset=Cluster.objects.all(),
|
|
302
|
-
serializer=NestedClusterSerializer,
|
|
303
|
-
required=False,
|
|
304
|
-
many=True,
|
|
305
|
-
)
|
|
306
|
-
tenant_groups = SerializedPKRelatedField(
|
|
307
|
-
queryset=TenantGroup.objects.all(),
|
|
308
|
-
serializer=NestedTenantGroupSerializer,
|
|
309
|
-
required=False,
|
|
310
|
-
many=True,
|
|
311
|
-
)
|
|
312
|
-
tenants = SerializedPKRelatedField(
|
|
313
|
-
queryset=Tenant.objects.all(),
|
|
314
|
-
serializer=NestedTenantSerializer,
|
|
315
|
-
required=False,
|
|
316
|
-
many=True,
|
|
317
|
-
)
|
|
318
|
-
tags = serializers.SlugRelatedField(queryset=Tag.objects.all(), slug_field="slug", required=False, many=True)
|
|
319
|
-
|
|
320
|
-
dynamic_groups = SerializedPKRelatedField(
|
|
321
|
-
queryset=DynamicGroup.objects.all(),
|
|
322
|
-
serializer=NestedDynamicGroupSerializer,
|
|
323
|
-
required=False,
|
|
324
|
-
many=True,
|
|
325
|
-
)
|
|
326
115
|
|
|
327
116
|
# Conditional enablement of dynamic groups filtering
|
|
328
117
|
def __init__(self, *args, **kwargs):
|
|
@@ -333,45 +122,21 @@ class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
333
122
|
|
|
334
123
|
class Meta:
|
|
335
124
|
model = ConfigContext
|
|
336
|
-
fields =
|
|
337
|
-
"url",
|
|
338
|
-
"name",
|
|
339
|
-
"owner_content_type",
|
|
340
|
-
"owner_object_id",
|
|
341
|
-
"owner",
|
|
342
|
-
"weight",
|
|
343
|
-
"description",
|
|
344
|
-
"config_context_schema",
|
|
345
|
-
"is_active",
|
|
346
|
-
"locations",
|
|
347
|
-
"roles",
|
|
348
|
-
"device_types",
|
|
349
|
-
"platforms",
|
|
350
|
-
"cluster_groups",
|
|
351
|
-
"clusters",
|
|
352
|
-
"tenant_groups",
|
|
353
|
-
"tenants",
|
|
354
|
-
"tags",
|
|
355
|
-
"dynamic_groups",
|
|
356
|
-
"data",
|
|
357
|
-
]
|
|
125
|
+
fields = "__all__"
|
|
358
126
|
|
|
359
127
|
@extend_schema_field(
|
|
360
128
|
PolymorphicProxySerializer(
|
|
361
129
|
component_name="ConfigContextOwner",
|
|
362
130
|
resource_type_field_name="object_type",
|
|
363
|
-
serializers=lambda: get_serializers_for_models(
|
|
364
|
-
FeatureQuery("config_context_owners").list_subclasses(), prefix="Nested"
|
|
365
|
-
),
|
|
131
|
+
serializers=lambda: get_serializers_for_models(FeatureQuery("config_context_owners").list_subclasses()),
|
|
366
132
|
allow_null=True,
|
|
367
133
|
)
|
|
368
134
|
)
|
|
369
135
|
def get_owner(self, obj):
|
|
370
136
|
if obj.owner is None:
|
|
371
137
|
return None
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
return serializer(obj.owner, context=context).data
|
|
138
|
+
depth = get_nested_serializer_depth(self)
|
|
139
|
+
return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
|
|
375
140
|
|
|
376
141
|
|
|
377
142
|
#
|
|
@@ -380,7 +145,6 @@ class ConfigContextSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
380
145
|
|
|
381
146
|
|
|
382
147
|
class ConfigContextSchemaSerializer(NautobotModelSerializer):
|
|
383
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:configcontextschema-detail")
|
|
384
148
|
owner_content_type = ContentTypeField(
|
|
385
149
|
queryset=ContentType.objects.filter(FeatureQuery("config_context_owners").get_query()),
|
|
386
150
|
required=False,
|
|
@@ -391,33 +155,21 @@ class ConfigContextSchemaSerializer(NautobotModelSerializer):
|
|
|
391
155
|
|
|
392
156
|
class Meta:
|
|
393
157
|
model = ConfigContextSchema
|
|
394
|
-
fields =
|
|
395
|
-
"url",
|
|
396
|
-
"name",
|
|
397
|
-
"slug",
|
|
398
|
-
"owner_content_type",
|
|
399
|
-
"owner_object_id",
|
|
400
|
-
"owner",
|
|
401
|
-
"description",
|
|
402
|
-
"data_schema",
|
|
403
|
-
]
|
|
158
|
+
fields = "__all__"
|
|
404
159
|
|
|
405
160
|
@extend_schema_field(
|
|
406
161
|
PolymorphicProxySerializer(
|
|
407
162
|
component_name="ConfigContextSchemaOwner",
|
|
408
163
|
resource_type_field_name="object_type",
|
|
409
|
-
serializers=lambda: get_serializers_for_models(
|
|
410
|
-
FeatureQuery("config_context_owners").list_subclasses(), prefix="Nested"
|
|
411
|
-
),
|
|
164
|
+
serializers=lambda: get_serializers_for_models(FeatureQuery("config_context_owners").list_subclasses()),
|
|
412
165
|
allow_null=True,
|
|
413
166
|
)
|
|
414
167
|
)
|
|
415
168
|
def get_owner(self, obj):
|
|
416
169
|
if obj.owner is None:
|
|
417
170
|
return None
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
return serializer(obj.owner, context=context).data
|
|
171
|
+
depth = get_nested_serializer_depth(self)
|
|
172
|
+
return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
|
|
421
173
|
|
|
422
174
|
|
|
423
175
|
#
|
|
@@ -431,7 +183,7 @@ class ContentTypeSerializer(BaseModelSerializer):
|
|
|
431
183
|
|
|
432
184
|
class Meta:
|
|
433
185
|
model = ContentType
|
|
434
|
-
fields =
|
|
186
|
+
fields = "__all__"
|
|
435
187
|
|
|
436
188
|
@extend_schema_field(serializers.CharField)
|
|
437
189
|
def get_display(self, obj):
|
|
@@ -444,7 +196,6 @@ class ContentTypeSerializer(BaseModelSerializer):
|
|
|
444
196
|
|
|
445
197
|
|
|
446
198
|
class CustomFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
447
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:customfield-detail")
|
|
448
199
|
content_types = ContentTypeField(
|
|
449
200
|
queryset=ContentType.objects.filter(FeatureQuery("custom_fields").get_query()),
|
|
450
201
|
many=True,
|
|
@@ -455,30 +206,13 @@ class CustomFieldSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
455
206
|
|
|
456
207
|
class Meta:
|
|
457
208
|
model = CustomField
|
|
458
|
-
fields =
|
|
459
|
-
"url",
|
|
460
|
-
"content_types",
|
|
461
|
-
"type",
|
|
462
|
-
"label",
|
|
463
|
-
"key",
|
|
464
|
-
"description",
|
|
465
|
-
"required",
|
|
466
|
-
"filter_logic",
|
|
467
|
-
"default",
|
|
468
|
-
"weight",
|
|
469
|
-
"validation_minimum",
|
|
470
|
-
"validation_maximum",
|
|
471
|
-
"validation_regex",
|
|
472
|
-
]
|
|
209
|
+
fields = "__all__"
|
|
473
210
|
|
|
474
211
|
|
|
475
212
|
class CustomFieldChoiceSerializer(ValidatedModelSerializer):
|
|
476
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:customfieldchoice-detail")
|
|
477
|
-
custom_field = NestedCustomFieldSerializer()
|
|
478
|
-
|
|
479
213
|
class Meta:
|
|
480
214
|
model = CustomFieldChoice
|
|
481
|
-
fields =
|
|
215
|
+
fields = "__all__"
|
|
482
216
|
|
|
483
217
|
|
|
484
218
|
#
|
|
@@ -487,24 +221,13 @@ class CustomFieldChoiceSerializer(ValidatedModelSerializer):
|
|
|
487
221
|
|
|
488
222
|
|
|
489
223
|
class CustomLinkSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
490
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:customlink-detail")
|
|
491
224
|
content_type = ContentTypeField(
|
|
492
225
|
queryset=ContentType.objects.filter(FeatureQuery("custom_links").get_query()).order_by("app_label", "model"),
|
|
493
226
|
)
|
|
494
227
|
|
|
495
228
|
class Meta:
|
|
496
229
|
model = CustomLink
|
|
497
|
-
fields =
|
|
498
|
-
"url",
|
|
499
|
-
"target_url",
|
|
500
|
-
"name",
|
|
501
|
-
"content_type",
|
|
502
|
-
"text",
|
|
503
|
-
"weight",
|
|
504
|
-
"group_name",
|
|
505
|
-
"button_class",
|
|
506
|
-
"new_window",
|
|
507
|
-
)
|
|
230
|
+
fields = "__all__"
|
|
508
231
|
|
|
509
232
|
|
|
510
233
|
#
|
|
@@ -512,36 +235,24 @@ class CustomLinkSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
512
235
|
#
|
|
513
236
|
|
|
514
237
|
|
|
238
|
+
class DynamicGroupMembershipSerializer(ValidatedModelSerializer):
|
|
239
|
+
class Meta:
|
|
240
|
+
model = DynamicGroupMembership
|
|
241
|
+
fields = "__all__"
|
|
242
|
+
|
|
243
|
+
|
|
515
244
|
class DynamicGroupSerializer(NautobotModelSerializer):
|
|
516
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:dynamicgroup-detail")
|
|
517
245
|
content_type = ContentTypeField(
|
|
518
246
|
queryset=ContentType.objects.filter(FeatureQuery("dynamic_groups").get_query()).order_by("app_label", "model"),
|
|
519
247
|
)
|
|
520
|
-
# Read-only because m2m is hard. Easier to just create # `DynamicGroupMemberships` explicitly
|
|
521
|
-
# using their own endpoint at /api/extras/dynamic-group-memberships/.
|
|
522
|
-
children = NestedDynamicGroupMembershipSerializer(source="dynamic_group_memberships", read_only=True, many=True)
|
|
523
248
|
|
|
524
249
|
class Meta:
|
|
525
250
|
model = DynamicGroup
|
|
526
|
-
fields =
|
|
527
|
-
|
|
528
|
-
"
|
|
529
|
-
"
|
|
530
|
-
|
|
531
|
-
"filter",
|
|
532
|
-
"children",
|
|
533
|
-
]
|
|
534
|
-
extra_kwargs = {"filter": {"read_only": False}}
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
class DynamicGroupMembershipSerializer(ValidatedModelSerializer):
|
|
538
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:dynamicgroupmembership-detail")
|
|
539
|
-
group = NestedDynamicGroupSerializer()
|
|
540
|
-
parent_group = NestedDynamicGroupSerializer()
|
|
541
|
-
|
|
542
|
-
class Meta:
|
|
543
|
-
model = DynamicGroupMembership
|
|
544
|
-
fields = ["url", "group", "parent_group", "operator", "weight"]
|
|
251
|
+
fields = "__all__"
|
|
252
|
+
extra_kwargs = {
|
|
253
|
+
"children": {"source": "dynamic_group_memberships", "read_only": True},
|
|
254
|
+
"filter": {"read_only": False},
|
|
255
|
+
}
|
|
545
256
|
|
|
546
257
|
|
|
547
258
|
#
|
|
@@ -551,7 +262,6 @@ class DynamicGroupMembershipSerializer(ValidatedModelSerializer):
|
|
|
551
262
|
|
|
552
263
|
# TODO: export-templates don't support custom-fields, is this omission intentional?
|
|
553
264
|
class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelSerializer, NotesSerializerMixin):
|
|
554
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:exporttemplate-detail")
|
|
555
265
|
content_type = ContentTypeField(
|
|
556
266
|
queryset=ContentType.objects.filter(FeatureQuery("export_templates").get_query()),
|
|
557
267
|
)
|
|
@@ -565,35 +275,21 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
|
|
|
565
275
|
|
|
566
276
|
class Meta:
|
|
567
277
|
model = ExportTemplate
|
|
568
|
-
fields =
|
|
569
|
-
"url",
|
|
570
|
-
"content_type",
|
|
571
|
-
"owner_content_type",
|
|
572
|
-
"owner_object_id",
|
|
573
|
-
"owner",
|
|
574
|
-
"name",
|
|
575
|
-
"description",
|
|
576
|
-
"template_code",
|
|
577
|
-
"mime_type",
|
|
578
|
-
"file_extension",
|
|
579
|
-
]
|
|
278
|
+
fields = "__all__"
|
|
580
279
|
|
|
581
280
|
@extend_schema_field(
|
|
582
281
|
PolymorphicProxySerializer(
|
|
583
282
|
component_name="ExportTemplateOwner",
|
|
584
283
|
resource_type_field_name="object_type",
|
|
585
|
-
serializers=lambda: get_serializers_for_models(
|
|
586
|
-
FeatureQuery("export_template_owners").list_subclasses(), prefix="Nested"
|
|
587
|
-
),
|
|
284
|
+
serializers=lambda: get_serializers_for_models(FeatureQuery("export_template_owners").list_subclasses()),
|
|
588
285
|
allow_null=True,
|
|
589
286
|
)
|
|
590
287
|
)
|
|
591
288
|
def get_owner(self, obj):
|
|
592
289
|
if obj.owner is None:
|
|
593
290
|
return None
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
return serializer(obj.owner, context=context).data
|
|
291
|
+
depth = get_nested_serializer_depth(self)
|
|
292
|
+
return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.owner, "owner")
|
|
597
293
|
|
|
598
294
|
|
|
599
295
|
#
|
|
@@ -604,10 +300,6 @@ class ExportTemplateSerializer(RelationshipModelSerializerMixin, ValidatedModelS
|
|
|
604
300
|
class GitRepositorySerializer(NautobotModelSerializer):
|
|
605
301
|
"""Git repositories defined as a data source."""
|
|
606
302
|
|
|
607
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:gitrepository-detail")
|
|
608
|
-
|
|
609
|
-
secrets_group = NestedSecretsGroupSerializer(required=False, allow_null=True)
|
|
610
|
-
|
|
611
303
|
provided_contents = MultipleChoiceJSONField(
|
|
612
304
|
choices=lambda: get_datasource_content_choices("extras.gitrepository"),
|
|
613
305
|
allow_blank=True,
|
|
@@ -616,23 +308,7 @@ class GitRepositorySerializer(NautobotModelSerializer):
|
|
|
616
308
|
|
|
617
309
|
class Meta:
|
|
618
310
|
model = GitRepository
|
|
619
|
-
fields =
|
|
620
|
-
"url",
|
|
621
|
-
"name",
|
|
622
|
-
"slug",
|
|
623
|
-
"remote_url",
|
|
624
|
-
"branch",
|
|
625
|
-
"secrets_group",
|
|
626
|
-
"current_head",
|
|
627
|
-
"provided_contents",
|
|
628
|
-
]
|
|
629
|
-
|
|
630
|
-
def validate(self, data):
|
|
631
|
-
"""
|
|
632
|
-
Add the originating Request as a parameter to be passed when creating/updating a GitRepository.
|
|
633
|
-
"""
|
|
634
|
-
data["request"] = self.context["request"]
|
|
635
|
-
return super().validate(data)
|
|
311
|
+
fields = "__all__"
|
|
636
312
|
|
|
637
313
|
|
|
638
314
|
#
|
|
@@ -641,17 +317,11 @@ class GitRepositorySerializer(NautobotModelSerializer):
|
|
|
641
317
|
|
|
642
318
|
|
|
643
319
|
class GraphQLQuerySerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
644
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:graphqlquery-detail")
|
|
645
320
|
variables = serializers.DictField(required=False, allow_null=True, default={})
|
|
646
321
|
|
|
647
322
|
class Meta:
|
|
648
323
|
model = GraphQLQuery
|
|
649
|
-
fields =
|
|
650
|
-
"url",
|
|
651
|
-
"name",
|
|
652
|
-
"query",
|
|
653
|
-
"variables",
|
|
654
|
-
)
|
|
324
|
+
fields = "__all__"
|
|
655
325
|
|
|
656
326
|
|
|
657
327
|
class GraphQLQueryInputSerializer(serializers.Serializer):
|
|
@@ -668,23 +338,11 @@ class GraphQLQueryOutputSerializer(serializers.Serializer):
|
|
|
668
338
|
|
|
669
339
|
|
|
670
340
|
class ImageAttachmentSerializer(ValidatedModelSerializer):
|
|
671
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:imageattachment-detail")
|
|
672
341
|
content_type = ContentTypeField(queryset=ContentType.objects.all())
|
|
673
|
-
parent = serializers.SerializerMethodField(read_only=True)
|
|
674
342
|
|
|
675
343
|
class Meta:
|
|
676
344
|
model = ImageAttachment
|
|
677
|
-
fields =
|
|
678
|
-
"url",
|
|
679
|
-
"content_type",
|
|
680
|
-
"object_id",
|
|
681
|
-
"parent",
|
|
682
|
-
"name",
|
|
683
|
-
"image",
|
|
684
|
-
"image_height",
|
|
685
|
-
"image_width",
|
|
686
|
-
"created",
|
|
687
|
-
]
|
|
345
|
+
fields = "__all__"
|
|
688
346
|
|
|
689
347
|
def validate(self, data):
|
|
690
348
|
# Validate that the parent object exists
|
|
@@ -703,15 +361,15 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
|
|
|
703
361
|
component_name="ImageAttachmentParent",
|
|
704
362
|
resource_type_field_name="object_type",
|
|
705
363
|
serializers=[
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
364
|
+
DeviceSerializer,
|
|
365
|
+
LocationSerializer,
|
|
366
|
+
RackSerializer,
|
|
709
367
|
],
|
|
710
368
|
)
|
|
711
369
|
)
|
|
712
370
|
def get_parent(self, obj):
|
|
713
|
-
|
|
714
|
-
return
|
|
371
|
+
depth = get_nested_serializer_depth(self)
|
|
372
|
+
return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.parent, "parent")
|
|
715
373
|
|
|
716
374
|
|
|
717
375
|
#
|
|
@@ -720,44 +378,9 @@ class ImageAttachmentSerializer(ValidatedModelSerializer):
|
|
|
720
378
|
|
|
721
379
|
|
|
722
380
|
class JobSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
723
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:job-detail")
|
|
724
|
-
|
|
725
381
|
class Meta:
|
|
726
382
|
model = Job
|
|
727
|
-
fields =
|
|
728
|
-
"url",
|
|
729
|
-
"source",
|
|
730
|
-
"module_name",
|
|
731
|
-
"job_class_name",
|
|
732
|
-
"grouping",
|
|
733
|
-
"grouping_override",
|
|
734
|
-
"name",
|
|
735
|
-
"name_override",
|
|
736
|
-
"slug",
|
|
737
|
-
"description",
|
|
738
|
-
"description_override",
|
|
739
|
-
"installed",
|
|
740
|
-
"enabled",
|
|
741
|
-
"is_job_hook_receiver",
|
|
742
|
-
"is_job_button_receiver",
|
|
743
|
-
"has_sensitive_variables",
|
|
744
|
-
"has_sensitive_variables_override",
|
|
745
|
-
"approval_required",
|
|
746
|
-
"approval_required_override",
|
|
747
|
-
"commit_default",
|
|
748
|
-
"commit_default_override",
|
|
749
|
-
"hidden",
|
|
750
|
-
"hidden_override",
|
|
751
|
-
"read_only",
|
|
752
|
-
"read_only_override",
|
|
753
|
-
"soft_time_limit",
|
|
754
|
-
"soft_time_limit_override",
|
|
755
|
-
"time_limit",
|
|
756
|
-
"time_limit_override",
|
|
757
|
-
"task_queues",
|
|
758
|
-
"task_queues_override",
|
|
759
|
-
"tags",
|
|
760
|
-
]
|
|
383
|
+
fields = "__all__"
|
|
761
384
|
|
|
762
385
|
def validate(self, data):
|
|
763
386
|
# note no validation for on creation of jobs because we do not support user creation of Job records via API
|
|
@@ -788,7 +411,6 @@ class JobVariableSerializer(serializers.Serializer):
|
|
|
788
411
|
help_text = serializers.CharField(read_only=True, required=False)
|
|
789
412
|
default = serializers.JSONField(read_only=True, required=False)
|
|
790
413
|
required = serializers.BooleanField(read_only=True, required=False)
|
|
791
|
-
|
|
792
414
|
min_length = serializers.IntegerField(read_only=True, required=False)
|
|
793
415
|
max_length = serializers.IntegerField(read_only=True, required=False)
|
|
794
416
|
min_value = serializers.IntegerField(read_only=True, required=False)
|
|
@@ -797,11 +419,17 @@ class JobVariableSerializer(serializers.Serializer):
|
|
|
797
419
|
model = serializers.CharField(read_only=True, required=False)
|
|
798
420
|
|
|
799
421
|
|
|
800
|
-
|
|
801
|
-
|
|
422
|
+
#
|
|
423
|
+
# Scheduled Jobs
|
|
424
|
+
#
|
|
425
|
+
|
|
802
426
|
|
|
803
|
-
|
|
804
|
-
|
|
427
|
+
class ScheduledJobSerializer(BaseModelSerializer):
|
|
428
|
+
# start_time = serializers.DateTimeField(format=None, required=False)
|
|
429
|
+
|
|
430
|
+
class Meta:
|
|
431
|
+
model = ScheduledJob
|
|
432
|
+
fields = "__all__"
|
|
805
433
|
|
|
806
434
|
|
|
807
435
|
#
|
|
@@ -810,63 +438,18 @@ class JobRunResponseSerializer(serializers.Serializer):
|
|
|
810
438
|
|
|
811
439
|
|
|
812
440
|
class JobResultSerializer(CustomFieldModelSerializerMixin, BaseModelSerializer):
|
|
813
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:jobresult-detail")
|
|
814
|
-
user = NestedUserSerializer(read_only=True)
|
|
815
441
|
status = ChoiceField(choices=JobResultStatusChoices, read_only=True)
|
|
816
|
-
job_model = NestedJobSerializer(read_only=True)
|
|
817
|
-
obj_type = ContentTypeField(read_only=True)
|
|
818
|
-
scheduled_job = NestedScheduledJobSerializer(read_only=True)
|
|
819
442
|
|
|
820
443
|
class Meta:
|
|
821
444
|
model = JobResult
|
|
822
|
-
fields =
|
|
823
|
-
"url",
|
|
824
|
-
"date_created",
|
|
825
|
-
"date_done",
|
|
826
|
-
"name",
|
|
827
|
-
"job_model",
|
|
828
|
-
"obj_type",
|
|
829
|
-
"status",
|
|
830
|
-
"user",
|
|
831
|
-
"data",
|
|
832
|
-
"task_id",
|
|
833
|
-
"task_kwargs",
|
|
834
|
-
"scheduled_job",
|
|
835
|
-
]
|
|
445
|
+
fields = "__all__"
|
|
836
446
|
|
|
837
447
|
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
#
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
class ScheduledJobSerializer(BaseModelSerializer):
|
|
844
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:scheduledjob-detail")
|
|
845
|
-
user = NestedUserSerializer(read_only=True)
|
|
846
|
-
job_model = NestedJobSerializer(read_only=True)
|
|
847
|
-
approved_by_user = NestedUserSerializer(read_only=True)
|
|
448
|
+
class JobRunResponseSerializer(serializers.Serializer):
|
|
449
|
+
"""Serializer representing responses from the JobModelViewSet.run() POST endpoint."""
|
|
848
450
|
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
fields = [
|
|
852
|
-
"url",
|
|
853
|
-
"name",
|
|
854
|
-
"user",
|
|
855
|
-
"job_model",
|
|
856
|
-
"task",
|
|
857
|
-
"interval",
|
|
858
|
-
"queue",
|
|
859
|
-
"job_class",
|
|
860
|
-
"last_run_at",
|
|
861
|
-
"total_run_count",
|
|
862
|
-
"date_changed",
|
|
863
|
-
"description",
|
|
864
|
-
"user",
|
|
865
|
-
"approved_by_user",
|
|
866
|
-
"approval_required",
|
|
867
|
-
"approved_at",
|
|
868
|
-
"crontab",
|
|
869
|
-
]
|
|
451
|
+
schedule = ScheduledJobSerializer(read_only=True, required=False)
|
|
452
|
+
job_result = JobResultSerializer(read_only=True, required=False)
|
|
870
453
|
|
|
871
454
|
|
|
872
455
|
#
|
|
@@ -887,7 +470,6 @@ class JobClassSerializer(serializers.Serializer):
|
|
|
887
470
|
description = serializers.CharField(max_length=255, required=False, read_only=True)
|
|
888
471
|
test_methods = serializers.ListField(child=serializers.CharField(max_length=255))
|
|
889
472
|
vars = serializers.SerializerMethodField(read_only=True)
|
|
890
|
-
result = NestedJobResultSerializer(required=False)
|
|
891
473
|
|
|
892
474
|
@extend_schema_field(serializers.DictField)
|
|
893
475
|
def get_vars(self, instance):
|
|
@@ -910,7 +492,6 @@ class JobClassDetailSerializer(JobClassSerializer):
|
|
|
910
492
|
|
|
911
493
|
|
|
912
494
|
class JobHookSerializer(NautobotModelSerializer):
|
|
913
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:jobhook-detail")
|
|
914
495
|
content_types = ContentTypeField(
|
|
915
496
|
queryset=ChangeLoggedModelsQuery().as_queryset(),
|
|
916
497
|
many=True,
|
|
@@ -918,17 +499,7 @@ class JobHookSerializer(NautobotModelSerializer):
|
|
|
918
499
|
|
|
919
500
|
class Meta:
|
|
920
501
|
model = JobHook
|
|
921
|
-
fields =
|
|
922
|
-
"id",
|
|
923
|
-
"url",
|
|
924
|
-
"name",
|
|
925
|
-
"content_types",
|
|
926
|
-
"job",
|
|
927
|
-
"enabled",
|
|
928
|
-
"type_create",
|
|
929
|
-
"type_update",
|
|
930
|
-
"type_delete",
|
|
931
|
-
]
|
|
502
|
+
fields = "__all__"
|
|
932
503
|
|
|
933
504
|
def validate(self, data):
|
|
934
505
|
validated_data = super().validate(data)
|
|
@@ -948,17 +519,58 @@ class JobHookSerializer(NautobotModelSerializer):
|
|
|
948
519
|
return validated_data
|
|
949
520
|
|
|
950
521
|
|
|
522
|
+
class JobCreationSerializer(BaseModelSerializer):
|
|
523
|
+
"""
|
|
524
|
+
Nested serializer specifically for use with `JobInputSerializer.schedule`.
|
|
525
|
+
|
|
526
|
+
We don't use `WritableNestedSerializer` here because this is not used to look up
|
|
527
|
+
an existing `ScheduledJob`, but instead used to specify parameters for creating one.
|
|
528
|
+
"""
|
|
529
|
+
|
|
530
|
+
url = serializers.HyperlinkedIdentityField(view_name="extras-api:scheduledjob-detail")
|
|
531
|
+
name = serializers.CharField(max_length=255, required=False)
|
|
532
|
+
start_time = serializers.DateTimeField(format=None, required=False)
|
|
533
|
+
|
|
534
|
+
class Meta:
|
|
535
|
+
model = ScheduledJob
|
|
536
|
+
fields = ["url", "name", "start_time", "interval", "crontab"]
|
|
537
|
+
|
|
538
|
+
def validate(self, data):
|
|
539
|
+
data = super().validate(data)
|
|
540
|
+
|
|
541
|
+
if data["interval"] in choices.JobExecutionType.SCHEDULE_CHOICES:
|
|
542
|
+
if "name" not in data:
|
|
543
|
+
raise serializers.ValidationError({"name": "Please provide a name for the job schedule."})
|
|
544
|
+
|
|
545
|
+
if ("start_time" not in data and data["interval"] != choices.JobExecutionType.TYPE_CUSTOM) or (
|
|
546
|
+
"start_time" in data and data["start_time"] < models.ScheduledJob.earliest_possible_time()
|
|
547
|
+
):
|
|
548
|
+
raise serializers.ValidationError(
|
|
549
|
+
{
|
|
550
|
+
"start_time": "Please enter a valid date and time greater than or equal to the current date and time."
|
|
551
|
+
}
|
|
552
|
+
)
|
|
553
|
+
|
|
554
|
+
if data["interval"] == choices.JobExecutionType.TYPE_CUSTOM:
|
|
555
|
+
if data.get("crontab") is None:
|
|
556
|
+
raise serializers.ValidationError({"crontab": "Please enter a valid crontab."})
|
|
557
|
+
try:
|
|
558
|
+
models.ScheduledJob.get_crontab(data["crontab"])
|
|
559
|
+
except Exception as e:
|
|
560
|
+
raise serializers.ValidationError({"crontab": e})
|
|
561
|
+
|
|
562
|
+
return data
|
|
563
|
+
|
|
564
|
+
|
|
951
565
|
class JobInputSerializer(serializers.Serializer):
|
|
952
566
|
data = serializers.JSONField(required=False, default=dict)
|
|
953
|
-
|
|
954
|
-
schedule = NestedScheduledJobCreationSerializer(required=False)
|
|
567
|
+
schedule = JobCreationSerializer(required=False)
|
|
955
568
|
task_queue = serializers.CharField(required=False, allow_blank=True)
|
|
956
569
|
|
|
957
570
|
|
|
958
571
|
class JobMultiPartInputSerializer(serializers.Serializer):
|
|
959
572
|
"""JobMultiPartInputSerializer is a "flattened" version of JobInputSerializer for use with multipart/form-data submissions which only accept key-value pairs"""
|
|
960
573
|
|
|
961
|
-
_commit = serializers.BooleanField(required=False, default=None)
|
|
962
574
|
_schedule_name = serializers.CharField(max_length=255, required=False)
|
|
963
575
|
_schedule_start_time = serializers.DateTimeField(format=None, required=False)
|
|
964
576
|
_schedule_interval = ChoiceField(choices=JobExecutionType, required=False)
|
|
@@ -993,25 +605,9 @@ class JobMultiPartInputSerializer(serializers.Serializer):
|
|
|
993
605
|
|
|
994
606
|
|
|
995
607
|
class JobLogEntrySerializer(BaseModelSerializer):
|
|
996
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:joblogentry-detail")
|
|
997
|
-
display = serializers.SerializerMethodField()
|
|
998
|
-
|
|
999
608
|
class Meta:
|
|
1000
609
|
model = JobLogEntry
|
|
1001
|
-
fields =
|
|
1002
|
-
"url",
|
|
1003
|
-
"absolute_url",
|
|
1004
|
-
"created",
|
|
1005
|
-
"grouping",
|
|
1006
|
-
"job_result",
|
|
1007
|
-
"log_level",
|
|
1008
|
-
"log_object",
|
|
1009
|
-
"message",
|
|
1010
|
-
]
|
|
1011
|
-
|
|
1012
|
-
@extend_schema_field(serializers.CharField)
|
|
1013
|
-
def get_display(self, obj):
|
|
1014
|
-
return obj.created.isoformat()
|
|
610
|
+
fields = "__all__"
|
|
1015
611
|
|
|
1016
612
|
|
|
1017
613
|
#
|
|
@@ -1020,22 +616,11 @@ class JobLogEntrySerializer(BaseModelSerializer):
|
|
|
1020
616
|
|
|
1021
617
|
|
|
1022
618
|
class JobButtonSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
1023
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:jobbutton-detail")
|
|
1024
619
|
content_types = ContentTypeField(queryset=ContentType.objects.all(), many=True)
|
|
1025
620
|
|
|
1026
621
|
class Meta:
|
|
1027
622
|
model = JobButton
|
|
1028
|
-
fields =
|
|
1029
|
-
"url",
|
|
1030
|
-
"job",
|
|
1031
|
-
"name",
|
|
1032
|
-
"content_types",
|
|
1033
|
-
"text",
|
|
1034
|
-
"weight",
|
|
1035
|
-
"group_name",
|
|
1036
|
-
"button_class",
|
|
1037
|
-
"confirmation",
|
|
1038
|
-
)
|
|
623
|
+
fields = "__all__"
|
|
1039
624
|
|
|
1040
625
|
|
|
1041
626
|
#
|
|
@@ -1044,29 +629,19 @@ class JobButtonSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
1044
629
|
|
|
1045
630
|
|
|
1046
631
|
class NoteSerializer(BaseModelSerializer):
|
|
1047
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:note-detail")
|
|
1048
|
-
user = NestedUserSerializer(read_only=True)
|
|
1049
632
|
assigned_object_type = ContentTypeField(queryset=ContentType.objects.all())
|
|
1050
633
|
assigned_object = serializers.SerializerMethodField()
|
|
1051
634
|
|
|
1052
635
|
class Meta:
|
|
1053
636
|
model = Note
|
|
1054
|
-
fields =
|
|
1055
|
-
|
|
1056
|
-
"user",
|
|
1057
|
-
"user_name",
|
|
1058
|
-
"assigned_object_type",
|
|
1059
|
-
"assigned_object_id",
|
|
1060
|
-
"assigned_object",
|
|
1061
|
-
"note",
|
|
1062
|
-
"slug",
|
|
1063
|
-
]
|
|
637
|
+
fields = "__all__"
|
|
638
|
+
list_display_fields = ["note", "assigned_object_type", "assigned_object_id", "user"]
|
|
1064
639
|
|
|
1065
640
|
@extend_schema_field(
|
|
1066
641
|
PolymorphicProxySerializer(
|
|
1067
642
|
component_name="NoteAssignedObject",
|
|
1068
643
|
resource_type_field_name="object_type",
|
|
1069
|
-
serializers=lambda: get_serializers_for_models(get_all_concrete_models(NotesMixin)
|
|
644
|
+
serializers=lambda: get_serializers_for_models(get_all_concrete_models(NotesMixin)),
|
|
1070
645
|
allow_null=True,
|
|
1071
646
|
)
|
|
1072
647
|
)
|
|
@@ -1074,9 +649,10 @@ class NoteSerializer(BaseModelSerializer):
|
|
|
1074
649
|
if obj.assigned_object is None:
|
|
1075
650
|
return None
|
|
1076
651
|
try:
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
652
|
+
depth = get_nested_serializer_depth(self)
|
|
653
|
+
return return_nested_serializer_data_based_on_depth(
|
|
654
|
+
self, depth, obj, obj.assigned_object, "assigned_object"
|
|
655
|
+
)
|
|
1080
656
|
except SerializerNotFound:
|
|
1081
657
|
return None
|
|
1082
658
|
|
|
@@ -1091,34 +667,20 @@ class NoteInputSerializer(serializers.Serializer):
|
|
|
1091
667
|
|
|
1092
668
|
|
|
1093
669
|
class ObjectChangeSerializer(BaseModelSerializer):
|
|
1094
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:objectchange-detail")
|
|
1095
|
-
user = NestedUserSerializer(read_only=True)
|
|
1096
670
|
action = ChoiceField(choices=ObjectChangeActionChoices, read_only=True)
|
|
1097
671
|
changed_object_type = ContentTypeField(read_only=True)
|
|
1098
672
|
changed_object = serializers.SerializerMethodField(read_only=True)
|
|
1099
673
|
|
|
1100
674
|
class Meta:
|
|
1101
675
|
model = ObjectChange
|
|
1102
|
-
fields =
|
|
1103
|
-
|
|
1104
|
-
"time",
|
|
1105
|
-
"user",
|
|
1106
|
-
"user_name",
|
|
1107
|
-
"request_id",
|
|
1108
|
-
"action",
|
|
1109
|
-
"changed_object_type",
|
|
1110
|
-
"changed_object_id",
|
|
1111
|
-
"changed_object",
|
|
1112
|
-
"object_data",
|
|
1113
|
-
]
|
|
676
|
+
fields = "__all__"
|
|
677
|
+
list_display_fields = ["changed_object_id", "related_object_id", "related_object_type", "user"]
|
|
1114
678
|
|
|
1115
679
|
@extend_schema_field(
|
|
1116
680
|
PolymorphicProxySerializer(
|
|
1117
681
|
component_name="ObjectChangeChangedObject",
|
|
1118
682
|
resource_type_field_name="object_type",
|
|
1119
|
-
serializers=lambda: get_serializers_for_models(
|
|
1120
|
-
ChangeLoggedModelsQuery().list_subclasses(), prefix="Nested"
|
|
1121
|
-
),
|
|
683
|
+
serializers=lambda: get_serializers_for_models(ChangeLoggedModelsQuery().list_subclasses()),
|
|
1122
684
|
allow_null=True,
|
|
1123
685
|
)
|
|
1124
686
|
)
|
|
@@ -1128,15 +690,11 @@ class ObjectChangeSerializer(BaseModelSerializer):
|
|
|
1128
690
|
"""
|
|
1129
691
|
if obj.changed_object is None:
|
|
1130
692
|
return None
|
|
1131
|
-
|
|
1132
693
|
try:
|
|
1133
|
-
|
|
694
|
+
depth = get_nested_serializer_depth(self)
|
|
695
|
+
return return_nested_serializer_data_based_on_depth(self, depth, obj, obj.changed_object, "changed_object")
|
|
1134
696
|
except SerializerNotFound:
|
|
1135
697
|
return obj.object_repr
|
|
1136
|
-
context = {"request": self.context["request"]}
|
|
1137
|
-
data = serializer(obj.changed_object, context=context).data
|
|
1138
|
-
|
|
1139
|
-
return data
|
|
1140
698
|
|
|
1141
699
|
|
|
1142
700
|
#
|
|
@@ -1145,8 +703,6 @@ class ObjectChangeSerializer(BaseModelSerializer):
|
|
|
1145
703
|
|
|
1146
704
|
|
|
1147
705
|
class RelationshipSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
1148
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:relationship-detail")
|
|
1149
|
-
|
|
1150
706
|
source_type = ContentTypeField(
|
|
1151
707
|
queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()),
|
|
1152
708
|
)
|
|
@@ -1157,27 +713,10 @@ class RelationshipSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
1157
713
|
|
|
1158
714
|
class Meta:
|
|
1159
715
|
model = Relationship
|
|
1160
|
-
fields =
|
|
1161
|
-
"url",
|
|
1162
|
-
"name",
|
|
1163
|
-
"slug",
|
|
1164
|
-
"description",
|
|
1165
|
-
"type",
|
|
1166
|
-
"required_on",
|
|
1167
|
-
"source_type",
|
|
1168
|
-
"source_label",
|
|
1169
|
-
"source_hidden",
|
|
1170
|
-
"source_filter",
|
|
1171
|
-
"destination_type",
|
|
1172
|
-
"destination_label",
|
|
1173
|
-
"destination_hidden",
|
|
1174
|
-
"destination_filter",
|
|
1175
|
-
]
|
|
716
|
+
fields = "__all__"
|
|
1176
717
|
|
|
1177
718
|
|
|
1178
719
|
class RelationshipAssociationSerializer(ValidatedModelSerializer):
|
|
1179
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:relationshipassociation-detail")
|
|
1180
|
-
|
|
1181
720
|
source_type = ContentTypeField(
|
|
1182
721
|
queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()),
|
|
1183
722
|
)
|
|
@@ -1186,18 +725,9 @@ class RelationshipAssociationSerializer(ValidatedModelSerializer):
|
|
|
1186
725
|
queryset=ContentType.objects.filter(FeatureQuery("relationships").get_query()),
|
|
1187
726
|
)
|
|
1188
727
|
|
|
1189
|
-
relationship = NestedRelationshipSerializer()
|
|
1190
|
-
|
|
1191
728
|
class Meta:
|
|
1192
729
|
model = RelationshipAssociation
|
|
1193
|
-
fields =
|
|
1194
|
-
"url",
|
|
1195
|
-
"relationship",
|
|
1196
|
-
"source_type",
|
|
1197
|
-
"source_id",
|
|
1198
|
-
"destination_type",
|
|
1199
|
-
"destination_id",
|
|
1200
|
-
]
|
|
730
|
+
fields = "__all__"
|
|
1201
731
|
|
|
1202
732
|
|
|
1203
733
|
#
|
|
@@ -1205,22 +735,9 @@ class RelationshipAssociationSerializer(ValidatedModelSerializer):
|
|
|
1205
735
|
#
|
|
1206
736
|
|
|
1207
737
|
|
|
1208
|
-
class RoleModelSerializerMixin(BaseModelSerializer):
|
|
1209
|
-
"""Mixin to add `role` choice field to model serializers."""
|
|
1210
|
-
|
|
1211
|
-
role = RoleSerializerField(required=False)
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
class RoleRequiredRoleModelSerializerMixin(BaseModelSerializer):
|
|
1215
|
-
"""Mixin to add `role` choice field to model serializers."""
|
|
1216
|
-
|
|
1217
|
-
role = RoleSerializerField()
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
738
|
class RoleSerializer(NautobotModelSerializer):
|
|
1221
739
|
"""Serializer for `Role` objects."""
|
|
1222
740
|
|
|
1223
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:role-detail")
|
|
1224
741
|
content_types = ContentTypeField(
|
|
1225
742
|
queryset=RoleModelsQuery().as_queryset(),
|
|
1226
743
|
many=True,
|
|
@@ -1228,13 +745,10 @@ class RoleSerializer(NautobotModelSerializer):
|
|
|
1228
745
|
|
|
1229
746
|
class Meta:
|
|
1230
747
|
model = Role
|
|
1231
|
-
fields =
|
|
1232
|
-
|
|
1233
|
-
"
|
|
1234
|
-
|
|
1235
|
-
"color",
|
|
1236
|
-
"weight",
|
|
1237
|
-
]
|
|
748
|
+
fields = "__all__"
|
|
749
|
+
extra_kwargs = {
|
|
750
|
+
"color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
|
|
751
|
+
}
|
|
1238
752
|
|
|
1239
753
|
|
|
1240
754
|
#
|
|
@@ -1245,57 +759,33 @@ class RoleSerializer(NautobotModelSerializer):
|
|
|
1245
759
|
class SecretSerializer(NautobotModelSerializer, TaggedModelSerializerMixin):
|
|
1246
760
|
"""Serializer for `Secret` objects."""
|
|
1247
761
|
|
|
1248
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:secret-detail")
|
|
1249
|
-
|
|
1250
762
|
class Meta:
|
|
1251
763
|
model = Secret
|
|
1252
|
-
fields =
|
|
1253
|
-
"url",
|
|
1254
|
-
"name",
|
|
1255
|
-
"description",
|
|
1256
|
-
"provider",
|
|
1257
|
-
"parameters",
|
|
1258
|
-
]
|
|
764
|
+
fields = "__all__"
|
|
1259
765
|
|
|
1260
766
|
|
|
1261
|
-
class
|
|
1262
|
-
"""Serializer for `
|
|
1263
|
-
|
|
1264
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:secretsgroup-detail")
|
|
1265
|
-
|
|
1266
|
-
# TODO: it would be **awesome** if we could create/update SecretsGroupAssociations
|
|
1267
|
-
# alongside creating/updating the base SecretsGroup, but since this is a ManyToManyField with
|
|
1268
|
-
# a `through` table, that appears very non-trivial to implement. For now we have this as a
|
|
1269
|
-
# read-only field; to create/update SecretsGroupAssociations you must make separate calls to the
|
|
1270
|
-
# api/extras/secrets-group-associations/ REST endpoint as appropriate.
|
|
1271
|
-
secrets = NestedSecretsGroupAssociationSerializer(source="secrets_group_associations", many=True, read_only=True)
|
|
767
|
+
class SecretsGroupAssociationSerializer(ValidatedModelSerializer):
|
|
768
|
+
"""Serializer for `SecretsGroupAssociation` objects."""
|
|
1272
769
|
|
|
1273
770
|
class Meta:
|
|
1274
|
-
model =
|
|
1275
|
-
fields =
|
|
1276
|
-
"url",
|
|
1277
|
-
"name",
|
|
1278
|
-
"description",
|
|
1279
|
-
"secrets",
|
|
1280
|
-
]
|
|
1281
|
-
|
|
771
|
+
model = SecretsGroupAssociation
|
|
772
|
+
fields = "__all__"
|
|
1282
773
|
|
|
1283
|
-
class SecretsGroupAssociationSerializer(ValidatedModelSerializer):
|
|
1284
|
-
"""Serializer for `SecretsGroupAssociation` objects."""
|
|
1285
774
|
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
secret = NestedSecretSerializer()
|
|
775
|
+
class SecretsGroupSerializer(NautobotModelSerializer):
|
|
776
|
+
"""Serializer for `SecretsGroup` objects."""
|
|
1289
777
|
|
|
1290
778
|
class Meta:
|
|
1291
|
-
model =
|
|
1292
|
-
fields =
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
779
|
+
model = SecretsGroup
|
|
780
|
+
fields = "__all__"
|
|
781
|
+
# TODO: it would be **awesome** if we could create/update SecretsGroupAssociations
|
|
782
|
+
# alongside creating/updating the base SecretsGroup, but since this is a ManyToManyField with
|
|
783
|
+
# a `through` table, that appears very non-trivial to implement. For now we have this as a
|
|
784
|
+
# read-only field; to create/update SecretsGroupAssociations you must make separate calls to the
|
|
785
|
+
# api/extras/secrets-group-associations/ REST endpoint as appropriate.
|
|
786
|
+
extra_kwargs = {
|
|
787
|
+
"secrets": {"source": "secrets_group_associations", "read_only": True},
|
|
788
|
+
}
|
|
1299
789
|
|
|
1300
790
|
|
|
1301
791
|
#
|
|
@@ -1306,7 +796,6 @@ class SecretsGroupAssociationSerializer(ValidatedModelSerializer):
|
|
|
1306
796
|
class StatusSerializer(NautobotModelSerializer):
|
|
1307
797
|
"""Serializer for `Status` objects."""
|
|
1308
798
|
|
|
1309
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:status-detail")
|
|
1310
799
|
content_types = ContentTypeField(
|
|
1311
800
|
queryset=ContentType.objects.filter(FeatureQuery("statuses").get_query()),
|
|
1312
801
|
many=True,
|
|
@@ -1314,12 +803,10 @@ class StatusSerializer(NautobotModelSerializer):
|
|
|
1314
803
|
|
|
1315
804
|
class Meta:
|
|
1316
805
|
model = Status
|
|
1317
|
-
fields =
|
|
1318
|
-
|
|
1319
|
-
"
|
|
1320
|
-
|
|
1321
|
-
"color",
|
|
1322
|
-
]
|
|
806
|
+
fields = "__all__"
|
|
807
|
+
extra_kwargs = {
|
|
808
|
+
"color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
|
|
809
|
+
}
|
|
1323
810
|
|
|
1324
811
|
|
|
1325
812
|
#
|
|
@@ -1328,7 +815,6 @@ class StatusSerializer(NautobotModelSerializer):
|
|
|
1328
815
|
|
|
1329
816
|
|
|
1330
817
|
class TagSerializer(NautobotModelSerializer):
|
|
1331
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:tag-detail")
|
|
1332
818
|
tagged_items = serializers.IntegerField(read_only=True)
|
|
1333
819
|
content_types = ContentTypeField(
|
|
1334
820
|
queryset=TaggableClassesQuery().as_queryset(),
|
|
@@ -1338,15 +824,10 @@ class TagSerializer(NautobotModelSerializer):
|
|
|
1338
824
|
|
|
1339
825
|
class Meta:
|
|
1340
826
|
model = Tag
|
|
1341
|
-
fields =
|
|
1342
|
-
|
|
1343
|
-
"
|
|
1344
|
-
|
|
1345
|
-
"color",
|
|
1346
|
-
"description",
|
|
1347
|
-
"tagged_items",
|
|
1348
|
-
"content_types",
|
|
1349
|
-
]
|
|
827
|
+
fields = "__all__"
|
|
828
|
+
extra_kwargs = {
|
|
829
|
+
"color": {"help_text": "RGB color in hexadecimal (e.g. 00ff00)"},
|
|
830
|
+
}
|
|
1350
831
|
|
|
1351
832
|
def validate(self, data):
|
|
1352
833
|
data = super().validate(data)
|
|
@@ -1368,7 +849,6 @@ class TagSerializer(NautobotModelSerializer):
|
|
|
1368
849
|
|
|
1369
850
|
|
|
1370
851
|
class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
1371
|
-
url = serializers.HyperlinkedIdentityField(view_name="extras-api:webhook-detail")
|
|
1372
852
|
content_types = ContentTypeField(
|
|
1373
853
|
queryset=ContentType.objects.filter(FeatureQuery("webhooks").get_query()).order_by("app_label", "model"),
|
|
1374
854
|
many=True,
|
|
@@ -1376,22 +856,7 @@ class WebhookSerializer(ValidatedModelSerializer, NotesSerializerMixin):
|
|
|
1376
856
|
|
|
1377
857
|
class Meta:
|
|
1378
858
|
model = Webhook
|
|
1379
|
-
fields =
|
|
1380
|
-
"url",
|
|
1381
|
-
"content_types",
|
|
1382
|
-
"name",
|
|
1383
|
-
"type_create",
|
|
1384
|
-
"type_update",
|
|
1385
|
-
"type_delete",
|
|
1386
|
-
"payload_url",
|
|
1387
|
-
"http_method",
|
|
1388
|
-
"http_content_type",
|
|
1389
|
-
"additional_headers",
|
|
1390
|
-
"body_template",
|
|
1391
|
-
"secret",
|
|
1392
|
-
"ssl_verification",
|
|
1393
|
-
"ca_file_path",
|
|
1394
|
-
]
|
|
859
|
+
fields = "__all__"
|
|
1395
860
|
|
|
1396
861
|
def validate(self, data):
|
|
1397
862
|
validated_data = super().validate(data)
|