Render VLAN Group VID ranges with ArrayColumn #11698

Closed
opened 2025-12-29 21:48:45 +01:00 by adam · 2 comments
Owner

Originally created by @pheus on GitHub (Oct 6, 2025).

Originally assigned to: @pheus on GitHub.

NetBox version

v4.4.2

Feature type

Change to existing functionality

Proposed functionality

Introduce a helper that returns a list of human‑readable range strings so callers can control spacing and presentation without re‑implementing range logic:

  • ranges_to_text_list(ranges: Iterable[NumericRange]) -> list[str]
    Returns items like ["5-10", "25-30"] using the same inclusive semantics that ranges_to_string() currently applies.

Refactor the existing ranges_to_string() implementation to build on the new helper while preserving its current output (comma‑separated, no spaces), e.g.:

def ranges_to_string(ranges):
    return ",".join(ranges_to_text_list(ranges))

Finally, update the VLAN Group list to render VID ranges using ArrayColumn so the UI shows the standard comma‑and‑space formatting (", "), improving readability and aligning with other list displays.

Use case

Today, utilities.data.ranges_to_string() emits no spaces between items (e.g., "5-10,25-30"). This is correct for some contexts, but it makes it hard to reuse when a space‑separated presentation is desired (for example, table displays or human‑facing messages). Adding ranges_to_text_list() lets call sites choose their own joiner, and lets tables use ArrayColumn (which already renders with ", ") for consistent UI.

Database changes

None.

External dependencies

None.

Proposed change (implementation notes)

  1. Add helper in utilities/data.py
from typing import Iterable
from django.db.backends.postgresql.psycopg_any import NumericRange

def ranges_to_text_list(ranges: Iterable[NumericRange]) -> list[str]:
    """
    Convert NumericRange values to human-friendly inclusive strings ["lo-hi", ...].
    Mirrors ranges_to_string() semantics.
    """
    if not ranges:
        return []

    items: list[str] = []
    for r in ranges:
        # Compute inclusive bounds regardless of how the DB range is stored.
        lower = r.lower if getattr(r, "lower_inc", True) else r.lower + 1
        upper = r.upper if getattr(r, "upper_inc", False) else r.upper - 1

        # If you prefer singletons like "5" instead of "5-5", uncomment:
        # if lower == upper:
        #     items.append(f"{lower}")
        # else:
        items.append(f"{lower}-{upper}")
    return items
  1. Refactor ranges_to_string() (backward compatible)
def ranges_to_string(ranges):
    if not ranges:
        return ""
    return ",".join(ranges_to_text_list(ranges))
  1. VLAN Group model
    Keep the existing string property (e.g., vid_ranges_list) to avoid breaking any consumers. Add a new list‑returning property for table use:
# ipam/models/vlans.py
from utilities.data import ranges_to_text_list

@property
def vid_ranges_items(self) -> list[str]:
    return ranges_to_text_list(self.vid_ranges)
  1. VLAN Group table
    Switch the column to ArrayColumn but keep the column name vid_ranges_list to preserve saved table configs; point it at the new list property:
# ipam/tables/vlans.py
from netbox.tables import columns

# Old:
# vid_ranges_list = tables.Column(verbose_name=_('VID Ranges'), orderable=False)

# New:
vid_ranges_list = columns.ArrayColumn(
    accessor='vid_ranges_items',
    verbose_name=_('VID Ranges'),
    orderable=False,
)

Backwards compatibility

  • ranges_to_string() output and signature remain unchanged (still returns a str with no spaces).
  • VLANGroup.vid_ranges_list remains available (still a str) to avoid breaking any code or saved table configurations that reference its column name. The table change keeps the same column name while sourcing from a new vid_ranges_items list property.

Additional context / references

  • Background plugin work that motivated this (spacing control): ranges_to_text_list implementation in netbox‑acls:
    da406f918c

Before / After (table rendering example)

  • Before: VID Ranges1-99,200-299
  • After: VID Ranges1-99, 200-299 (space after comma via ArrayColumn)
Originally created by @pheus on GitHub (Oct 6, 2025). Originally assigned to: @pheus on GitHub. ### NetBox version v4.4.2 ### Feature type Change to existing functionality ### Proposed functionality Introduce a helper that returns a **list of human‑readable range strings** so callers can control spacing and presentation without re‑implementing range logic: - `ranges_to_text_list(ranges: Iterable[NumericRange]) -> list[str]` Returns items like `["5-10", "25-30"]` using the same inclusive semantics that `ranges_to_string()` currently applies. Refactor the existing `ranges_to_string()` implementation to build on the new helper while **preserving its current output** (comma‑separated, **no spaces**), e.g.: ```py def ranges_to_string(ranges): return ",".join(ranges_to_text_list(ranges)) ``` Finally, update the VLAN Group list to **render VID ranges using `ArrayColumn`** so the UI shows the standard comma‑and‑space formatting (`", "`), improving readability and aligning with other list displays. ### Use case Today, `utilities.data.ranges_to_string()` emits no spaces between items (e.g., `"5-10,25-30"`). This is correct for some contexts, but it makes it hard to reuse when a space‑separated presentation is desired (for example, table displays or human‑facing messages). Adding `ranges_to_text_list()` lets call sites choose their own joiner, and lets tables use `ArrayColumn` (which already renders with `", "`) for consistent UI. ### Database changes None. ### External dependencies None. ## Proposed change (implementation notes) 1) **Add helper in `utilities/data.py`** ```py from typing import Iterable from django.db.backends.postgresql.psycopg_any import NumericRange def ranges_to_text_list(ranges: Iterable[NumericRange]) -> list[str]: """ Convert NumericRange values to human-friendly inclusive strings ["lo-hi", ...]. Mirrors ranges_to_string() semantics. """ if not ranges: return [] items: list[str] = [] for r in ranges: # Compute inclusive bounds regardless of how the DB range is stored. lower = r.lower if getattr(r, "lower_inc", True) else r.lower + 1 upper = r.upper if getattr(r, "upper_inc", False) else r.upper - 1 # If you prefer singletons like "5" instead of "5-5", uncomment: # if lower == upper: # items.append(f"{lower}") # else: items.append(f"{lower}-{upper}") return items ``` 2) **Refactor `ranges_to_string()`** (backward compatible) ```py def ranges_to_string(ranges): if not ranges: return "" return ",".join(ranges_to_text_list(ranges)) ``` 3) **VLAN Group model** Keep the existing string property (e.g., `vid_ranges_list`) **to avoid breaking any consumers**. Add a new list‑returning property for table use: ```py # ipam/models/vlans.py from utilities.data import ranges_to_text_list @property def vid_ranges_items(self) -> list[str]: return ranges_to_text_list(self.vid_ranges) ``` 4) **VLAN Group table** Switch the column to `ArrayColumn` but **keep the column name** `vid_ranges_list` to preserve saved table configs; point it at the new list property: ```py # ipam/tables/vlans.py from netbox.tables import columns # Old: # vid_ranges_list = tables.Column(verbose_name=_('VID Ranges'), orderable=False) # New: vid_ranges_list = columns.ArrayColumn( accessor='vid_ranges_items', verbose_name=_('VID Ranges'), orderable=False, ) ``` --- ## Backwards compatibility - `ranges_to_string()` output and signature remain unchanged (still returns a `str` with **no spaces**). - `VLANGroup.vid_ranges_list` remains available (still a `str`) to avoid breaking any code or saved table configurations that reference its column name. The table change keeps the same column name while sourcing from a new `vid_ranges_items` list property. --- ## Additional context / references - Background plugin work that motivated this (spacing control): `ranges_to_text_list` implementation in **netbox‑acls**: https://github.com/pheus/netbox-acls/commit/da406f918ce904b1c8d2e71e2165f4b55896a19d --- ### Before / After (table rendering example) - **Before:** `VID Ranges` → `1-99,200-299` - **After:** `VID Ranges` → `1-99, 200-299` (space after comma via `ArrayColumn`)
adam added the status: acceptedtype: featurecomplexity: low labels 2025-12-29 21:48:45 +01:00
adam closed this issue 2025-12-29 21:48:45 +01:00
Author
Owner

@pheus commented on GitHub (Oct 8, 2025):

I’m happy to open a PR if this enhancement is accepted.

@pheus commented on GitHub (Oct 8, 2025): I’m happy to open a PR if this enhancement is accepted.
Author
Owner

@jeremystretch commented on GitHub (Oct 9, 2025):

@pheus I've assigned this to you, thanks!

@jeremystretch commented on GitHub (Oct 9, 2025): @pheus I've assigned this to you, thanks!
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: starred/netbox#11698