Skip to main content

English · Čeština · Dansk · Deutsch · Español · Français · Italiano · 日本語 · 한국어 · Latviešu · Nederlands · Polski · Português · Русский · Türkçe · Українська · 中文

NetBox Scope Switcher

Pick your scope once — tenant, region, site, tag, whatever you configure — and every list in NetBox narrows to it, with the filters cascading on each other.

netbox-scope-switcher adds one compact, configurable selector to the top navigation bar. Choose values across any number of scope dimensions (grouped however you like) and, as you move between sections (Devices, Prefixes, VLANs, Sites, …), each list view is automatically scoped to your selection.

It generalizes netbox-tenant-switcher: tenant is just the default dimension.

Screenshots

Grouped scope panel with a tenant selected; the Site list has cascaded to that tenant

Grouped dimensions: Tenant / Location / Tag Labels follow the NetBox UI language

Features

  • Configurable, grouped dimensions. Scope by tenant, tenant group, region, site group, site, location, tag, or any filter you declare in PLUGINS_CONFIG — arranged under your own group headings. No code changes.
  • Cascading dependent filters. Selecting values in one dimension narrows the option lists of the others, in both directions: pick a Tenant Group and only its tenants remain; pick a Tenant and Regions/Sites/Racks shrink to where that tenant is present. Powered by NetBox's own filtersets (so tree descendants and every relationship are honoured), with no hard-coded model knowledge.
  • Token-style control. One dropdown with a section per dimension: selected values shown as removable chips, a + add picker with instant search, an Any placeholder, a None option (for objects with no value), per-dimension and global clear. Chips stay name-sorted. No external JS dependencies.
  • Localized. Dimension labels come straight from each model's NetBox verbose_name, and the service words are translated via NetBox's catalog, so the panel follows the active UI language automatically.
  • Resizable & viewport-bounded panel. Drag the corner grip to resize (the size is remembered for the session); the panel never grows past the screen and scrolls internally.
  • Honest URLs. By default the plugin issues a single redirect that adds the filter params to the address bar, so links are shareable, NetBox's own filter panel shows them, and Clear filters behaves predictably. A silent mode is available.
  • Per-scope applicability. Each dimension is applied only on list views whose filterset actually supports it — a prefixes list may scope by tenant and tag but not region — computed by introspection, not hard-coding. The control dims when nothing applies to the current page.
  • Combining semantics: several values within a dimension are OR-combined; different dimensions are AND-combined; None maps to ?param=null.
  • Permission-aware. Only values the user may view are listed and selectable, and scoping only ever narrows results — NetBox object permissions still apply on top.
  • No models, no migrations. Selection lives in the session.

Compatibility

Plugin version NetBox version Python
1.0.x 4.6 3.10 – 3.12

Developed and verified against NetBox 4.6, using only stable plugin APIs (PluginTemplateExtension.navbar() / head(), plugin middleware). The CI matrix (.github/workflows/ci.yml) additionally exercises 4.4 and 4.5.

Installation

source /opt/netbox/venv/bin/activate
pip install netbox-scope-switcher

Enable it in configuration.py:

PLUGINS = ["netbox_scope_switcher"]

Restart NetBox (sudo systemctl restart netbox netbox-rq). No migrations needed.

Docker (netbox-docker)

See deploy/ for a ready-to-use Dockerfile-Plugins, docker-compose.override.yml, and plugins.py.

Configuration

Out of the box the plugin scopes by tenant only (matching netbox-tenant-switcher). To configure dimensions and grouping, set PLUGINS_CONFIG:

PLUGINS_CONFIG = {
    "netbox_scope_switcher": {
        "mode": "redirect",  # or "silent"
        "scopes": [
            {"param": "tenant_group_id", "model": "tenancy.TenantGroup", "group": "Tenant"},
            {"param": "tenant_id",       "model": "tenancy.Tenant",      "group": "Tenant"},
            {"param": "region_id",       "model": "dcim.Region",         "group": "Location"},
            {"param": "site_group_id",   "model": "dcim.SiteGroup",      "group": "Location"},
            {"param": "site_id",         "model": "dcim.Site",           "group": "Location"},
            {"param": "location_id",     "model": "dcim.Location",       "group": "Location"},
            {"param": "tag",             "model": "extras.Tag",          "group": "Tag",
             "value_field": "slug"},
        ],
    }
}

PLUGINS_CONFIG keys

Key Type Default Description
scopes list tenant only Ordered list of scope dimensions (below).
mode string redirect redirect (add params to the URL via a 302) or silent (rewrite the request in place).

