Skip to content

fix(templatetags): render hostgroup/tag previews with representative device#130

Open
berlikm wants to merge 2 commits into
OpensourceICTSolutions:developmentfrom
berlikm:fix/preview-device-context
Open

fix(templatetags): render hostgroup/tag previews with representative device#130
berlikm wants to merge 2 commits into
OpensourceICTSolutions:developmentfrom
berlikm:fix/preview-device-context

Conversation

@berlikm

@berlikm berlikm commented Jul 17, 2026

Copy link
Copy Markdown

Problem

Templates like Roles/{{ object.role.name }} (assigned to DeviceRole) and Sites/{{ object.site.group.name }}/{{ object.site.name }} (assigned to SiteGroup) fail in the NetBox UI 'Rendered Value' preview card and ObjectViewTable. The render context uses the assignment target (DeviceRole/SiteGroup) as object, which lacks .role/.site:

Undefined variable in template 'Roles/{{ object.role.name }}': 'dcim.models.devices.DeviceRole object' has no attribute 'role'

The sync engine was already fixed in #110 to pass object=Device explicitly, but the UI preview path (render_zabbix_hostgroup_assignment / render_zabbix_tag_assignment) was never addressed and leaked the raw Jinja2 UndefinedError string into the page.

Fix

Substitute a representative Device/VM that inherits the assignment so device-context templates resolve to the same value the sync produces. When no representative is found (empty role/site), the tag returns '' instead of the error string.

Files

  • nbxsync/utils/preview.py (new): get_representative_device(assignment) resolver with dispatch table covering DeviceRole, Platform, Manufacturer, DeviceType, Site, SiteGroup (recursive via get_descendants), Region (recursive), Cluster, ClusterType. Cached via @lru_cache(maxsize=64) for the table case.
  • nbxsync/templatetags/zabbix_hostgroups.py: takes_context=True, substitute representative when no explicit object= passed. if 'object' not in extra guard preserves the sync-engine path (which passes object=Device explicitly).
  • nbxsync/templatetags/zabbix_tags.py: mirror for tags.
  • nbxsync/tests/templatetags/test_preview_render.py (+ __init__.py): covers DeviceRole rep, recursive SiteGroup, empty role (graceful ''), static passthrough, explicit object= override.

Behaviour

Template Before After
Roles/{{ object.role.name }} on DeviceRole 'Cohesity' Error string Roles/Cohesity
Sites/{{ object.site.group.name }}/{{ object.site.name }} on SiteGroup 'CH' Error string Sites/CH-NKN/CH-NKN-G08 (first CH device)
Managed/nbxSync (static) Managed/nbxSync Managed/nbxSync (unchanged)
Empty role with no devices Error string '' (graceful)

Compatibility

Supplements #102 (taofineberg's related-context PR) — #102 adds alternative context keys (device, site, role); this PR overrides object so existing templates keep working without rewrite.

…device

Templates like 'Roles/{{ object.role.name }}' assigned to a DeviceRole,
or 'Sites/{{ object.site.group.name }}/{{ object.site.name }}' assigned
to a SiteGroup, fail in the NetBox UI 'Rendered Value' preview card
and ObjectViewTable because the render context uses the assignment
target (DeviceRole/SiteGroup) as 'object', which lacks the traversed
attributes (.role, .site).

The sync engine was already fixed in PR OpensourceICTSolutions#110 to pass object=Device
explicitly, but the UI preview path (render_zabbix_hostgroup_assignment
/ render_zabbix_tag_assignment) was never addressed and leaked the raw
Jinja2 UndefinedError string into the page.

Fix: substitute a representative Device/VM that inherits the assignment
so device-context templates render the same value the sync produces.
Cached via lru_cache(maxsize=64) for the table case. Returns '' on
failure instead of the error string.

- nbxsync/utils/preview.py (new): representative-device resolver with
  dispatch table covering DeviceRole, Platform, Manufacturer, DeviceType,
  Site, SiteGroup (recursive), Region (recursive), Cluster, ClusterType.
- nbxsync/templatetags/zabbix_hostgroups.py: takes_context=True,
  substitute representative when no explicit object= passed.
- nbxsync/templatetags/zabbix_tags.py: mirror for tags.
- nbxsync/tests/templatetags/test_preview_render.py: covers DeviceRole
  rep, recursive SiteGroup, empty role (graceful ''), static passthrough,
  explicit object= override (sync-engine path preserved).
berlikm added a commit to berlikm/nbxsync that referenced this pull request Jul 17, 2026
…ag preview representative device

Merges fix/preview-device-context into integration-test for VM testing.
Resolves UndefinedError leak in NetBox UI 'Rendered Value' card for
inherited hostgroup/tag assignments.
create_test_device(name, site, **attrs) already passes role=devicerole
internally, so passing role= via **attrs collides. Use a _make_device
wrapper that creates then sets the role.

Also fix assertIs(rep, device) → assertEqual(rep.pk, device.pk):
the resolver returns a fresh DB fetch, not the same Python instance.

All 10 tests now pass.
@light-foot

Copy link
Copy Markdown

This is a much needed PR. It makes things more NetBox native.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants