nautobot 2.3.16__py3-none-any.whl → 2.4.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Potentially problematic release.
This version of nautobot might be problematic. Click here for more details.
- nautobot/__init__.py +15 -0
- nautobot/apps/__init__.py +1 -1
- nautobot/apps/api.py +8 -10
- nautobot/apps/change_logging.py +2 -2
- nautobot/apps/choices.py +4 -4
- nautobot/apps/config.py +32 -3
- nautobot/apps/events.py +19 -0
- nautobot/apps/exceptions.py +0 -2
- nautobot/apps/factory.py +2 -2
- nautobot/apps/filters.py +1 -1
- nautobot/apps/forms.py +20 -20
- nautobot/apps/graphql.py +2 -2
- nautobot/apps/jobs.py +8 -8
- nautobot/apps/models.py +19 -19
- nautobot/apps/tables.py +1 -1
- nautobot/apps/testing.py +10 -10
- nautobot/apps/ui.py +44 -9
- nautobot/apps/utils.py +7 -15
- nautobot/apps/views.py +8 -6
- nautobot/circuits/api/serializers.py +1 -0
- nautobot/circuits/api/views.py +4 -8
- nautobot/circuits/navigation.py +0 -57
- nautobot/circuits/templates/circuits/circuit_create.html +1 -7
- nautobot/circuits/templates/circuits/circuit_retrieve.html +0 -71
- nautobot/circuits/templates/circuits/inc/circuit_termination.html +6 -64
- nautobot/circuits/templates/circuits/inc/circuit_termination_cable_fragment.html +40 -0
- nautobot/circuits/templates/circuits/inc/circuit_termination_header_extra_content.html +26 -0
- nautobot/circuits/templates/circuits/provider_retrieve.html +0 -76
- nautobot/circuits/tests/integration/test_relationships.py +33 -24
- nautobot/circuits/tests/test_filters.py +4 -8
- nautobot/circuits/views.py +140 -23
- nautobot/cloud/api/views.py +6 -10
- nautobot/cloud/factory.py +4 -1
- nautobot/cloud/tests/test_filters.py +5 -4
- nautobot/cloud/views.py +0 -16
- nautobot/core/api/constants.py +11 -0
- nautobot/core/api/filter_backends.py +3 -9
- nautobot/core/api/metadata.py +28 -256
- nautobot/core/api/pagination.py +3 -2
- nautobot/core/api/renderers.py +3 -0
- nautobot/core/api/schema.py +13 -2
- nautobot/core/api/serializers.py +45 -259
- nautobot/core/api/urls.py +3 -4
- nautobot/core/api/utils.py +0 -62
- nautobot/core/api/views.py +99 -157
- nautobot/core/apps/__init__.py +22 -578
- nautobot/core/celery/__init__.py +13 -0
- nautobot/core/celery/schedulers.py +47 -2
- nautobot/core/choices.py +2 -2
- nautobot/core/cli/__init__.py +8 -0
- nautobot/core/constants.py +7 -0
- nautobot/core/events/__init__.py +116 -0
- nautobot/core/events/base.py +27 -0
- nautobot/core/events/exceptions.py +10 -0
- nautobot/core/events/redis_broker.py +48 -0
- nautobot/core/events/syslog_broker.py +19 -0
- nautobot/core/exceptions.py +0 -6
- nautobot/core/forms/__init__.py +19 -19
- nautobot/core/forms/fields.py +57 -9
- nautobot/core/forms/forms.py +33 -2
- nautobot/core/forms/utils.py +2 -1
- nautobot/core/graphql/schema.py +3 -1
- nautobot/core/jobs/__init__.py +24 -3
- nautobot/core/jobs/bulk_actions.py +248 -0
- nautobot/core/jobs/cleanup.py +1 -1
- nautobot/core/management/commands/generate_test_data.py +21 -0
- nautobot/core/middleware.py +16 -0
- nautobot/core/models/fields.py +11 -7
- nautobot/core/settings.py +68 -4
- nautobot/core/settings.yaml +99 -0
- nautobot/core/tables.py +10 -46
- nautobot/core/tasks.py +1 -1
- nautobot/core/templates/about.html +67 -0
- nautobot/core/templates/components/button/default.html +7 -0
- nautobot/core/templates/components/button/dropdown.html +20 -0
- nautobot/core/templates/components/layout/one_over_two.html +19 -0
- nautobot/core/templates/components/layout/two_over_one.html +19 -0
- nautobot/core/templates/components/panel/body_content_data_table.html +27 -0
- nautobot/core/templates/components/panel/body_content_objects_table.html +4 -0
- nautobot/core/templates/components/panel/body_content_tags.html +6 -0
- nautobot/core/templates/components/panel/body_content_text.html +12 -0
- nautobot/core/templates/components/panel/body_wrapper_generic.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_key_value_table.html +3 -0
- nautobot/core/templates/components/panel/body_wrapper_table.html +3 -0
- nautobot/core/templates/components/panel/footer_contacts_table.html +20 -0
- nautobot/core/templates/components/panel/footer_content_table.html +14 -0
- nautobot/core/templates/components/panel/grouping_toggle.html +14 -0
- nautobot/core/templates/components/panel/header_extra_content_table.html +3 -0
- nautobot/core/templates/components/panel/panel.html +16 -0
- nautobot/core/templates/components/panel/stats_panel_body.html +8 -0
- nautobot/core/templates/components/tab/content_wrapper.html +3 -0
- nautobot/core/templates/components/tab/label_wrapper.html +5 -0
- nautobot/core/templates/components/tab/label_wrapper_distinct_view.html +3 -0
- nautobot/core/templates/generic/object_retrieve.html +28 -17
- nautobot/core/templates/inc/computed_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/custom_fields/panel.html +2 -2
- nautobot/core/templates/inc/custom_fields/panel_data.html +4 -7
- nautobot/core/templates/inc/footer.html +1 -0
- nautobot/core/templates/inc/nav_menu.html +2 -1
- nautobot/core/templates/inc/relationships_panel.html +1 -1
- nautobot/core/templates/inc/tenancy_form_panel.html +9 -0
- nautobot/core/templates/inc/tenant_table_row.html +11 -0
- nautobot/core/templates/nautobot_config.py.j2 +13 -0
- nautobot/core/templates/panel_table.html +12 -0
- nautobot/core/templates/utilities/render_jinja2.html +117 -0
- nautobot/core/templates/utilities/templatetags/tag.html +1 -1
- nautobot/core/templates/utilities/theme_preview.html +7 -0
- nautobot/core/templatetags/helpers.py +104 -6
- nautobot/core/templatetags/ui_framework.py +40 -0
- nautobot/core/testing/__init__.py +8 -8
- nautobot/core/testing/api.py +187 -137
- nautobot/core/testing/context.py +18 -0
- nautobot/core/testing/filters.py +41 -35
- nautobot/core/testing/forms.py +2 -0
- nautobot/core/testing/views.py +65 -148
- nautobot/core/tests/integration/test_view_authentication.py +1 -1
- nautobot/core/tests/nautobot_config.py +198 -0
- nautobot/core/tests/runner.py +2 -2
- nautobot/core/tests/test_api.py +154 -176
- nautobot/core/tests/test_events.py +214 -0
- nautobot/core/tests/test_forms.py +1 -0
- nautobot/core/tests/test_jinja_filters.py +1 -0
- nautobot/core/tests/test_jobs.py +387 -14
- nautobot/core/tests/test_navigations.py +7 -241
- nautobot/core/tests/test_settings_schema.py +7 -0
- nautobot/core/tests/test_tables.py +100 -0
- nautobot/core/tests/test_templatetags_helpers.py +16 -0
- nautobot/core/tests/test_ui.py +150 -0
- nautobot/core/tests/test_utils.py +55 -18
- nautobot/core/tests/test_views.py +124 -5
- nautobot/core/ui/__init__.py +0 -0
- nautobot/core/ui/base.py +11 -0
- nautobot/core/ui/choices.py +44 -0
- nautobot/core/ui/homepage.py +167 -0
- nautobot/core/ui/nav.py +280 -0
- nautobot/core/ui/object_detail.py +1855 -0
- nautobot/core/ui/utils.py +36 -0
- nautobot/core/urls.py +6 -0
- nautobot/core/utils/config.py +30 -3
- nautobot/core/utils/lookup.py +12 -2
- nautobot/core/utils/querysets.py +64 -0
- nautobot/core/utils/requests.py +24 -9
- nautobot/core/views/__init__.py +48 -1
- nautobot/core/views/generic.py +37 -140
- nautobot/core/views/mixins.py +82 -32
- nautobot/core/views/paginator.py +8 -5
- nautobot/core/views/renderers.py +9 -9
- nautobot/core/views/utils.py +11 -0
- nautobot/core/wsgi.py +3 -3
- nautobot/dcim/api/serializers.py +34 -141
- nautobot/dcim/api/urls.py +5 -0
- nautobot/dcim/api/views.py +57 -110
- nautobot/dcim/apps.py +1 -0
- nautobot/dcim/choices.py +28 -0
- nautobot/dcim/factory.py +58 -0
- nautobot/dcim/filters/__init__.py +204 -2
- nautobot/dcim/forms.py +219 -9
- nautobot/dcim/migrations/0063_interfacevdcassignment_virtualdevicecontext_and_more.py +165 -0
- nautobot/dcim/migrations/0064_virtualdevicecontext_status_data_migration.py +28 -0
- nautobot/dcim/migrations/0065_controller_capabilities_and_more.py +29 -0
- nautobot/dcim/migrations/0066_controllermanageddevicegroup_radio_profiles_and_more.py +33 -0
- nautobot/dcim/migrations/0067_controllermanageddevicegroup_tenant.py +25 -0
- nautobot/dcim/models/__init__.py +5 -1
- nautobot/dcim/models/devices.py +180 -2
- nautobot/dcim/models/racks.py +2 -2
- nautobot/dcim/navigation.py +25 -224
- nautobot/dcim/signals.py +44 -0
- nautobot/dcim/tables/__init__.py +2 -0
- nautobot/dcim/tables/devices.py +103 -7
- nautobot/dcim/tables/racks.py +1 -1
- nautobot/dcim/templates/dcim/controller/base.html +10 -0
- nautobot/dcim/templates/dcim/controller_create.html +2 -7
- nautobot/dcim/templates/dcim/controller_retrieve.html +6 -10
- nautobot/dcim/templates/dcim/controller_wirelessnetworks.html +25 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_create.html +68 -0
- nautobot/dcim/templates/dcim/controllermanageddevicegroup_retrieve.html +51 -0
- nautobot/dcim/templates/dcim/device/base.html +6 -42
- nautobot/dcim/templates/dcim/device/wireless.html +73 -0
- nautobot/dcim/templates/dcim/device.html +4 -10
- nautobot/dcim/templates/dcim/device_edit.html +36 -37
- nautobot/dcim/templates/dcim/interface.html +1 -0
- nautobot/dcim/templates/dcim/interface_edit.html +1 -0
- nautobot/dcim/templates/dcim/location.html +1 -9
- nautobot/dcim/templates/dcim/location_edit.html +1 -7
- nautobot/dcim/templates/dcim/locationtype.html +0 -107
- nautobot/dcim/templates/dcim/locationtype_retrieve.html +8 -0
- nautobot/dcim/templates/dcim/rack.html +1 -9
- nautobot/dcim/templates/dcim/rack_edit.html +1 -7
- nautobot/dcim/templates/dcim/rackreservation.html +1 -9
- nautobot/dcim/templates/dcim/virtualdevicecontext_retrieve.html +68 -0
- nautobot/dcim/templates/dcim/virtualdevicecontext_update.html +28 -0
- nautobot/dcim/tests/integration/test_controller.py +62 -0
- nautobot/dcim/tests/integration/test_controller_managed_device_group.py +71 -0
- nautobot/dcim/tests/test_api.py +188 -64
- nautobot/dcim/tests/test_filters.py +171 -76
- nautobot/dcim/tests/test_jobs.py +118 -0
- nautobot/dcim/tests/test_models.py +157 -6
- nautobot/dcim/tests/test_signals.py +1 -0
- nautobot/dcim/tests/test_views.py +118 -88
- nautobot/dcim/urls.py +72 -27
- nautobot/dcim/utils.py +2 -2
- nautobot/dcim/views.py +356 -61
- nautobot/extras/api/serializers.py +39 -18
- nautobot/extras/api/urls.py +4 -0
- nautobot/extras/api/views.py +89 -31
- nautobot/extras/choices.py +13 -0
- nautobot/extras/constants.py +2 -1
- nautobot/extras/context_managers.py +23 -6
- nautobot/extras/datasources/git.py +4 -1
- nautobot/extras/factory.py +27 -0
- nautobot/extras/filters/__init__.py +66 -5
- nautobot/extras/forms/base.py +2 -2
- nautobot/extras/forms/forms.py +262 -59
- nautobot/extras/forms/mixins.py +2 -2
- nautobot/extras/graphql/types.py +25 -1
- nautobot/extras/jobs.py +109 -15
- nautobot/extras/management/__init__.py +1 -0
- nautobot/extras/management/commands/runjob.py +7 -79
- nautobot/extras/management/commands/runjob_with_job_result.py +46 -0
- nautobot/extras/management/utils.py +87 -0
- nautobot/extras/migrations/0117_create_job_queue_model.py +129 -0
- nautobot/extras/migrations/0118_task_queue_to_job_queue_migration.py +78 -0
- nautobot/extras/migrations/0119_remove_task_queues_from_job_and_queue_from_scheduled_job.py +28 -0
- nautobot/extras/migrations/0120_job_is_singleton_job_is_singleton_override.py +22 -0
- nautobot/extras/migrations/0121_alter_team_contacts.py +17 -0
- nautobot/extras/models/__init__.py +5 -1
- nautobot/extras/models/change_logging.py +7 -3
- nautobot/extras/models/contacts.py +1 -1
- nautobot/extras/models/groups.py +0 -2
- nautobot/extras/models/jobs.py +233 -33
- nautobot/extras/models/relationships.py +69 -1
- nautobot/extras/models/secrets.py +5 -0
- nautobot/extras/navigation.py +20 -262
- nautobot/extras/plugins/__init__.py +54 -19
- nautobot/extras/plugins/marketplace_manifest.yml +455 -0
- nautobot/extras/plugins/tables.py +16 -14
- nautobot/extras/plugins/urls.py +1 -0
- nautobot/extras/plugins/views.py +103 -60
- nautobot/extras/registry.py +1 -1
- nautobot/extras/secrets/__init__.py +2 -2
- nautobot/extras/signals.py +39 -1
- nautobot/extras/tables.py +37 -1
- nautobot/extras/templates/extras/dynamicgroup.html +1 -9
- nautobot/extras/templates/extras/externalintegration_retrieve.html +0 -47
- nautobot/extras/templates/extras/inc/tags_panel.html +1 -5
- nautobot/extras/templates/extras/job_bulk_edit.html +2 -1
- nautobot/extras/templates/extras/job_detail.html +52 -6
- nautobot/extras/templates/extras/job_edit.html +6 -2
- nautobot/extras/templates/extras/job_list.html +2 -7
- nautobot/extras/templates/extras/jobqueue_retrieve.html +36 -0
- nautobot/extras/templates/extras/marketplace.html +296 -0
- nautobot/extras/templates/extras/plugin_detail.html +32 -15
- nautobot/extras/templates/extras/plugins_list.html +35 -1
- nautobot/extras/templates/extras/plugins_tiles.html +90 -0
- nautobot/extras/templates/extras/role_retrieve.html +16 -0
- nautobot/extras/templates/extras/secret.html +0 -65
- nautobot/extras/templates/extras/secret_check.js +16 -0
- nautobot/extras/templates/extras/secret_create.html +114 -0
- nautobot/extras/templates/extras/secret_edit.html +1 -114
- nautobot/extras/templates/extras/secretsgroup_edit.html +1 -1
- nautobot/extras/templates/extras/templatetags/plugin_object_detail_tabs.html +2 -0
- nautobot/extras/templatetags/job_buttons.py +5 -4
- nautobot/extras/templatetags/plugins.py +69 -6
- nautobot/extras/test_jobs/singleton.py +16 -0
- nautobot/extras/tests/test_api.py +145 -43
- nautobot/extras/tests/test_context_managers.py +4 -1
- nautobot/extras/tests/test_filters.py +213 -529
- nautobot/extras/tests/test_job_variables.py +73 -152
- nautobot/extras/tests/test_jobs.py +181 -51
- nautobot/extras/tests/test_models.py +61 -6
- nautobot/extras/tests/test_plugins.py +62 -9
- nautobot/extras/tests/test_relationships.py +123 -9
- nautobot/extras/tests/test_utils.py +23 -2
- nautobot/extras/tests/test_views.py +146 -145
- nautobot/extras/tests/test_webhooks.py +2 -1
- nautobot/extras/urls.py +2 -20
- nautobot/extras/utils.py +119 -4
- nautobot/extras/views.py +168 -125
- nautobot/extras/webhooks.py +5 -2
- nautobot/ipam/api/serializers.py +10 -103
- nautobot/ipam/api/views.py +31 -49
- nautobot/ipam/factory.py +1 -1
- nautobot/ipam/filters.py +3 -2
- nautobot/ipam/models.py +10 -12
- nautobot/ipam/navigation.py +0 -90
- nautobot/ipam/tables.py +3 -1
- nautobot/ipam/templates/ipam/ipaddress.html +1 -9
- nautobot/ipam/templates/ipam/ipaddress_bulk_add.html +1 -7
- nautobot/ipam/templates/ipam/ipaddress_edit.html +1 -7
- nautobot/ipam/templates/ipam/prefix.html +1 -9
- nautobot/ipam/templates/ipam/prefix_edit.html +1 -7
- nautobot/ipam/templates/ipam/routetarget.html +0 -28
- nautobot/ipam/templates/ipam/vlan.html +1 -9
- nautobot/ipam/templates/ipam/vlan_edit.html +1 -7
- nautobot/ipam/templates/ipam/vrf.html +0 -47
- nautobot/ipam/templates/ipam/vrf_edit.html +1 -7
- nautobot/ipam/tests/test_api.py +7 -5
- nautobot/ipam/tests/test_filters.py +39 -119
- nautobot/ipam/tests/test_forms.py +0 -2
- nautobot/ipam/tests/test_models.py +56 -36
- nautobot/ipam/tests/test_views.py +3 -0
- nautobot/ipam/urls.py +3 -69
- nautobot/ipam/utils/__init__.py +16 -10
- nautobot/ipam/views.py +91 -162
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap-theme.min.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css +40 -2
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.css.map +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css +1 -1
- nautobot/project-static/bootstrap-3.4.1-dist/css/bootstrap.min.css.map +1 -1
- nautobot/project-static/css/base.css +38 -3
- nautobot/project-static/docs/404.html +461 -17
- nautobot/project-static/docs/apps/index.html +461 -17
- nautobot/project-static/docs/apps/nautobot-apps.html +462 -19
- nautobot/project-static/docs/assets/_mkdocstrings.css +25 -1
- nautobot/project-static/docs/assets/extra.css +5 -1
- nautobot/project-static/docs/code-reference/nautobot/apps/__init__.html +477 -23
- nautobot/project-static/docs/code-reference/nautobot/apps/admin.html +474 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/api.html +790 -289
- nautobot/project-static/docs/code-reference/nautobot/apps/change_logging.html +505 -31
- nautobot/project-static/docs/code-reference/nautobot/apps/choices.html +510 -34
- nautobot/project-static/docs/code-reference/nautobot/apps/config.html +471 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/constants.html +467 -18
- nautobot/project-static/docs/code-reference/nautobot/apps/datasources.html +497 -33
- nautobot/project-static/docs/code-reference/nautobot/apps/events.html +9883 -0
- nautobot/project-static/docs/code-reference/nautobot/apps/exceptions.html +523 -75
- nautobot/project-static/docs/code-reference/nautobot/apps/factory.html +546 -51
- nautobot/project-static/docs/code-reference/nautobot/apps/filters.html +670 -94
- nautobot/project-static/docs/code-reference/nautobot/apps/forms.html +1030 -177
- nautobot/project-static/docs/code-reference/nautobot/apps/graphql.html +524 -49
- nautobot/project-static/docs/code-reference/nautobot/apps/jobs.html +874 -188
- nautobot/project-static/docs/code-reference/nautobot/apps/models.html +955 -235
- nautobot/project-static/docs/code-reference/nautobot/apps/querysets.html +475 -21
- nautobot/project-static/docs/code-reference/nautobot/apps/secrets.html +486 -28
- nautobot/project-static/docs/code-reference/nautobot/apps/tables.html +661 -99
- nautobot/project-static/docs/code-reference/nautobot/apps/testing.html +947 -479
- nautobot/project-static/docs/code-reference/nautobot/apps/ui.html +6425 -1234
- nautobot/project-static/docs/code-reference/nautobot/apps/urls.html +474 -20
- nautobot/project-static/docs/code-reference/nautobot/apps/utils.html +877 -344
- nautobot/project-static/docs/code-reference/nautobot/apps/views.html +828 -171
- nautobot/project-static/docs/development/apps/api/configuration-view.html +461 -17
- nautobot/project-static/docs/development/apps/api/database-backend-config.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/django-admin.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/global-search.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/graphql.html +461 -17
- nautobot/project-static/docs/development/apps/api/models/index.html +461 -17
- nautobot/project-static/docs/development/apps/api/nautobot-app-config.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/custom-validators.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/filter-extensions.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/git-repository-content.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/index.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/jinja2-filters.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/jobs.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/populating-extensibility-features.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/secrets-providers.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/table-extensions.html +461 -17
- nautobot/project-static/docs/development/apps/api/platform-features/uniquely-identify-objects.html +461 -17
- nautobot/project-static/docs/development/apps/api/prometheus.html +461 -17
- nautobot/project-static/docs/development/apps/api/setup.html +465 -153
- nautobot/project-static/docs/development/apps/api/testing.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/banners.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/home-page.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/index.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/navigation.html +461 -17
- nautobot/project-static/docs/development/apps/api/ui-extensions/object-views.html +741 -128
- nautobot/project-static/docs/development/apps/api/views/base-template.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/core-view-overrides.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/django-generic-views.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/help-documentation.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/index.html +463 -18
- nautobot/project-static/docs/development/apps/api/views/nautobot-generic-views.html +465 -17
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewset.html +491 -17
- nautobot/project-static/docs/development/apps/api/views/nautobotuiviewsetrouter.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/notes.html +461 -17
- nautobot/project-static/docs/development/apps/api/views/rest-api.html +467 -19
- nautobot/project-static/docs/development/apps/api/views/urls.html +461 -17
- nautobot/project-static/docs/development/apps/index.html +461 -17
- nautobot/project-static/docs/development/apps/migration/code-updates.html +462 -50
- nautobot/project-static/docs/development/apps/migration/dependency-updates.html +462 -18
- nautobot/project-static/docs/development/apps/migration/from-v1.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/dcim.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/extras.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/global.html +461 -17
- nautobot/project-static/docs/development/apps/migration/model-updates/ipam.html +464 -20
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/best-practices.html +9261 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/custom-content.html +9375 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/index.html +9671 -0
- nautobot/project-static/docs/development/apps/migration/ui-component-framework/migration-steps.html +9559 -0
- nautobot/project-static/docs/development/apps/porting-from-netbox.html +464 -20
- nautobot/project-static/docs/development/core/application-registry.html +461 -17
- nautobot/project-static/docs/development/core/best-practices.html +461 -17
- nautobot/project-static/docs/development/core/bootstrap-ui.html +461 -17
- nautobot/project-static/docs/development/core/caching.html +461 -17
- nautobot/project-static/docs/development/core/controllers.html +463 -17
- nautobot/project-static/docs/development/core/docker-compose-advanced-use-cases.html +464 -20
- nautobot/project-static/docs/development/core/generic-views.html +461 -17
- nautobot/project-static/docs/development/core/getting-started.html +539 -127
- nautobot/project-static/docs/development/core/homepage.html +472 -28
- nautobot/project-static/docs/development/core/index.html +461 -17
- nautobot/project-static/docs/development/core/minikube-dev-environment-for-k8s-jobs.html +9754 -0
- nautobot/project-static/docs/development/core/model-checklist.html +471 -25
- nautobot/project-static/docs/development/core/model-features.html +461 -17
- nautobot/project-static/docs/development/core/natural-keys.html +461 -17
- nautobot/project-static/docs/development/core/navigation-menu.html +478 -24
- nautobot/project-static/docs/development/core/release-checklist.html +478 -46
- nautobot/project-static/docs/development/core/role-internals.html +461 -17
- nautobot/project-static/docs/development/core/settings.html +461 -17
- nautobot/project-static/docs/development/core/style-guide.html +464 -20
- nautobot/project-static/docs/development/core/templates.html +471 -20
- nautobot/project-static/docs/development/core/testing.html +461 -17
- nautobot/project-static/docs/development/core/ui-component-framework.html +11116 -0
- nautobot/project-static/docs/development/core/user-preferences.html +464 -20
- nautobot/project-static/docs/development/index.html +461 -17
- nautobot/project-static/docs/development/jobs/index.html +499 -19
- nautobot/project-static/docs/development/jobs/migration/from-v1.html +461 -17
- nautobot/project-static/docs/index.html +469 -36
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_edit_button.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_list_view.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_add.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_queue_config.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_completed.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_nav.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_result_pending.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_job_run_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_nautobot_login.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_job.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_run_scheduled_job_form.png +0 -0
- nautobot/project-static/docs/media/development/core/kubernetes/k8s_scheduled_job_result.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/basic-panel-layout.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/button-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/buttons-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/cluster-type-before-after-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/dropdown-button-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-1.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/grouped-key-value-table-panel-example-2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/object-fields-panel-example_2.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example-code.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/stats-panel-example.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/table-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/text-panels-family.png +0 -0
- nautobot/project-static/docs/media/development/core/ui-component-framework/ui-framework-example.png +0 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.drawio +73 -0
- nautobot/project-static/docs/media/models/virtual_device_context_overview.png +0 -0
- nautobot/project-static/docs/models/dcim/virtualdevicecontext.html +14 -0
- nautobot/project-static/docs/models/extras/jobqueue.html +14 -0
- nautobot/project-static/docs/models/wireless/radioprofile.html +14 -0
- nautobot/project-static/docs/models/wireless/supporteddatarate.html +14 -0
- nautobot/project-static/docs/models/wireless/wirelessnetwork.html +14 -0
- nautobot/project-static/docs/objects.inv +0 -0
- nautobot/project-static/docs/overview/application_stack.html +467 -21
- nautobot/project-static/docs/overview/design_philosophy.html +461 -17
- nautobot/project-static/docs/release-notes/index.html +483 -20
- nautobot/project-static/docs/release-notes/version-1.0.html +649 -206
- nautobot/project-static/docs/release-notes/version-1.1.html +646 -203
- nautobot/project-static/docs/release-notes/version-1.2.html +721 -278
- nautobot/project-static/docs/release-notes/version-1.3.html +747 -304
- nautobot/project-static/docs/release-notes/version-1.4.html +832 -390
- nautobot/project-static/docs/release-notes/version-1.5.html +1020 -579
- nautobot/project-static/docs/release-notes/version-1.6.html +940 -516
- nautobot/project-static/docs/release-notes/version-2.0.html +943 -502
- nautobot/project-static/docs/release-notes/version-2.1.html +778 -337
- nautobot/project-static/docs/release-notes/version-2.2.html +771 -330
- nautobot/project-static/docs/release-notes/version-2.3.html +914 -471
- nautobot/project-static/docs/release-notes/version-2.4.html +10323 -0
- nautobot/project-static/docs/search/search_index.json +1 -1
- nautobot/project-static/docs/sitemap.xml +342 -270
- nautobot/project-static/docs/sitemap.xml.gz +0 -0
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/ldap.html +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/remote.html +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/authentication/sso.html +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/index.html +473 -30
- nautobot/project-static/docs/user-guide/administration/configuration/redis.html +461 -17
- nautobot/project-static/docs/user-guide/administration/configuration/settings.html +842 -155
- nautobot/project-static/docs/user-guide/administration/configuration/time-zones.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/celery-queues.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/docker.html +474 -27
- nautobot/project-static/docs/user-guide/administration/guides/health-checks.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/permissions.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/prometheus-metrics.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/replicating-nautobot.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/request-profiling.html +461 -17
- nautobot/project-static/docs/user-guide/administration/guides/s3-django-storage.html +463 -19
- nautobot/project-static/docs/user-guide/administration/guides/selinux-troubleshooting.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/app-install.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/external-authentication.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/http-server.html +481 -21
- nautobot/project-static/docs/user-guide/administration/installation/index.html +466 -18
- nautobot/project-static/docs/user-guide/administration/installation/install_system.html +462 -18
- nautobot/project-static/docs/user-guide/administration/installation/nautobot.html +461 -17
- nautobot/project-static/docs/user-guide/administration/installation/services.html +461 -17
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-netbox.html +461 -17
- nautobot/project-static/docs/user-guide/administration/migration/migrating-from-postgresql.html +482 -39
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-server.html +475 -64
- nautobot/project-static/docs/user-guide/administration/tools/nautobot-shell.html +475 -64
- nautobot/project-static/docs/user-guide/administration/upgrading/database-backup.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/after-you-upgrade.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/before-you-upgrade.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/for-developers.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/index.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/ipam/whats-changed.html +464 -21
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/region-and-site-data-migration-guide.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/tables/v2-code-nautobot-app-location.yaml +0 -16
- nautobot/project-static/docs/user-guide/administration/upgrading/from-v1/upgrading-from-nautobot-v1.html +461 -17
- nautobot/project-static/docs/user-guide/administration/upgrading/upgrading.html +467 -19
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuit.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittermination.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/circuittype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/provider.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/circuits/providernetwork.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloud.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudaccount.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetwork.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudnetworkprefixassignment.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudresourcetype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservice.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/cloud/cloudservicenetworkassignment.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/cable.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/consoleserverporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controller.html +497 -18
- nautobot/project-static/docs/user-guide/core-data-model/dcim/controllermanageddevicegroup.html +487 -20
- nautobot/project-static/docs/user-guide/core-data-model/dcim/device.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebay.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicebaytemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicefamily.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/deviceredundancygroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/devicetype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/frontporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interface.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfaceredundancygroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/interfacetemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/inventoryitem.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/location.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/locationtype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/manufacturer.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/module.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebay.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/modulebaytemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/moduletype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/platform.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerfeed.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlet.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/poweroutlettemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerpanel.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/powerporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rack.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackgroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rackreservation.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearport.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/rearporttemplate.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareimagefile.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/softwareversion.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualchassis.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/dcim/virtualdevicecontext.html +9375 -0
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontext.html +468 -28
- nautobot/project-static/docs/user-guide/core-data-model/extras/configcontextschema.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/extras/contact.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/extras/team.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/ipaddress.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/namespace.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/prefix.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/rir.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/routetarget.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/service.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlan.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vlangroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/ipam/vrf.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/overview/introduction.html +464 -20
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenant.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/tenancy/tenantgroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/cluster.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustergroup.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/clustertype.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/virtualmachine.html +461 -17
- nautobot/project-static/docs/user-guide/core-data-model/virtualization/vminterface.html +464 -20
- nautobot/project-static/docs/user-guide/core-data-model/wireless/index.html +9313 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/radioprofile.html +9217 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/supporteddatarate.html +9211 -0
- nautobot/project-static/docs/user-guide/core-data-model/wireless/wirelessnetwork.html +9277 -0
- nautobot/project-static/docs/user-guide/feature-guides/contacts-and-teams.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/custom-fields.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-devices.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/creating-location-types-and-locations.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/index.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/interfaces.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/ipam.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/platforms.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/search-bar.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/tenants.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/getting-started/vlans-and-vlan-groups.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/git-data-source.html +466 -20
- nautobot/project-static/docs/user-guide/feature-guides/graphql.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/central-mode.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/device-group-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/radio-profile-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/supported-data-rate-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-1.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-controller-create-2.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-add.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/images/wireless/wireless-network-create.png +0 -0
- nautobot/project-static/docs/user-guide/feature-guides/ip-address-merge-tool.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/relationships.html +461 -17
- nautobot/project-static/docs/user-guide/feature-guides/software-image-files-and-versions.html +464 -20
- nautobot/project-static/docs/user-guide/feature-guides/wireless-networks-and-controllers.html +9444 -0
- nautobot/project-static/docs/user-guide/index.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/change-logging.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/computedfield.html +465 -21
- nautobot/project-static/docs/user-guide/platform-functionality/customfield.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/customlink.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/dynamicgroup.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/events.html +9617 -0
- nautobot/project-static/docs/user-guide/platform-functionality/exporttemplate.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/externalintegration.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/gitrepository.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/graphql.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/graphqlquery.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/imageattachment.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/index.html +470 -21
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/job-scheduling-and-approvals.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobbutton.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobhook.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/jobqueue.html +9224 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/kubernetes-job-support.html +9722 -0
- nautobot/project-static/docs/user-guide/platform-functionality/jobs/models.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/napalm.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/note.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/objectmetadata.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/relationship.html +465 -21
- nautobot/project-static/docs/user-guide/platform-functionality/rendering-jinja-templates.html +9292 -0
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/authentication.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/filtering.html +509 -38
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/overview.html +492 -21
- nautobot/project-static/docs/user-guide/platform-functionality/rest-api/ui-related-endpoints.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/role.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/savedview.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/secret.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/staticgroupassociation.html +464 -20
- nautobot/project-static/docs/user-guide/platform-functionality/status.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/tag.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/template-filters.html +529 -54
- nautobot/project-static/docs/user-guide/platform-functionality/users/objectpermission.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/users/token.html +461 -17
- nautobot/project-static/docs/user-guide/platform-functionality/webhook.html +461 -17
- nautobot/project-static/img/jinja_logo.svg +97 -0
- nautobot/project-static/js/forms.js +6 -1
- nautobot/project-static/js/nav_menu.js +2 -1
- nautobot/tenancy/api/serializers.py +0 -2
- nautobot/tenancy/api/views.py +9 -13
- nautobot/tenancy/factory.py +1 -1
- nautobot/tenancy/navigation.py +0 -29
- nautobot/tenancy/templates/tenancy/tenant.html +4 -91
- nautobot/tenancy/tests/test_filters.py +29 -134
- nautobot/tenancy/views.py +35 -24
- nautobot/users/admin.py +2 -0
- nautobot/users/api/views.py +2 -2
- nautobot/users/forms.py +19 -0
- nautobot/users/templates/users/preferences.html +22 -0
- nautobot/users/tests/test_filters.py +1 -19
- nautobot/users/tests/test_views.py +57 -0
- nautobot/users/utils.py +8 -0
- nautobot/users/views.py +48 -11
- nautobot/virtualization/api/views.py +5 -24
- nautobot/virtualization/filters.py +1 -2
- nautobot/virtualization/models.py +1 -1
- nautobot/virtualization/navigation.py +0 -48
- nautobot/virtualization/tables.py +2 -2
- nautobot/virtualization/templates/virtualization/cluster_edit.html +1 -7
- nautobot/virtualization/templates/virtualization/clustertype.html +0 -39
- nautobot/virtualization/templates/virtualization/virtualmachine.html +1 -9
- nautobot/virtualization/templates/virtualization/virtualmachine_edit.html +2 -8
- nautobot/virtualization/tests/test_filters.py +57 -166
- nautobot/virtualization/views.py +18 -15
- nautobot/wireless/__init__.py +0 -0
- nautobot/wireless/api/__init__.py +0 -0
- nautobot/wireless/api/serializers.py +44 -0
- nautobot/wireless/api/urls.py +20 -0
- nautobot/wireless/api/views.py +34 -0
- nautobot/wireless/apps.py +8 -0
- nautobot/wireless/choices.py +345 -0
- nautobot/wireless/factory.py +138 -0
- nautobot/wireless/filters.py +167 -0
- nautobot/wireless/forms.py +283 -0
- nautobot/wireless/homepage.py +19 -0
- nautobot/wireless/migrations/0001_initial.py +223 -0
- nautobot/wireless/migrations/__init__.py +0 -0
- nautobot/wireless/models.py +207 -0
- nautobot/wireless/navigation.py +105 -0
- nautobot/wireless/tables.py +244 -0
- nautobot/wireless/templates/wireless/radioprofile_retrieve.html +81 -0
- nautobot/wireless/templates/wireless/supporteddatarate_retrieve.html +26 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_create.html +88 -0
- nautobot/wireless/templates/wireless/wirelessnetwork_retrieve.html +56 -0
- nautobot/wireless/tests/__init__.py +0 -0
- nautobot/wireless/tests/integration/__init__.py +0 -0
- nautobot/wireless/tests/integration/test_radio_profile.py +42 -0
- nautobot/wireless/tests/test_api.py +247 -0
- nautobot/wireless/tests/test_filters.py +82 -0
- nautobot/wireless/tests/test_models.py +22 -0
- nautobot/wireless/tests/test_views.py +378 -0
- nautobot/wireless/urls.py +13 -0
- nautobot/wireless/views.py +119 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/METADATA +9 -12
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/RECORD +720 -549
- nautobot/core/utils/navigation.py +0 -54
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/LICENSE.txt +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/NOTICE +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/WHEEL +0 -0
- {nautobot-2.3.16.dist-info → nautobot-2.4.0.dist-info}/entry_points.txt +0 -0
|
@@ -1,19 +1,13 @@
|
|
|
1
1
|
from datetime import datetime
|
|
2
2
|
import uuid
|
|
3
|
+
from zoneinfo import ZoneInfo
|
|
3
4
|
|
|
4
5
|
from django.contrib.auth import get_user_model
|
|
5
6
|
from django.contrib.contenttypes.models import ContentType
|
|
6
7
|
from django.core.files.uploadedfile import SimpleUploadedFile
|
|
7
|
-
from django.db.models import Q
|
|
8
8
|
from django.test import override_settings, RequestFactory
|
|
9
9
|
from django.utils.timezone import now
|
|
10
10
|
|
|
11
|
-
try:
|
|
12
|
-
from zoneinfo import ZoneInfo
|
|
13
|
-
except ImportError: # Python 3.8
|
|
14
|
-
from backports.zoneinfo import ZoneInfo
|
|
15
|
-
|
|
16
|
-
from nautobot.core.choices import ColorChoices
|
|
17
11
|
from nautobot.core.testing import FilterTestCases
|
|
18
12
|
from nautobot.dcim.filters import DeviceFilterSet
|
|
19
13
|
from nautobot.dcim.models import (
|
|
@@ -30,6 +24,7 @@ from nautobot.extras.choices import (
|
|
|
30
24
|
CustomFieldTypeChoices,
|
|
31
25
|
DynamicGroupTypeChoices,
|
|
32
26
|
JobExecutionType,
|
|
27
|
+
JobQueueTypeChoices,
|
|
33
28
|
JobResultStatusChoices,
|
|
34
29
|
MetadataTypeDataTypeChoices,
|
|
35
30
|
ObjectChangeActionChoices,
|
|
@@ -55,6 +50,8 @@ from nautobot.extras.filters import (
|
|
|
55
50
|
JobFilterSet,
|
|
56
51
|
JobHookFilterSet,
|
|
57
52
|
JobLogEntryFilterSet,
|
|
53
|
+
JobQueueAssignmentFilterSet,
|
|
54
|
+
JobQueueFilterSet,
|
|
58
55
|
JobResultFilterSet,
|
|
59
56
|
MetadataChoiceFilterSet,
|
|
60
57
|
MetadataTypeFilterSet,
|
|
@@ -92,6 +89,8 @@ from nautobot.extras.models import (
|
|
|
92
89
|
JobButton,
|
|
93
90
|
JobHook,
|
|
94
91
|
JobLogEntry,
|
|
92
|
+
JobQueue,
|
|
93
|
+
JobQueueAssignment,
|
|
95
94
|
JobResult,
|
|
96
95
|
MetadataChoice,
|
|
97
96
|
MetadataType,
|
|
@@ -116,7 +115,7 @@ from nautobot.ipam.filters import VLANFilterSet
|
|
|
116
115
|
from nautobot.ipam.models import IPAddress, Namespace, Prefix, VLAN, VLANGroup
|
|
117
116
|
from nautobot.tenancy.models import Tenant, TenantGroup
|
|
118
117
|
from nautobot.users.factory import UserFactory
|
|
119
|
-
from nautobot.virtualization.models import Cluster, ClusterGroup, ClusterType
|
|
118
|
+
from nautobot.virtualization.models import Cluster, ClusterGroup, ClusterType
|
|
120
119
|
|
|
121
120
|
# Use the proper swappable User model
|
|
122
121
|
User = get_user_model()
|
|
@@ -125,6 +124,12 @@ User = get_user_model()
|
|
|
125
124
|
class ComputedFieldTestCase(FilterTestCases.FilterTestCase):
|
|
126
125
|
queryset = ComputedField.objects.all()
|
|
127
126
|
filterset = ComputedFieldFilterSet
|
|
127
|
+
generic_filter_tests = (
|
|
128
|
+
("fallback_value",),
|
|
129
|
+
("key",),
|
|
130
|
+
("template",),
|
|
131
|
+
("weight",),
|
|
132
|
+
)
|
|
128
133
|
|
|
129
134
|
@classmethod
|
|
130
135
|
def setUpTestData(cls):
|
|
@@ -160,50 +165,38 @@ class ComputedFieldTestCase(FilterTestCases.FilterTestCase):
|
|
|
160
165
|
label="Device Computed Field",
|
|
161
166
|
template="Hello, world.",
|
|
162
167
|
fallback_value="This template has errored",
|
|
163
|
-
weight=
|
|
168
|
+
weight=300,
|
|
164
169
|
)
|
|
165
170
|
|
|
166
|
-
def test_key(self):
|
|
167
|
-
params = {"key": ["device_computed_field", "worse_computed_field"]}
|
|
168
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
169
|
-
|
|
170
171
|
def test_content_type(self):
|
|
171
172
|
params = {"content_type": "dcim.location"}
|
|
172
173
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
173
174
|
|
|
174
|
-
def test_template(self):
|
|
175
|
-
params = {"template": ["Hello, world."]}
|
|
176
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
177
|
-
|
|
178
|
-
def test_fallback_value(self):
|
|
179
|
-
params = {"fallback_value": ["This template has errored"]}
|
|
180
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
181
|
-
|
|
182
|
-
def test_weight(self):
|
|
183
|
-
params = {"weight": [100]}
|
|
184
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
185
|
-
|
|
186
|
-
def test_search(self):
|
|
187
|
-
# label
|
|
188
|
-
params = {"q": "Field One"}
|
|
189
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
190
|
-
# content_type__app_label
|
|
191
|
-
params = {"q": "dcim"}
|
|
192
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
|
193
|
-
# content_type__model
|
|
194
|
-
params = {"q": "location"}
|
|
195
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
196
|
-
# template
|
|
197
|
-
params = {"q": "hello"}
|
|
198
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
199
|
-
# fallback_value
|
|
200
|
-
params = {"q": "has errored"}
|
|
201
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
202
|
-
|
|
203
175
|
|
|
204
176
|
class ConfigContextTestCase(FilterTestCases.FilterTestCase):
|
|
205
177
|
queryset = ConfigContext.objects.all()
|
|
206
178
|
filterset = ConfigContextFilterSet
|
|
179
|
+
generic_filter_tests = (
|
|
180
|
+
("cluster_id", "clusters__id"),
|
|
181
|
+
("cluster_group", "cluster_groups__id"),
|
|
182
|
+
("cluster_group", "cluster_groups__name"),
|
|
183
|
+
("cluster_group_id", "cluster_groups__id"),
|
|
184
|
+
("device_type", "device_types__id"),
|
|
185
|
+
("device_type", "device_types__model"),
|
|
186
|
+
("device_type_id", "device_types__id"),
|
|
187
|
+
("name",),
|
|
188
|
+
("platform", "platforms__id"),
|
|
189
|
+
("platform", "platforms__name"),
|
|
190
|
+
("platform_id", "platforms__id"),
|
|
191
|
+
("role", "roles__id"),
|
|
192
|
+
("role", "roles__name"),
|
|
193
|
+
("tenant", "tenants__id"),
|
|
194
|
+
("tenant", "tenants__name"),
|
|
195
|
+
("tenant_id", "tenants__id"),
|
|
196
|
+
("tenant_group", "tenant_groups__id"),
|
|
197
|
+
("tenant_group", "tenant_groups__name"),
|
|
198
|
+
("tenant_group_id", "tenant_groups__id"),
|
|
199
|
+
)
|
|
207
200
|
|
|
208
201
|
@classmethod
|
|
209
202
|
def setUpTestData(cls):
|
|
@@ -260,10 +253,6 @@ class ConfigContextTestCase(FilterTestCases.FilterTestCase):
|
|
|
260
253
|
c.tenants.set([cls.tenants[i]])
|
|
261
254
|
c.locations.set([cls.locations[i]])
|
|
262
255
|
|
|
263
|
-
def test_name(self):
|
|
264
|
-
params = {"name": ["Config Context 1", "Config Context 2"]}
|
|
265
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
266
|
-
|
|
267
256
|
def test_is_active(self):
|
|
268
257
|
params = {"is_active": True}
|
|
269
258
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
@@ -280,82 +269,6 @@ class ConfigContextTestCase(FilterTestCases.FilterTestCase):
|
|
|
280
269
|
self.filterset(params, self.queryset).qs, self.queryset.filter(locations__name__in=params["location"])
|
|
281
270
|
)
|
|
282
271
|
|
|
283
|
-
def test_role(self):
|
|
284
|
-
device_role = Role.objects.get_for_model(Device).first()
|
|
285
|
-
vm_role = Role.objects.get_for_model(VirtualMachine).first()
|
|
286
|
-
params = {"role": [device_role.pk, vm_role.name]}
|
|
287
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
288
|
-
self.filterset(params, self.queryset).qs,
|
|
289
|
-
self.queryset.filter(roles__in=[vm_role, device_role]).distinct(),
|
|
290
|
-
)
|
|
291
|
-
|
|
292
|
-
def test_type(self):
|
|
293
|
-
device_types = list(self.device_types[:2])
|
|
294
|
-
filter_params = [
|
|
295
|
-
{"device_type_id": [device_types[0].pk, device_types[1].pk]},
|
|
296
|
-
{"device_type": [device_types[0].pk, device_types[1].model]},
|
|
297
|
-
]
|
|
298
|
-
for params in filter_params:
|
|
299
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
300
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(device_types__in=device_types).distinct()
|
|
301
|
-
)
|
|
302
|
-
|
|
303
|
-
def test_platform(self):
|
|
304
|
-
platforms = list(self.platforms[:2])
|
|
305
|
-
filter_params = [
|
|
306
|
-
{"platform_id": [platforms[0].pk, platforms[1].pk]},
|
|
307
|
-
{"platform": [platforms[0].pk, platforms[1].name]},
|
|
308
|
-
]
|
|
309
|
-
for params in filter_params:
|
|
310
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
311
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(platforms__in=platforms).distinct()
|
|
312
|
-
)
|
|
313
|
-
|
|
314
|
-
def test_cluster_group(self):
|
|
315
|
-
cluster_groups = list(ClusterGroup.objects.all()[:2])
|
|
316
|
-
filter_params = [
|
|
317
|
-
{"cluster_group_id": [cluster_groups[0].pk, cluster_groups[1].pk]},
|
|
318
|
-
{"cluster_group": [cluster_groups[0].pk, cluster_groups[1].name]},
|
|
319
|
-
]
|
|
320
|
-
for params in filter_params:
|
|
321
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
322
|
-
self.filterset(params, self.queryset).qs,
|
|
323
|
-
self.queryset.filter(cluster_groups__in=cluster_groups).distinct(),
|
|
324
|
-
)
|
|
325
|
-
|
|
326
|
-
def test_cluster(self):
|
|
327
|
-
clusters = Cluster.objects.all()[:2]
|
|
328
|
-
params = {"cluster_id": [clusters[0].pk, clusters[1].pk]}
|
|
329
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
330
|
-
|
|
331
|
-
def test_tenant_group(self):
|
|
332
|
-
tenant_groups = list(self.tenant_groups[:2])
|
|
333
|
-
filter_params = [
|
|
334
|
-
{"tenant_group_id": [tenant_groups[0].pk, tenant_groups[1].pk]},
|
|
335
|
-
{"tenant_group": [tenant_groups[0].name, tenant_groups[1].pk]},
|
|
336
|
-
]
|
|
337
|
-
for params in filter_params:
|
|
338
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
339
|
-
self.filterset(params, self.queryset).qs,
|
|
340
|
-
self.queryset.filter(tenant_groups__in=tenant_groups).distinct(),
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
def test_tenant(self):
|
|
344
|
-
tenants = list(self.tenants[:2])
|
|
345
|
-
filter_params = [
|
|
346
|
-
{"tenant_id": [tenants[0].pk, tenants[1].pk]},
|
|
347
|
-
{"tenant": [tenants[0].name, tenants[1].pk]},
|
|
348
|
-
]
|
|
349
|
-
for params in filter_params:
|
|
350
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
351
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(tenants__in=tenants).distinct()
|
|
352
|
-
)
|
|
353
|
-
|
|
354
|
-
def test_search(self):
|
|
355
|
-
value = self.queryset.values_list("pk", flat=True)[0]
|
|
356
|
-
params = {"q": value}
|
|
357
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
358
|
-
|
|
359
272
|
@override_settings(CONFIG_CONTEXT_DYNAMIC_GROUPS_ENABLED=True)
|
|
360
273
|
def test_with_dynamic_groups_enabled(self):
|
|
361
274
|
"""Asserts that `ConfigContextFilterSet.dynamic_group` is present when feature flag is enabled."""
|
|
@@ -372,6 +285,10 @@ class ConfigContextTestCase(FilterTestCases.FilterTestCase):
|
|
|
372
285
|
class ContentTypeFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
373
286
|
queryset = ContentType.objects.order_by("app_label", "model")
|
|
374
287
|
filterset = ContentTypeFilterSet
|
|
288
|
+
generic_filter_tests = (
|
|
289
|
+
("app_label",),
|
|
290
|
+
("model",),
|
|
291
|
+
)
|
|
375
292
|
user_permissions = [
|
|
376
293
|
"dcim.add_location",
|
|
377
294
|
"extras.change_status",
|
|
@@ -383,16 +300,6 @@ class ContentTypeFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
383
300
|
super().setUp()
|
|
384
301
|
self.factory = RequestFactory(SERVER_NAME="nautobot.example.com")
|
|
385
302
|
|
|
386
|
-
def test_app_label(self):
|
|
387
|
-
params = {"app_label": ["dcim"]}
|
|
388
|
-
self.assertQuerysetEqual(self.filterset(params, self.queryset).qs, self.queryset.filter(app_label="dcim"))
|
|
389
|
-
|
|
390
|
-
def test_model(self):
|
|
391
|
-
params = {"model": ["device", "virtualmachine"]}
|
|
392
|
-
self.assertQuerysetEqual(
|
|
393
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(model__in=["device", "virtualmachine"])
|
|
394
|
-
)
|
|
395
|
-
|
|
396
303
|
def test_can_add(self):
|
|
397
304
|
# With no request user, can't add anything
|
|
398
305
|
params = {"can_add": True}
|
|
@@ -473,13 +380,6 @@ class ContentTypeFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
473
380
|
self.queryset.exclude(app_label="tenancy", model="tenant"),
|
|
474
381
|
)
|
|
475
382
|
|
|
476
|
-
def test_search(self):
|
|
477
|
-
params = {"q": "circ"}
|
|
478
|
-
self.assertQuerysetEqual(
|
|
479
|
-
self.filterset(params, self.queryset).qs,
|
|
480
|
-
self.queryset.filter(Q(app_label__icontains="circ") | Q(model__icontains="circ")),
|
|
481
|
-
)
|
|
482
|
-
|
|
483
383
|
|
|
484
384
|
class ContactAndTeamFilterSetTestCaseMixin:
|
|
485
385
|
"""Mixin class to test common filters to both Contact and Team filter sets."""
|
|
@@ -647,33 +547,17 @@ class ContactAssociationFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
647
547
|
)
|
|
648
548
|
|
|
649
549
|
|
|
650
|
-
class CustomFieldChoiceFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
651
|
-
queryset = CustomFieldChoice.objects.all()
|
|
652
|
-
filterset = CustomFieldChoiceFilterSet
|
|
653
|
-
|
|
654
|
-
generic_filter_tests = (
|
|
655
|
-
["value"],
|
|
656
|
-
["custom_field", "custom_field__key"],
|
|
657
|
-
["weight"],
|
|
658
|
-
)
|
|
659
|
-
|
|
660
|
-
@classmethod
|
|
661
|
-
def setUpTestData(cls):
|
|
662
|
-
obj_type = ContentType.objects.get_for_model(Device)
|
|
663
|
-
cfs = [
|
|
664
|
-
CustomField.objects.create(label=f"Custom Field {num}", type=CustomFieldTypeChoices.TYPE_TEXT)
|
|
665
|
-
for num in range(3)
|
|
666
|
-
]
|
|
667
|
-
for cf in cfs:
|
|
668
|
-
cf.content_types.set([obj_type])
|
|
669
|
-
|
|
670
|
-
for i, val in enumerate(["Value 1", "Value 2", "Value 3"]):
|
|
671
|
-
CustomFieldChoice.objects.create(custom_field=cfs[i], value=val, weight=100 * i)
|
|
672
|
-
|
|
673
|
-
|
|
674
550
|
class CustomLinkTestCase(FilterTestCases.FilterTestCase):
|
|
675
551
|
queryset = CustomLink.objects.all()
|
|
676
552
|
filterset = CustomLinkFilterSet
|
|
553
|
+
generic_filter_tests = (
|
|
554
|
+
# ("button_class",), # TODO
|
|
555
|
+
# ("group_name",), # TODO
|
|
556
|
+
("name",),
|
|
557
|
+
("target_url",),
|
|
558
|
+
("text",),
|
|
559
|
+
("weight",),
|
|
560
|
+
)
|
|
677
561
|
|
|
678
562
|
@classmethod
|
|
679
563
|
def setUpTestData(cls):
|
|
@@ -693,7 +577,7 @@ class CustomLinkTestCase(FilterTestCases.FilterTestCase):
|
|
|
693
577
|
name="customlink-2",
|
|
694
578
|
text="customlink text 2",
|
|
695
579
|
target_url="http://customlink2.com",
|
|
696
|
-
weight=
|
|
580
|
+
weight=200,
|
|
697
581
|
button_class="default",
|
|
698
582
|
new_window=False,
|
|
699
583
|
)
|
|
@@ -702,31 +586,21 @@ class CustomLinkTestCase(FilterTestCases.FilterTestCase):
|
|
|
702
586
|
name="customlink-3",
|
|
703
587
|
text="customlink text 3",
|
|
704
588
|
target_url="http://customlink3.com",
|
|
705
|
-
weight=
|
|
589
|
+
weight=300,
|
|
706
590
|
button_class="default",
|
|
707
591
|
new_window=False,
|
|
708
592
|
)
|
|
709
593
|
|
|
710
|
-
def test_name(self):
|
|
711
|
-
params = {"name": ["customlink-1"]}
|
|
712
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
713
|
-
|
|
714
|
-
def test_target_url(self):
|
|
715
|
-
params = {"target_url": ["http://customlink1.com"]}
|
|
716
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
717
|
-
|
|
718
|
-
def test_weight(self):
|
|
719
|
-
params = {"weight": [100]}
|
|
720
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
721
|
-
|
|
722
|
-
def test_search(self):
|
|
723
|
-
params = {"q": "customlink"}
|
|
724
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
725
|
-
|
|
726
594
|
|
|
727
595
|
class CustomFieldChoiceTestCase(FilterTestCases.FilterTestCase):
|
|
728
596
|
queryset = CustomFieldChoice.objects.all()
|
|
729
597
|
filterset = CustomFieldChoiceFilterSet
|
|
598
|
+
generic_filter_tests = (
|
|
599
|
+
("custom_field", "custom_field__key"),
|
|
600
|
+
("custom_field", "custom_field__id"),
|
|
601
|
+
("value",),
|
|
602
|
+
("weight",),
|
|
603
|
+
)
|
|
730
604
|
|
|
731
605
|
@classmethod
|
|
732
606
|
def setUpTestData(cls):
|
|
@@ -739,23 +613,14 @@ class CustomFieldChoiceTestCase(FilterTestCases.FilterTestCase):
|
|
|
739
613
|
for field in fields:
|
|
740
614
|
field.content_types.set([content_type])
|
|
741
615
|
|
|
742
|
-
for
|
|
743
|
-
CustomFieldChoice.objects.create(custom_field=fields[
|
|
744
|
-
|
|
745
|
-
def test_field(self):
|
|
746
|
-
fields = list(self.fields[:2])
|
|
747
|
-
filter_params = [
|
|
748
|
-
{"custom_field": [fields[0].key, fields[1].pk]},
|
|
749
|
-
]
|
|
750
|
-
for params in filter_params:
|
|
751
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
752
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(custom_field__in=fields).distinct()
|
|
753
|
-
)
|
|
616
|
+
for i, val in enumerate(["Value 1", "Value 2", "Value 3"]):
|
|
617
|
+
CustomFieldChoice.objects.create(custom_field=fields[i], value=val, weight=100 * i)
|
|
754
618
|
|
|
755
619
|
|
|
756
620
|
class ExportTemplateTestCase(FilterTestCases.FilterTestCase):
|
|
757
621
|
queryset = ExportTemplate.objects.all()
|
|
758
622
|
filterset = ExportTemplateFilterSet
|
|
623
|
+
generic_filter_tests = (("name",),)
|
|
759
624
|
|
|
760
625
|
@classmethod
|
|
761
626
|
def setUpTestData(cls):
|
|
@@ -782,18 +647,10 @@ class ExportTemplateTestCase(FilterTestCases.FilterTestCase):
|
|
|
782
647
|
owner=repo,
|
|
783
648
|
)
|
|
784
649
|
|
|
785
|
-
def test_name(self):
|
|
786
|
-
params = {"name": ["Export Template 1", "Export Template 2"]}
|
|
787
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
788
|
-
|
|
789
650
|
def test_content_type(self):
|
|
790
651
|
params = {"content_type": ContentType.objects.get(model="location").pk}
|
|
791
652
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
792
653
|
|
|
793
|
-
def test_search(self):
|
|
794
|
-
params = {"q": "export"}
|
|
795
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
796
|
-
|
|
797
654
|
|
|
798
655
|
class FileProxyTestCase(FilterTestCases.FilterTestCase):
|
|
799
656
|
queryset = FileProxy.objects.all()
|
|
@@ -842,34 +699,6 @@ class ExternalIntegrationTestCase(FilterTestCases.FilterTestCase):
|
|
|
842
699
|
for ei in external_integrations:
|
|
843
700
|
ei.validated_save()
|
|
844
701
|
|
|
845
|
-
def test_search(self):
|
|
846
|
-
match_name = self.queryset.values_list("name", flat=True)[0].upper()
|
|
847
|
-
params = {"q": match_name}
|
|
848
|
-
expected_matches = (
|
|
849
|
-
Q(id__iexact=match_name) | Q(name__icontains=match_name) | Q(remote_url__icontains=match_name) # pylint: disable=unsupported-binary-operation
|
|
850
|
-
)
|
|
851
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
852
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(expected_matches)
|
|
853
|
-
)
|
|
854
|
-
|
|
855
|
-
match_remote_url = self.queryset.values_list("remote_url", flat=True)[0].upper()
|
|
856
|
-
expected_matches = (
|
|
857
|
-
Q(id__iexact=match_remote_url) # pylint: disable=unsupported-binary-operation
|
|
858
|
-
| Q(name__icontains=match_remote_url)
|
|
859
|
-
| Q(remote_url__icontains=match_remote_url)
|
|
860
|
-
)
|
|
861
|
-
params = {"q": match_remote_url}
|
|
862
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
863
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(expected_matches)
|
|
864
|
-
)
|
|
865
|
-
|
|
866
|
-
match_pk = str(self.queryset.values_list("pk", flat=True)[0]).title()
|
|
867
|
-
expected_matches = Q(id__iexact=match_pk) | Q(name__icontains=match_pk) | Q(remote_url__icontains=match_pk) # pylint: disable=unsupported-binary-operation
|
|
868
|
-
params = {"q": match_pk}
|
|
869
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
870
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(expected_matches)
|
|
871
|
-
)
|
|
872
|
-
|
|
873
702
|
def test_verify_ssl(self):
|
|
874
703
|
params = {"verify_ssl": True}
|
|
875
704
|
self.assertQuerysetEqualAndNotEmpty(
|
|
@@ -884,6 +713,16 @@ class ExternalIntegrationTestCase(FilterTestCases.FilterTestCase):
|
|
|
884
713
|
class GitRepositoryTestCase(FilterTestCases.FilterTestCase):
|
|
885
714
|
queryset = GitRepository.objects.all()
|
|
886
715
|
filterset = GitRepositoryFilterSet
|
|
716
|
+
generic_filter_tests = (
|
|
717
|
+
("branch",),
|
|
718
|
+
("name",),
|
|
719
|
+
# ("provided_contents",), # TODO
|
|
720
|
+
("remote_url",),
|
|
721
|
+
("secrets_group", "secrets_group__id"),
|
|
722
|
+
("secrets_group", "secrets_group__name"),
|
|
723
|
+
("secrets_group_id", "secrets_group__id"),
|
|
724
|
+
("slug",),
|
|
725
|
+
)
|
|
887
726
|
|
|
888
727
|
@classmethod
|
|
889
728
|
def setUpTestData(cls):
|
|
@@ -932,43 +771,17 @@ class GitRepositoryTestCase(FilterTestCases.FilterTestCase):
|
|
|
932
771
|
repos[0].tags.set(Tag.objects.get_for_model(GitRepository))
|
|
933
772
|
repos[1].tags.set(Tag.objects.get_for_model(GitRepository)[:3])
|
|
934
773
|
|
|
935
|
-
def test_id(self):
|
|
936
|
-
params = {"id": self.queryset.values_list("pk", flat=True)[:2]}
|
|
937
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
938
|
-
|
|
939
|
-
def test_name(self):
|
|
940
|
-
params = {"name": ["Repo 3", "Repo 2"]}
|
|
941
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
942
|
-
|
|
943
|
-
def test_remote_url(self):
|
|
944
|
-
params = {"remote_url": ["https://example.com/repo1.git"]}
|
|
945
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
946
|
-
|
|
947
|
-
def test_branch(self):
|
|
948
|
-
params = {"branch": ["main", "next"]}
|
|
949
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
950
|
-
|
|
951
774
|
def test_provided_contents(self):
|
|
952
775
|
params = {"provided_contents": ["extras.exporttemplate"]}
|
|
953
776
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
954
777
|
params = {"provided_contents": ["extras.job"]}
|
|
955
778
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
956
779
|
|
|
957
|
-
def test_secrets_group(self):
|
|
958
|
-
filter_params = [
|
|
959
|
-
{"secrets_group_id": [self.secrets_groups[0].pk, self.secrets_groups[1].pk]},
|
|
960
|
-
{"secrets_group": [self.secrets_groups[0].name, self.secrets_groups[1].pk]},
|
|
961
|
-
]
|
|
962
|
-
for params in filter_params:
|
|
963
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
964
|
-
self.filterset(params, self.queryset).qs,
|
|
965
|
-
self.queryset.filter(secrets_group__in=self.secrets_groups).distinct(),
|
|
966
|
-
)
|
|
967
|
-
|
|
968
780
|
|
|
969
|
-
class GraphQLTestCase(FilterTestCases.
|
|
781
|
+
class GraphQLTestCase(FilterTestCases.FilterTestCase):
|
|
970
782
|
queryset = GraphQLQuery.objects.all()
|
|
971
783
|
filterset = GraphQLQueryFilterSet
|
|
784
|
+
generic_filter_tests = (("name",),)
|
|
972
785
|
# skip testing "query" attribute for generic q filter test as it's not trivially modifiable
|
|
973
786
|
exclude_q_filter_predicates = ["query"]
|
|
974
787
|
|
|
@@ -1001,6 +814,7 @@ class GraphQLTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1001
814
|
class ImageAttachmentTestCase(FilterTestCases.FilterTestCase):
|
|
1002
815
|
queryset = ImageAttachment.objects.all()
|
|
1003
816
|
filterset = ImageAttachmentFilterSet
|
|
817
|
+
generic_filter_tests = (("name",),)
|
|
1004
818
|
|
|
1005
819
|
@classmethod
|
|
1006
820
|
def setUpTestData(cls):
|
|
@@ -1048,10 +862,6 @@ class ImageAttachmentTestCase(FilterTestCases.FilterTestCase):
|
|
|
1048
862
|
image_width=100,
|
|
1049
863
|
)
|
|
1050
864
|
|
|
1051
|
-
def test_name(self):
|
|
1052
|
-
params = {"name": ["Image Attachment 1", "Image Attachment 2"]}
|
|
1053
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1054
|
-
|
|
1055
865
|
def test_content_type(self):
|
|
1056
866
|
params = {"content_type": "dcim.location"}
|
|
1057
867
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
@@ -1064,19 +874,21 @@ class ImageAttachmentTestCase(FilterTestCases.FilterTestCase):
|
|
|
1064
874
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
1065
875
|
|
|
1066
876
|
|
|
1067
|
-
class JobFilterSetTestCase(FilterTestCases.
|
|
877
|
+
class JobFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
1068
878
|
queryset = Job.objects.all()
|
|
1069
879
|
filterset = JobFilterSet
|
|
880
|
+
generic_filter_tests = (
|
|
881
|
+
("grouping",),
|
|
882
|
+
("job_class_name",),
|
|
883
|
+
("module_name",),
|
|
884
|
+
("name",),
|
|
885
|
+
)
|
|
1070
886
|
|
|
1071
887
|
@classmethod
|
|
1072
888
|
def setUpTestData(cls):
|
|
1073
889
|
Job.objects.first().tags.set(Tag.objects.get_for_model(Job))
|
|
1074
890
|
Job.objects.last().tags.set(Tag.objects.get_for_model(Job)[:3])
|
|
1075
891
|
|
|
1076
|
-
def test_grouping(self):
|
|
1077
|
-
params = {"grouping": ["file_upload_pass", "file_upload_fail"]}
|
|
1078
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1079
|
-
|
|
1080
892
|
def test_installed(self):
|
|
1081
893
|
params = {"job_class_name": "TestPassJob", "installed": True}
|
|
1082
894
|
self.assertTrue(self.filterset(params, self.queryset).qs.exists())
|
|
@@ -1106,28 +918,74 @@ class JobFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1106
918
|
self.queryset.filter(approval_required=True),
|
|
1107
919
|
)
|
|
1108
920
|
|
|
1109
|
-
def
|
|
1110
|
-
params = {"
|
|
1111
|
-
|
|
1112
|
-
|
|
1113
|
-
|
|
1114
|
-
|
|
921
|
+
def test_is_job_hook_receiver(self):
|
|
922
|
+
params = {"is_job_hook_receiver": True}
|
|
923
|
+
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
|
924
|
+
|
|
925
|
+
|
|
926
|
+
class JobQueueFilterSetTestCase(FilterTestCases.FilterTestCase, FilterTestCases.TenancyFilterTestCaseMixin):
|
|
927
|
+
queryset = JobQueue.objects.all()
|
|
928
|
+
filterset = JobQueueFilterSet
|
|
929
|
+
tenancy_related_name = "job_queues"
|
|
930
|
+
generic_filter_tests = [
|
|
931
|
+
["name"],
|
|
932
|
+
]
|
|
933
|
+
|
|
934
|
+
@classmethod
|
|
935
|
+
def setUpTestData(cls):
|
|
936
|
+
# create some job queues that do not have jobs attached to them
|
|
937
|
+
# for has_jobs boolean filter
|
|
938
|
+
JobQueue.objects.create(
|
|
939
|
+
name="Empty Job Queue 1",
|
|
940
|
+
queue_type=JobQueueTypeChoices.TYPE_KUBERNETES,
|
|
941
|
+
)
|
|
942
|
+
JobQueue.objects.create(name="Empty Job Queue 2", queue_type=JobQueueTypeChoices.TYPE_CELERY)
|
|
943
|
+
JobQueue.objects.create(
|
|
944
|
+
name="Empty Job Queue 3",
|
|
945
|
+
queue_type=JobQueueTypeChoices.TYPE_KUBERNETES,
|
|
946
|
+
)
|
|
947
|
+
JobQueue.objects.create(
|
|
948
|
+
name="Empty Job Queue 4",
|
|
949
|
+
queue_type=JobQueueTypeChoices.TYPE_KUBERNETES,
|
|
950
|
+
)
|
|
951
|
+
|
|
952
|
+
def test_queue_type(self):
|
|
953
|
+
# we cannot add this test to self.generic_filter_tests because JobQueueTypeChoices only has two values.
|
|
954
|
+
# self.generic_filter_tests needs at least three.
|
|
955
|
+
params = {"queue_type": [JobQueueTypeChoices.TYPE_CELERY]}
|
|
956
|
+
self.assertQuerysetEqualAndNotEmpty(
|
|
957
|
+
self.filterset(params, self.queryset).qs, self.queryset.filter(queue_type=JobQueueTypeChoices.TYPE_CELERY)
|
|
1115
958
|
)
|
|
959
|
+
params = {"queue_type": [JobQueueTypeChoices.TYPE_KUBERNETES]}
|
|
1116
960
|
self.assertQuerysetEqualAndNotEmpty(
|
|
1117
|
-
self.filterset(params, self.queryset).qs,
|
|
961
|
+
self.filterset(params, self.queryset).qs,
|
|
962
|
+
self.queryset.filter(queue_type=JobQueueTypeChoices.TYPE_KUBERNETES),
|
|
1118
963
|
)
|
|
1119
|
-
value = self.queryset.values_list("pk", flat=True)[0]
|
|
1120
|
-
params = {"q": value}
|
|
1121
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
1122
964
|
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
965
|
+
|
|
966
|
+
class JobQueueAssignmentFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
967
|
+
queryset = JobQueueAssignment.objects.all()
|
|
968
|
+
filterset = JobQueueAssignmentFilterSet
|
|
969
|
+
generic_filter_tests = [
|
|
970
|
+
("job", "job__id"),
|
|
971
|
+
("job", "job__name"),
|
|
972
|
+
("job_queue", "job_queue__id"),
|
|
973
|
+
("job_queue", "job_queue__name"),
|
|
974
|
+
]
|
|
1126
975
|
|
|
1127
976
|
|
|
1128
977
|
class JobResultFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
1129
978
|
queryset = JobResult.objects.all()
|
|
1130
979
|
filterset = JobResultFilterSet
|
|
980
|
+
generic_filter_tests = (
|
|
981
|
+
("date_created",),
|
|
982
|
+
("date_done",),
|
|
983
|
+
("job_model", "job_model__id"),
|
|
984
|
+
("job_model", "job_model__name"),
|
|
985
|
+
("job_model_id", "job_model__id"),
|
|
986
|
+
("name",),
|
|
987
|
+
("status",),
|
|
988
|
+
)
|
|
1131
989
|
|
|
1132
990
|
@classmethod
|
|
1133
991
|
def setUpTestData(cls):
|
|
@@ -1178,17 +1036,6 @@ class JobResultFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
1178
1036
|
scheduled_job=scheduled_jobs[idx],
|
|
1179
1037
|
)
|
|
1180
1038
|
|
|
1181
|
-
def test_job_model(self):
|
|
1182
|
-
jobs = list(self.jobs[:2])
|
|
1183
|
-
filter_params = [
|
|
1184
|
-
{"job_model_id": [jobs[0].pk, jobs[1].pk]},
|
|
1185
|
-
{"job_model": [jobs[0].pk, jobs[1].name]},
|
|
1186
|
-
]
|
|
1187
|
-
for params in filter_params:
|
|
1188
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1189
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(job_model__in=jobs).distinct()
|
|
1190
|
-
)
|
|
1191
|
-
|
|
1192
1039
|
def test_scheduled_job(self):
|
|
1193
1040
|
scheduled_jobs = list(self.scheduled_jobs[:2])
|
|
1194
1041
|
filter_params = [
|
|
@@ -1201,9 +1048,14 @@ class JobResultFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
1201
1048
|
)
|
|
1202
1049
|
|
|
1203
1050
|
|
|
1204
|
-
class JobHookFilterSetTestCase(FilterTestCases.
|
|
1051
|
+
class JobHookFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
1205
1052
|
queryset = JobHook.objects.all()
|
|
1206
1053
|
filterset = JobHookFilterSet
|
|
1054
|
+
generic_filter_tests = (
|
|
1055
|
+
("job", "job__id"),
|
|
1056
|
+
("job", "job__name"),
|
|
1057
|
+
("name",),
|
|
1058
|
+
)
|
|
1207
1059
|
|
|
1208
1060
|
@classmethod
|
|
1209
1061
|
def setUpTestData(cls):
|
|
@@ -1234,10 +1086,6 @@ class JobHookFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1234
1086
|
job_hooks[0].content_types.set([devicetype_ct])
|
|
1235
1087
|
job_hooks[1].content_types.set([devicetype_ct])
|
|
1236
1088
|
|
|
1237
|
-
def test_name(self):
|
|
1238
|
-
params = {"name": ["JobHook1", "JobHook2"]}
|
|
1239
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1240
|
-
|
|
1241
1089
|
def test_content_types(self):
|
|
1242
1090
|
params = {"content_types": ["dcim.devicetype"]}
|
|
1243
1091
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
@@ -1246,11 +1094,6 @@ class JobHookFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1246
1094
|
params = {"enabled": True}
|
|
1247
1095
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1248
1096
|
|
|
1249
|
-
def test_job(self):
|
|
1250
|
-
jobs = Job.objects.filter(job_class_name__in=["TestJobHookReceiverLog", "TestJobHookReceiverChange"])[:2]
|
|
1251
|
-
params = {"job": [jobs[0].name, jobs[1].pk]}
|
|
1252
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1253
|
-
|
|
1254
1097
|
def test_type_create(self):
|
|
1255
1098
|
params = {"type_create": True}
|
|
1256
1099
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
@@ -1263,16 +1106,17 @@ class JobHookFilterSetTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1263
1106
|
params = {"type_update": True}
|
|
1264
1107
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1265
1108
|
|
|
1266
|
-
def test_search(self):
|
|
1267
|
-
params = {"q": "hook"}
|
|
1268
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
1269
|
-
params = {"q": "hook1"}
|
|
1270
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
1271
|
-
|
|
1272
1109
|
|
|
1273
1110
|
class JobButtonFilterTestCase(FilterTestCases.FilterTestCase):
|
|
1274
1111
|
queryset = JobButton.objects.all()
|
|
1275
1112
|
filterset = JobButtonFilterSet
|
|
1113
|
+
generic_filter_tests = (
|
|
1114
|
+
# ("job", "job__id"), # TODO: not enough distinct values for generic test
|
|
1115
|
+
# ("job", "job__name"), # TODO: not enough distinct values for generic test
|
|
1116
|
+
("name",),
|
|
1117
|
+
("text",),
|
|
1118
|
+
("weight",),
|
|
1119
|
+
)
|
|
1276
1120
|
|
|
1277
1121
|
@classmethod
|
|
1278
1122
|
def setUpTestData(cls):
|
|
@@ -1304,12 +1148,6 @@ class JobButtonFilterTestCase(FilterTestCases.FilterTestCase):
|
|
|
1304
1148
|
for jb in job_buttons:
|
|
1305
1149
|
jb.content_types.set([location_ct])
|
|
1306
1150
|
|
|
1307
|
-
def test_name(self):
|
|
1308
|
-
params = {"name": ["JobButton1", "JobButton2"]}
|
|
1309
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1310
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(name__in=["JobButton1", "JobButton2"])
|
|
1311
|
-
)
|
|
1312
|
-
|
|
1313
1151
|
def test_job(self):
|
|
1314
1152
|
job = Job.objects.get(job_class_name="TestJobButtonReceiverSimple")
|
|
1315
1153
|
params = {"job": [job.pk]}
|
|
@@ -1322,23 +1160,15 @@ class JobButtonFilterTestCase(FilterTestCases.FilterTestCase):
|
|
|
1322
1160
|
self.filterset(params, self.queryset).qs, self.queryset.filter(job__name=job.name)
|
|
1323
1161
|
)
|
|
1324
1162
|
|
|
1325
|
-
def test_weight(self):
|
|
1326
|
-
params = {"weight": [30, 50]}
|
|
1327
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1328
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(weight__in=[30, 50])
|
|
1329
|
-
)
|
|
1330
|
-
|
|
1331
|
-
def test_search(self):
|
|
1332
|
-
params = {"q": "JobButton"}
|
|
1333
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1334
|
-
self.filterset(params, self.queryset).qs,
|
|
1335
|
-
self.queryset.filter(name__in=["JobButton1", "JobButton2", "JobButton3"]),
|
|
1336
|
-
)
|
|
1337
|
-
|
|
1338
1163
|
|
|
1339
1164
|
class JobLogEntryTestCase(FilterTestCases.FilterTestCase):
|
|
1340
1165
|
queryset = JobLogEntry.objects.all()
|
|
1341
1166
|
filterset = JobLogEntryFilterSet
|
|
1167
|
+
generic_filter_tests = (
|
|
1168
|
+
("grouping",),
|
|
1169
|
+
("log_level",),
|
|
1170
|
+
("message",),
|
|
1171
|
+
)
|
|
1342
1172
|
|
|
1343
1173
|
@classmethod
|
|
1344
1174
|
def setUpTestData(cls):
|
|
@@ -1352,56 +1182,6 @@ class JobLogEntryTestCase(FilterTestCases.FilterTestCase):
|
|
|
1352
1182
|
message=f"I am a {log_level} log.",
|
|
1353
1183
|
)
|
|
1354
1184
|
|
|
1355
|
-
def test_log_level(self):
|
|
1356
|
-
params = {"log_level": ["debug"]}
|
|
1357
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1358
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(log_level="debug")
|
|
1359
|
-
)
|
|
1360
|
-
|
|
1361
|
-
def test_grouping(self):
|
|
1362
|
-
params = {"grouping": ["run"]}
|
|
1363
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1364
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(grouping="run")
|
|
1365
|
-
)
|
|
1366
|
-
|
|
1367
|
-
def test_message(self):
|
|
1368
|
-
params = {"message": ["I am a debug log."]}
|
|
1369
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1370
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(message="I am a debug log.")
|
|
1371
|
-
)
|
|
1372
|
-
|
|
1373
|
-
def test_search(self):
|
|
1374
|
-
params = {"q": "run"}
|
|
1375
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1376
|
-
self.filterset(params, self.queryset).qs,
|
|
1377
|
-
self.queryset.filter(
|
|
1378
|
-
# TODO: Remove pylint disable after issue is resolved (see: https://github.com/PyCQA/pylint/issues/7381)
|
|
1379
|
-
# pylint: disable=unsupported-binary-operation
|
|
1380
|
-
Q(grouping__icontains="run") | Q(message__icontains="run") | Q(log_level__icontains="run")
|
|
1381
|
-
# pylint: enable=unsupported-binary-operation
|
|
1382
|
-
),
|
|
1383
|
-
)
|
|
1384
|
-
params = {"q": "warning"}
|
|
1385
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1386
|
-
self.filterset(params, self.queryset).qs,
|
|
1387
|
-
self.queryset.filter(
|
|
1388
|
-
# TODO: Remove pylint disable after issue is resolved (see: https://github.com/PyCQA/pylint/issues/7381)
|
|
1389
|
-
# pylint: disable=unsupported-binary-operation
|
|
1390
|
-
Q(grouping__icontains="warning") | Q(message__icontains="warning") | Q(log_level__icontains="warning")
|
|
1391
|
-
# pylint: enable=unsupported-binary-operation
|
|
1392
|
-
),
|
|
1393
|
-
)
|
|
1394
|
-
params = {"q": "debug"}
|
|
1395
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1396
|
-
self.filterset(params, self.queryset).qs,
|
|
1397
|
-
self.queryset.filter(
|
|
1398
|
-
# TODO: Remove pylint disable after issue is resolved (see: https://github.com/PyCQA/pylint/issues/7381)
|
|
1399
|
-
# pylint: disable=unsupported-binary-operation
|
|
1400
|
-
Q(grouping__icontains="debug") | Q(message__icontains="debug") | Q(log_level__icontains="debug")
|
|
1401
|
-
# pylint: enable=unsupported-binary-operation
|
|
1402
|
-
),
|
|
1403
|
-
)
|
|
1404
|
-
|
|
1405
1185
|
|
|
1406
1186
|
class MetadataChoiceTestCase(FilterTestCases.FilterTestCase):
|
|
1407
1187
|
queryset = MetadataChoice.objects.all()
|
|
@@ -1434,6 +1214,12 @@ class MetadataTypeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1434
1214
|
class ObjectChangeTestCase(FilterTestCases.FilterTestCase):
|
|
1435
1215
|
queryset = ObjectChange.objects.all()
|
|
1436
1216
|
filterset = ObjectChangeFilterSet
|
|
1217
|
+
generic_filter_tests = (
|
|
1218
|
+
("user", "user__id"),
|
|
1219
|
+
("user", "user__username"),
|
|
1220
|
+
("user_id", "user__id"),
|
|
1221
|
+
("user_name",),
|
|
1222
|
+
)
|
|
1437
1223
|
|
|
1438
1224
|
@classmethod
|
|
1439
1225
|
def setUpTestData(cls):
|
|
@@ -1505,21 +1291,6 @@ class ObjectChangeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1505
1291
|
object_data={"address": str(ipaddress.address), "status": str(ipaddress.status)},
|
|
1506
1292
|
)
|
|
1507
1293
|
|
|
1508
|
-
def test_user(self):
|
|
1509
|
-
users = list(User.objects.filter(username__in=["user1", "user2"]))
|
|
1510
|
-
filter_params = [
|
|
1511
|
-
{"user_id": [users[0].pk, users[1].pk]},
|
|
1512
|
-
{"user": [users[0].pk, users[1].username]},
|
|
1513
|
-
]
|
|
1514
|
-
for params in filter_params:
|
|
1515
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1516
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(user__in=users).distinct()
|
|
1517
|
-
)
|
|
1518
|
-
|
|
1519
|
-
def test_user_name(self):
|
|
1520
|
-
params = {"user_name": ["user1", "user2"]}
|
|
1521
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 4)
|
|
1522
|
-
|
|
1523
1294
|
def test_changed_object_type(self):
|
|
1524
1295
|
params = {"changed_object_type": "dcim.location"}
|
|
1525
1296
|
self.assertQuerysetEqualAndNotEmpty(
|
|
@@ -1534,11 +1305,6 @@ class ObjectChangeTestCase(FilterTestCases.FilterTestCase):
|
|
|
1534
1305
|
self.queryset.filter(changed_object_type=ContentType.objects.get_for_model(Location)),
|
|
1535
1306
|
)
|
|
1536
1307
|
|
|
1537
|
-
def test_search(self):
|
|
1538
|
-
value = self.queryset.values_list("pk", flat=True)[0]
|
|
1539
|
-
params = {"q": value}
|
|
1540
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
1541
|
-
|
|
1542
1308
|
|
|
1543
1309
|
class ObjectMetadataTestCase(FilterTestCases.FilterTestCase):
|
|
1544
1310
|
queryset = ObjectMetadata.objects.all()
|
|
@@ -1618,6 +1384,11 @@ class ObjectMetadataTestCase(FilterTestCases.FilterTestCase):
|
|
|
1618
1384
|
class RelationshipTestCase(FilterTestCases.FilterTestCase):
|
|
1619
1385
|
queryset = Relationship.objects.all()
|
|
1620
1386
|
filterset = RelationshipFilterSet
|
|
1387
|
+
generic_filter_tests = (
|
|
1388
|
+
("key",),
|
|
1389
|
+
("label",),
|
|
1390
|
+
("type",),
|
|
1391
|
+
)
|
|
1621
1392
|
|
|
1622
1393
|
@classmethod
|
|
1623
1394
|
def setUpTestData(cls):
|
|
@@ -1647,26 +1418,6 @@ class RelationshipTestCase(FilterTestCases.FilterTestCase):
|
|
|
1647
1418
|
destination_type=interface_type,
|
|
1648
1419
|
).validated_save()
|
|
1649
1420
|
|
|
1650
|
-
def test_label(self):
|
|
1651
|
-
"""Verify that the filterset supports filtering by label."""
|
|
1652
|
-
params = {"label": list(self.queryset.values_list("label", flat=True)[:2])}
|
|
1653
|
-
filterset = self.filterset(params, self.queryset)
|
|
1654
|
-
self.assertTrue(filterset.is_valid())
|
|
1655
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
1656
|
-
filterset.qs.order_by("label"), self.queryset.filter(label__in=params["label"]).order_by("label")
|
|
1657
|
-
)
|
|
1658
|
-
|
|
1659
|
-
def test_key(self):
|
|
1660
|
-
"""Verify that the filterset supports filtering by key."""
|
|
1661
|
-
params = {"key": self.queryset.values_list("key", flat=True)[:2]}
|
|
1662
|
-
filterset = self.filterset(params, self.queryset)
|
|
1663
|
-
self.assertTrue(filterset.is_valid())
|
|
1664
|
-
self.assertEqual(filterset.qs.count(), 2)
|
|
1665
|
-
|
|
1666
|
-
def test_type(self):
|
|
1667
|
-
params = {"type": ["one-to-many"]}
|
|
1668
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
1669
|
-
|
|
1670
1421
|
def test_source_type(self):
|
|
1671
1422
|
params = {"source_type": ["dcim.device"]}
|
|
1672
1423
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
@@ -1679,6 +1430,12 @@ class RelationshipTestCase(FilterTestCases.FilterTestCase):
|
|
|
1679
1430
|
class RelationshipAssociationFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
1680
1431
|
queryset = RelationshipAssociation.objects.all()
|
|
1681
1432
|
filterset = RelationshipAssociationFilterSet
|
|
1433
|
+
generic_filter_tests = (
|
|
1434
|
+
("destination_id",),
|
|
1435
|
+
# ("relationship", "relationship__id"), # TODO?
|
|
1436
|
+
("relationship", "relationship__key"),
|
|
1437
|
+
("source_id",),
|
|
1438
|
+
)
|
|
1682
1439
|
|
|
1683
1440
|
@classmethod
|
|
1684
1441
|
def setUpTestData(cls):
|
|
@@ -1794,26 +1551,14 @@ class RelationshipAssociationFilterSetTestCase(FilterTestCases.FilterTestCase):
|
|
|
1794
1551
|
for relationship_association in cls.relationship_associations:
|
|
1795
1552
|
relationship_association.validated_save()
|
|
1796
1553
|
|
|
1797
|
-
def test_relationship(self):
|
|
1798
|
-
params = {"relationship": [self.relationships[0].key]}
|
|
1799
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1800
|
-
|
|
1801
1554
|
def test_source_type(self):
|
|
1802
1555
|
params = {"source_type": ["dcim.device", "dcim.interface"]}
|
|
1803
1556
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5)
|
|
1804
1557
|
|
|
1805
|
-
def test_source_id(self):
|
|
1806
|
-
params = {"source_id": [self.devices[0].pk, self.devices[1].pk]}
|
|
1807
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 5)
|
|
1808
|
-
|
|
1809
1558
|
def test_destination_type(self):
|
|
1810
1559
|
params = {"destination_type": ["dcim.device", "dcim.interface"]}
|
|
1811
1560
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 6)
|
|
1812
1561
|
|
|
1813
|
-
def test_destination_id(self):
|
|
1814
|
-
params = {"destination_id": [self.devices[0].pk, self.devices[1].pk]}
|
|
1815
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
1816
|
-
|
|
1817
1562
|
def test_peer_id(self):
|
|
1818
1563
|
params = {"peer_id": [self.devices[0].pk, self.devices[1].pk]}
|
|
1819
1564
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
@@ -1949,9 +1694,16 @@ class SavedViewTestCase(FilterTestCases.FilterTestCase):
|
|
|
1949
1694
|
)
|
|
1950
1695
|
|
|
1951
1696
|
|
|
1952
|
-
class SecretTestCase(FilterTestCases.
|
|
1697
|
+
class SecretTestCase(FilterTestCases.FilterTestCase):
|
|
1953
1698
|
queryset = Secret.objects.all()
|
|
1954
1699
|
filterset = SecretFilterSet
|
|
1700
|
+
generic_filter_tests = (
|
|
1701
|
+
("created",),
|
|
1702
|
+
("last_updated",),
|
|
1703
|
+
("name",),
|
|
1704
|
+
("tags", "tags__id"),
|
|
1705
|
+
("tags", "tags__name"),
|
|
1706
|
+
)
|
|
1955
1707
|
|
|
1956
1708
|
@classmethod
|
|
1957
1709
|
def setUpTestData(cls):
|
|
@@ -1981,15 +1733,15 @@ class SecretTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1981
1733
|
params = {"provider": ["environment-variable"]}
|
|
1982
1734
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
1983
1735
|
|
|
1984
|
-
def test_search(self):
|
|
1985
|
-
value = self.queryset.values_list("pk", flat=True)[0]
|
|
1986
|
-
params = {"q": value}
|
|
1987
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
1988
|
-
|
|
1989
1736
|
|
|
1990
|
-
class SecretsGroupTestCase(FilterTestCases.
|
|
1737
|
+
class SecretsGroupTestCase(FilterTestCases.FilterTestCase):
|
|
1991
1738
|
queryset = SecretsGroup.objects.all()
|
|
1992
1739
|
filterset = SecretsGroupFilterSet
|
|
1740
|
+
generic_filter_tests = (
|
|
1741
|
+
("created",),
|
|
1742
|
+
("last_updated",),
|
|
1743
|
+
("name",),
|
|
1744
|
+
)
|
|
1993
1745
|
|
|
1994
1746
|
@classmethod
|
|
1995
1747
|
def setUpTestData(cls):
|
|
@@ -1997,17 +1749,18 @@ class SecretsGroupTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
1997
1749
|
SecretsGroup.objects.create(name="Group 2")
|
|
1998
1750
|
SecretsGroup.objects.create(name="Group 3")
|
|
1999
1751
|
|
|
2000
|
-
def test_search(self):
|
|
2001
|
-
value = self.queryset.values_list("pk", flat=True)[0]
|
|
2002
|
-
params = {"q": value}
|
|
2003
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
2004
|
-
|
|
2005
1752
|
|
|
2006
1753
|
class SecretsGroupAssociationTestCase(FilterTestCases.FilterTestCase):
|
|
2007
1754
|
queryset = SecretsGroupAssociation.objects.all()
|
|
2008
1755
|
filterset = SecretsGroupAssociationFilterSet
|
|
2009
1756
|
|
|
2010
|
-
generic_filter_tests = (
|
|
1757
|
+
generic_filter_tests = (
|
|
1758
|
+
("secret", "secret__id"),
|
|
1759
|
+
("secret", "secret__name"),
|
|
1760
|
+
("secret_id", "secret__id"),
|
|
1761
|
+
("secrets_group", "secrets_group__id"),
|
|
1762
|
+
("secrets_group", "secrets_group__name"),
|
|
1763
|
+
)
|
|
2011
1764
|
|
|
2012
1765
|
@classmethod
|
|
2013
1766
|
def setUpTestData(cls):
|
|
@@ -2057,16 +1810,6 @@ class SecretsGroupAssociationTestCase(FilterTestCases.FilterTestCase):
|
|
|
2057
1810
|
secret_type=SecretsGroupSecretTypeChoices.TYPE_PASSWORD,
|
|
2058
1811
|
)
|
|
2059
1812
|
|
|
2060
|
-
def test_secret(self):
|
|
2061
|
-
filter_params = [
|
|
2062
|
-
{"secret_id": [self.secrets[0].pk, self.secrets[1].pk]},
|
|
2063
|
-
{"secret": [self.secrets[0].name, self.secrets[1].pk]},
|
|
2064
|
-
]
|
|
2065
|
-
for params in filter_params:
|
|
2066
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2067
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(secret__in=self.secrets[:2]).distinct()
|
|
2068
|
-
)
|
|
2069
|
-
|
|
2070
1813
|
def test_access_type(self):
|
|
2071
1814
|
params = {"access_type": [SecretsGroupAccessTypeChoices.TYPE_GENERIC]}
|
|
2072
1815
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
@@ -2103,9 +1846,13 @@ class StaticGroupAssociationTestCase(FilterTestCases.FilterTestCase):
|
|
|
2103
1846
|
)
|
|
2104
1847
|
|
|
2105
1848
|
|
|
2106
|
-
class StatusTestCase(FilterTestCases.
|
|
1849
|
+
class StatusTestCase(FilterTestCases.FilterTestCase):
|
|
2107
1850
|
queryset = Status.objects.all()
|
|
2108
1851
|
filterset = StatusFilterSet
|
|
1852
|
+
generic_filter_tests = (
|
|
1853
|
+
("color",),
|
|
1854
|
+
("name",),
|
|
1855
|
+
)
|
|
2109
1856
|
|
|
2110
1857
|
def test_content_types(self):
|
|
2111
1858
|
ct = ContentType.objects.get_for_model(Device)
|
|
@@ -2113,57 +1860,25 @@ class StatusTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
2113
1860
|
params = {"content_types": ["dcim.device"]}
|
|
2114
1861
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), status_count)
|
|
2115
1862
|
|
|
2116
|
-
def test_color(self):
|
|
2117
|
-
"""Test the color search field."""
|
|
2118
|
-
params = {"color": [ColorChoices.COLOR_GREY]}
|
|
2119
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2120
|
-
self.filterset(params, self.queryset).qs, Status.objects.filter(color=ColorChoices.COLOR_GREY)
|
|
2121
|
-
)
|
|
2122
|
-
|
|
2123
|
-
def test_search(self):
|
|
2124
|
-
params = {"q": "active"}
|
|
2125
|
-
# TODO: Remove pylint disable after issue is resolved (see: https://github.com/PyCQA/pylint/issues/7381)
|
|
2126
|
-
# pylint: disable=unsupported-binary-operation
|
|
2127
|
-
q = Q(id__iexact="active") | Q(name__icontains="active")
|
|
2128
|
-
# pylint: enable=unsupported-binary-operation
|
|
2129
|
-
q |= Q(content_types__model__icontains="active")
|
|
2130
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2131
|
-
self.filterset(params, self.queryset).qs,
|
|
2132
|
-
self.queryset.filter(q).distinct(),
|
|
2133
|
-
)
|
|
2134
|
-
value = self.queryset.first().pk
|
|
2135
|
-
params = {"q": value}
|
|
2136
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2137
|
-
self.filterset(params, self.queryset).qs,
|
|
2138
|
-
self.queryset.filter(pk=value),
|
|
2139
|
-
)
|
|
2140
|
-
|
|
2141
1863
|
|
|
2142
|
-
class TagTestCase(FilterTestCases.
|
|
1864
|
+
class TagTestCase(FilterTestCases.FilterTestCase):
|
|
2143
1865
|
queryset = Tag.objects.all()
|
|
2144
1866
|
filterset = TagFilterSet
|
|
1867
|
+
generic_filter_tests = (
|
|
1868
|
+
("color",),
|
|
1869
|
+
("name",),
|
|
1870
|
+
)
|
|
2145
1871
|
|
|
2146
1872
|
@classmethod
|
|
2147
1873
|
def setUpTestData(cls):
|
|
2148
1874
|
cls.tags = Tag.objects.all()
|
|
2149
1875
|
|
|
2150
|
-
def test_color(self):
|
|
2151
|
-
params = {"color": [self.tags[0].color, self.tags[1].color]}
|
|
2152
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 2)
|
|
2153
|
-
|
|
2154
1876
|
def test_content_types(self):
|
|
2155
1877
|
params = {"content_types": ["dcim.location"]}
|
|
2156
1878
|
filtered_data = self.filterset(params, self.queryset).qs
|
|
2157
1879
|
self.assertQuerysetEqual(filtered_data, Tag.objects.get_for_model(Location))
|
|
2158
1880
|
self.assertEqual(filtered_data[0], Tag.objects.get_for_model(Location)[0])
|
|
2159
1881
|
|
|
2160
|
-
def test_search(self):
|
|
2161
|
-
params = {"q": self.tags[0].name}
|
|
2162
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
2163
|
-
value = self.queryset.values_list("pk", flat=True)[0]
|
|
2164
|
-
params = {"q": value}
|
|
2165
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
2166
|
-
|
|
2167
1882
|
|
|
2168
1883
|
class TeamFilterSetTestCase(ContactAndTeamFilterSetTestCaseMixin, FilterTestCases.FilterTestCase):
|
|
2169
1884
|
queryset = Team.objects.all()
|
|
@@ -2181,6 +1896,10 @@ class TeamFilterSetTestCase(ContactAndTeamFilterSetTestCaseMixin, FilterTestCase
|
|
|
2181
1896
|
class WebhookTestCase(FilterTestCases.FilterTestCase):
|
|
2182
1897
|
queryset = Webhook.objects.all()
|
|
2183
1898
|
filterset = WebhookFilterSet
|
|
1899
|
+
generic_filter_tests = (
|
|
1900
|
+
("name",),
|
|
1901
|
+
("payload_url",),
|
|
1902
|
+
)
|
|
2184
1903
|
|
|
2185
1904
|
@classmethod
|
|
2186
1905
|
def setUpTestData(cls):
|
|
@@ -2212,10 +1931,6 @@ class WebhookTestCase(FilterTestCases.FilterTestCase):
|
|
|
2212
1931
|
webhook.save()
|
|
2213
1932
|
webhook.content_types.set([obj_type])
|
|
2214
1933
|
|
|
2215
|
-
def test_name(self):
|
|
2216
|
-
params = {"name": ["webhook-1"]}
|
|
2217
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
2218
|
-
|
|
2219
1934
|
def test_create(self):
|
|
2220
1935
|
params = {"type_create": True}
|
|
2221
1936
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 1)
|
|
@@ -2232,17 +1947,15 @@ class WebhookTestCase(FilterTestCases.FilterTestCase):
|
|
|
2232
1947
|
params = {"enabled": True}
|
|
2233
1948
|
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
2234
1949
|
|
|
2235
|
-
def test_search(self):
|
|
2236
|
-
params = {"q": "webhook"}
|
|
2237
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.count(), 3)
|
|
2238
|
-
value = self.queryset.values_list("pk", flat=True)[0]
|
|
2239
|
-
params = {"q": value}
|
|
2240
|
-
self.assertEqual(self.filterset(params, self.queryset).qs.values_list("pk", flat=True)[0], value)
|
|
2241
|
-
|
|
2242
1950
|
|
|
2243
|
-
class RoleTestCase(FilterTestCases.
|
|
1951
|
+
class RoleTestCase(FilterTestCases.FilterTestCase):
|
|
2244
1952
|
queryset = Role.objects.all()
|
|
2245
1953
|
filterset = RoleFilterSet
|
|
1954
|
+
generic_filter_tests = (
|
|
1955
|
+
("color",),
|
|
1956
|
+
("name",),
|
|
1957
|
+
("weight",),
|
|
1958
|
+
)
|
|
2246
1959
|
|
|
2247
1960
|
def test_content_types(self):
|
|
2248
1961
|
device_ct = ContentType.objects.get_for_model(Device)
|
|
@@ -2254,32 +1967,3 @@ class RoleTestCase(FilterTestCases.NameOnlyFilterTestCase):
|
|
|
2254
1967
|
rack_roles = self.queryset.filter(content_types=rack_ct)
|
|
2255
1968
|
params = {"content_types": ["dcim.rack"]}
|
|
2256
1969
|
self.assertQuerysetEqualAndNotEmpty(self.filterset(params, self.queryset).qs, rack_roles)
|
|
2257
|
-
|
|
2258
|
-
def test_color(self):
|
|
2259
|
-
"""Test the color search field."""
|
|
2260
|
-
params = {"color": [ColorChoices.COLOR_AMBER]}
|
|
2261
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2262
|
-
self.filterset(params, self.queryset).qs, Role.objects.filter(color=ColorChoices.COLOR_AMBER)
|
|
2263
|
-
)
|
|
2264
|
-
|
|
2265
|
-
def test_weight(self):
|
|
2266
|
-
"""Test the weight search field."""
|
|
2267
|
-
instance = self.queryset.filter(weight__isnull=False).first()
|
|
2268
|
-
params = {"weight": [instance.weight]}
|
|
2269
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2270
|
-
self.filterset(params, self.queryset).qs, self.queryset.filter(weight=instance.weight)
|
|
2271
|
-
)
|
|
2272
|
-
|
|
2273
|
-
def test_search(self):
|
|
2274
|
-
value = self.queryset.first().name
|
|
2275
|
-
params = {"q": value}
|
|
2276
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2277
|
-
self.filterset(params, self.queryset).qs,
|
|
2278
|
-
self.queryset.filter(name__icontains=value).distinct(),
|
|
2279
|
-
)
|
|
2280
|
-
value = self.queryset.first().pk
|
|
2281
|
-
params = {"q": value}
|
|
2282
|
-
self.assertQuerysetEqualAndNotEmpty(
|
|
2283
|
-
self.filterset(params, self.queryset).qs,
|
|
2284
|
-
self.queryset.filter(pk=value),
|
|
2285
|
-
)
|