Each entry in scopes:

Field Required Default Description
param yes — GET parameter of the filter to apply (e.g. tenant_id, tag).
model yes — app_label.ModelName the dropdown values come from.
group no — Group heading to list this dimension under (translated via NetBox).
label no model verbose name Section heading. Omit it to follow the active UI language.
value_field no pk Value to put in the param: pk or slug (tags filter by slug).

The configuration is validated at startup: an unknown model or field raises a clear ImproperlyConfigured error on load, rather than a 500 at runtime.

How it works

  • Navbar widget (template_content.py) — a PluginTemplateExtension renders the control + a section per dimension via navbar(); CSS/JS are injected once via head(). Options are fetched from the values endpoint on open (so they can cascade); only the static None option is server-rendered.
  • Set endpoint (views.py) — GET /plugins/scope-switcher/set/ stores the chosen values per dimension in the session and redirects back. next is validated against the current host (no open redirects); every value is checked against the user's view permission.
  • Values endpoint (views.py) — GET /plugins/scope-switcher/values/<param>/?q=…&<other>=… returns a permission-scoped, cascaded, searchable JSON option list.
  • Cascade (cascade.py) — narrows a dimension's options to those consistent with the current selection in the others. A forward pass filters a model by every other scope its own filterset supports (Site by Region, Rack by Location, …); a reverse pass handles the "upward" direction by pivoting through a bridge model that has a FK to the target and whose filterset does support the source (Site bridges Region↔Tenant, Tenant bridges Tenant Group↔Tenant, …).
  • Applicability (applicability.py) — introspects the current list view's filterset (get_filters() / base_filters) to decide which configured params it supports; used to dim the control and to choose what to apply.
  • Middleware (middleware.py) — for ObjectListView pages, appends one ?param=<value> per selected value for each supported, not-already-present dimension. redirect mode issues a single 302; silent mode rewrites request.GET. API, GraphQL, and HTMX requests are skipped; existing query params (pagination, sort, per_page) are preserved.

Differences from netbox-tenant-switcher

netbox-tenant-switcher netbox-scope-switcher
Dimensions tenant only (hard-coded) any, configurable and grouped
Cascade — filters narrow each other, both directions
Control one tenant field one control, a section + chips per dimension
Localization — labels/service words follow the UI language
URL handling redirect redirect (default) or silent
Session state list of tenant ids {param: [values]} dict

Migrating

  1. pip uninstall netbox-tenant-switcher and remove it from PLUGINS.
  2. pip install netbox-scope-switcher, add "netbox_scope_switcher" to PLUGINS.
  3. Do nothing else for identical behaviour — the default config is the tenant scope. Add more dimensions to PLUGINS_CONFIG when you want them.

Sessions do not carry over (different key/shape); users simply re-pick their scope once.

Testing

Tests live in netbox_scope_switcher/tests/ and run inside a NetBox checkout:

python netbox/netbox/manage.py test netbox_scope_switcher -v 2

See .github/workflows/ci.yml for the full CI setup.

License

Apache-2.0.

Metadata

Release files for netbox-scope-switcher 1.0.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for netbox-scope-switcher 1.0.2
File Size Uploaded
netbox_scope_switcher-1.0.2.tar.gz 34.2 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for netbox-scope-switcher 1.0.2
File Interpreter ABI Platform
netbox_scope_switcher-1.0.2-py3-none-any.whl Python 3 none any Details

Total release size: 70.6 kB

Release files / netbox_scope_switcher-1.0.2.tar.gz

Download URL netbox_scope_switcher-1.0.2.tar.gz
Size 34.2 kB
Tags Source
SHA-256 checksum
How to use checksums
25b88fab2c5250a45410699ea30bfbf4b83a7a2ec9613319f87cdbc6dc32a92c
BLAKE2b-256 checksum
How to use checksums
8747c11aa2c103d15f9eea81d36524a9e3ccf5cc2063d6d594006339b95599d3
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release files / netbox_scope_switcher-1.0.2-py3-none-any.whl

Download URL netbox_scope_switcher-1.0.2-py3-none-any.whl
Size 36.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
93dfeeacb18531d9188d5093190f47735afeb26e7b27b1caffefb70fee6fee4b
BLAKE2b-256 checksum
How to use checksums
830b4983b5a5cc9d5af93da303908463be6b1f9b8a4492d1223ba0e475ba6a3a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

1.0.2 This release

2 release files

1.0.1

2 release files

1.0.0

2 release files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page